diff options
870 files changed, 50314 insertions, 6742 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 4b953b212829a..86ca2b3ef74b5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,6 +9,7 @@ cmake_minimum_required(VERSION 3.4.3)  if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR OR COMPILER_RT_STANDALONE_BUILD)    project(CompilerRT C CXX ASM)    set(COMPILER_RT_STANDALONE_BUILD TRUE) +  set_property(GLOBAL PROPERTY USE_FOLDERS ON)  endif()  # Add path for custom compiler-rt modules. @@ -63,6 +64,11 @@ set(COMPILER_RT_BAREMETAL_BUILD OFF CACHE BOOLEAN  if (COMPILER_RT_STANDALONE_BUILD)    load_llvm_config() +  if (TARGET intrinsics_gen) +    # Loading the llvm config causes this target to be imported so place it +    # under the appropriate folder in an IDE. +    set_target_properties(intrinsics_gen PROPERTIES FOLDER "Compiler-RT Misc") +  endif()    # Find Python interpreter.    set(Python_ADDITIONAL_VERSIONS 2.7 2.6 2.5) @@ -96,6 +102,8 @@ pythonize_bool(ANDROID)  set(COMPILER_RT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})  set(COMPILER_RT_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}) +pythonize_bool(LLVM_ENABLE_PER_TARGET_RUNTIME_DIR) +  # We support running instrumented tests when we're not cross compiling  # and target a UNIX-like system or Windows.  # We can run tests on Android even when we are cross-compiling. @@ -112,9 +120,6 @@ option(COMPILER_RT_EXTERNALIZE_DEBUGINFO  # COMPILER_RT_DEBUG_PYBOOL is used by lit.common.configured.in.  pythonize_bool(COMPILER_RT_DEBUG) -include(HandleCompilerRT) -include(config-ix) -  if(APPLE AND SANITIZER_MIN_OSX_VERSION AND SANITIZER_MIN_OSX_VERSION VERSION_LESS "10.9")    # Mac OS X prior to 10.9 had problems with exporting symbols from    # libc++/libc++abi. @@ -133,41 +138,34 @@ pythonize_bool(SANITIZER_CAN_USE_CXXABI)  set(SANITIZER_CXX_ABI "default" CACHE STRING      "Specify C++ ABI library to use.") -set(CXXABIS none default libcxxabi libstdc++ libc++) +set(CXXABIS none default libstdc++ libc++)  set_property(CACHE SANITIZER_CXX_ABI PROPERTY STRINGS ;${CXXABIS})  if (SANITIZER_CXX_ABI STREQUAL "default") -  if (HAVE_LIBCXXABI AND COMPILER_RT_DEFAULT_TARGET_ONLY) -    set(SANITIZER_CXX_ABI_LIBNAME "libcxxabi") -    set(SANITIZER_CXX_ABI_INTREE 1) -  elseif (APPLE) -    set(SANITIZER_CXX_ABI_LIBNAME "libcxxabi") +  if (APPLE) +    set(SANITIZER_CXX_ABI_LIBNAME "libc++")      set(SANITIZER_CXX_ABI_SYSTEM 1) +  elseif (FUCHSIA) +    set(SANITIZER_CXX_ABI_LIBNAME "libc++") +    set(SANITIZER_CXX_ABI_INTREE 1)    else()      set(SANITIZER_CXX_ABI_LIBNAME "libstdc++") +    set(SANITIZER_CXX_ABI_SYSTEM 1)    endif()  else()    set(SANITIZER_CXX_ABI_LIBNAME "${SANITIZER_CXX_ABI}") +  set(SANITIZER_CXX_ABI_SYSTEM 1)  endif() -if (SANITIZER_CXX_ABI_LIBNAME STREQUAL "libcxxabi") -  if (SANITIZER_CXX_ABI_INTREE) -    if (TARGET unwind_shared OR HAVE_LIBUNWIND) -      list(APPEND SANITIZER_CXX_ABI_LIBRARY unwind_shared) -    endif() -    if (TARGET cxxabi_shared OR HAVE_LIBCXXABI) -      list(APPEND SANITIZER_CXX_ABI_LIBRARY cxxabi_shared) -    endif() -  else() -    list(APPEND SANITIZER_CXX_ABI_LIBRARY "c++abi") -  endif() -elseif (SANITIZER_CXX_ABI_LIBNAME STREQUAL "libc++") -  list(APPEND SANITIZER_CXX_ABI_LIBRARY "c++") -elseif (SANITIZER_CXX_ABI_LIBNAME STREQUAL "libstdc++") -  append_list_if(COMPILER_RT_HAS_LIBSTDCXX stdc++ SANITIZER_CXX_ABI_LIBRARY) +set(DEFAULT_COMPILER_RT_USE_BUILTINS_LIBRARY OFF) +if (FUCHSIA) +  set(DEFAULT_COMPILER_RT_USE_BUILTINS_LIBRARY ON)  endif() -option(SANITIZER_USE_COMPILER_RT "Use compiler-rt builtins instead of libgcc" OFF) +option(COMPILER_RT_USE_BUILTINS_LIBRARY +  "Use compiler-rt builtins instead of libgcc" ${DEFAULT_COMPILER_RT_USE_BUILTINS_LIBRARY}) + +include(config-ix)  #================================  # Setup Compiler Flags @@ -274,12 +272,14 @@ else()    set(SANITIZER_LIMIT_FRAME_SIZE FALSE)  endif() +if(FUCHSIA OR UNIX) +  set(SANITIZER_USE_SYMBOLS TRUE) +else() +  set(SANITIZER_USE_SYMBOLS FALSE) +endif() +  # Build sanitizer runtimes with debug info. -if(COMPILER_RT_HAS_GLINE_TABLES_ONLY_FLAG AND NOT COMPILER_RT_DEBUG) -  list(APPEND SANITIZER_COMMON_CFLAGS -gline-tables-only) -elseif(COMPILER_RT_HAS_G_FLAG) -  list(APPEND SANITIZER_COMMON_CFLAGS -g) -elseif(MSVC) +if(MSVC)    # Use /Z7 instead of /Zi for the asan runtime. This avoids the LNK4099    # warning from the MS linker complaining that it can't find the 'vc140.pdb'    # file used by our object library compilations. @@ -287,6 +287,10 @@ elseif(MSVC)    llvm_replace_compiler_option(CMAKE_CXX_FLAGS "/Z[i7I]" "/Z7")    llvm_replace_compiler_option(CMAKE_CXX_FLAGS_DEBUG "/Z[i7I]" "/Z7")    llvm_replace_compiler_option(CMAKE_CXX_FLAGS_RELWITHDEBINFO "/Z[i7I]" "/Z7") +elseif(COMPILER_RT_HAS_GLINE_TABLES_ONLY_FLAG AND NOT COMPILER_RT_DEBUG) +  list(APPEND SANITIZER_COMMON_CFLAGS -gline-tables-only) +elseif(COMPILER_RT_HAS_G_FLAG) +  list(APPEND SANITIZER_COMMON_CFLAGS -g)  endif()  if(LLVM_ENABLE_MODULES) @@ -309,9 +313,7 @@ append_list_if(COMPILER_RT_HAS_WD4800_FLAG /wd4800 SANITIZER_COMMON_CFLAGS)  # Set common link flags.  append_list_if(COMPILER_RT_HAS_NODEFAULTLIBS_FLAG -nodefaultlibs SANITIZER_COMMON_LINK_FLAGS) -if (SANITIZER_USE_COMPILER_RT) -  list(APPEND SANITIZER_COMMON_LINK_FLAGS -rtlib=compiler-rt) -  find_compiler_rt_library(builtins COMPILER_RT_BUILTINS_LIBRARY) +if (COMPILER_RT_USE_BUILTINS_LIBRARY)    list(APPEND SANITIZER_COMMON_LINK_LIBS ${COMPILER_RT_BUILTINS_LIBRARY})  else()    if (ANDROID) @@ -323,11 +325,40 @@ endif()  append_list_if(COMPILER_RT_HAS_LIBC c SANITIZER_COMMON_LINK_LIBS) +if(ANDROID) +# Put the Sanitizer shared libraries in the global group. For more details, see +# android-changes-for-ndk-developers.md#changes-to-library-search-order +  if (COMPILER_RT_HAS_Z_GLOBAL) +    list(APPEND SANITIZER_COMMON_LINK_FLAGS -Wl,-z,global) +  endif() +endif() +  if("${CMAKE_SYSTEM_NAME}" STREQUAL "Fuchsia")    list(APPEND SANITIZER_COMMON_LINK_FLAGS -Wl,-z,defs,-z,now,-z,relro)    list(APPEND SANITIZER_COMMON_LINK_LIBS zircon)  endif() +if (SANITIZER_CXX_ABI_LIBNAME STREQUAL "libc++") +  if (SANITIZER_CXX_ABI_INTREE) +    if (NOT LIBCXXABI_ENABLE_STATIC_UNWINDER AND (TARGET unwind_shared OR HAVE_LIBUNWIND)) +      list(APPEND SANITIZER_CXX_ABI_LIBRARY unwind_shared) +    elseif (LIBCXXABI_ENABLE_STATIC_UNWINDER AND (TARGET unwind_static OR HAVE_LIBUNWIND)) +      list(APPEND SANITIZER_CXX_ABI_LIBRARY unwind_static) +    endif() +    if (NOT LIBCXX_ENABLE_STATIC_ABI_LIBRARY AND (TARGET cxxabi_shared OR HAVE_LIBCXXABI)) +      list(APPEND SANITIZER_CXX_ABI_LIBRARY cxxabi_shared) +    elseif (LIBCXX_ENABLE_STATIC_ABI_LIBRARY AND (TARGET cxxabi_static OR HAVE_LIBCXXABI)) +      list(APPEND SANITIZER_CXX_ABI_LIBRARY cxxabi_static) +    endif() +  else() +    append_list_if(COMPILER_RT_HAS_LIBCXX c++ SANITIZER_CXX_ABI_LIBRARY) +  endif() +elseif (SANITIZER_CXX_ABI_LIBNAME STREQUAL "libcxxabi") +  list(APPEND SANITIZER_CXX_ABI_LIBRARY "c++abi") +elseif (SANITIZER_CXX_ABI_LIBNAME STREQUAL "libstdc++") +  append_list_if(COMPILER_RT_HAS_LIBSTDCXX stdc++ SANITIZER_CXX_ABI_LIBRARY) +endif() +  # Warnings to turn off for all libraries, not just sanitizers.  append_string_if(COMPILER_RT_HAS_WUNUSED_PARAMETER_FLAG -Wno-unused-parameter CMAKE_C_FLAGS CMAKE_CXX_FLAGS) @@ -339,7 +370,7 @@ if (CMAKE_LINKER MATCHES "link.exe$")    # it, but CMake doesn't seem to have a way to set linker flags for    # individual static libraries, so we enable the suppression flag for    # the whole compiler-rt project. -  append("/IGNORE:4221" CMAKE_STATIC_LINKER_FLAGS) +  set(CMAKE_STATIC_LINKER_FLAGS "${CMAKE_STATIC_LINKER_FLAGS} /IGNORE:4221")  endif()  add_subdirectory(include) diff --git a/LICENSE.TXT b/LICENSE.TXT index a17dc12b272fb..0134694e4e5f1 100644 --- a/LICENSE.TXT +++ b/LICENSE.TXT @@ -14,7 +14,7 @@ Full text of the relevant licenses is included below.  University of Illinois/NCSA  Open Source License -Copyright (c) 2009-2016 by the contributors listed in CREDITS.TXT +Copyright (c) 2009-2018 by the contributors listed in CREDITS.TXT  All rights reserved. diff --git a/cmake/Modules/AddCompilerRT.cmake b/cmake/Modules/AddCompilerRT.cmake index 139b6140011c4..cd4c704fc824f 100644 --- a/cmake/Modules/AddCompilerRT.cmake +++ b/cmake/Modules/AddCompilerRT.cmake @@ -31,9 +31,12 @@ endfunction()  #                                  ARCHS <architectures>  #                                  SOURCES <source files>  #                                  CFLAGS <compile flags> -#                                  DEFS <compile definitions>) +#                                  DEFS <compile definitions> +#                                  DEPS <dependencies> +#                                  ADDITIONAL_HEADERS <header files>)  function(add_compiler_rt_object_libraries name) -  cmake_parse_arguments(LIB "" "" "OS;ARCHS;SOURCES;CFLAGS;DEFS" ${ARGN}) +  cmake_parse_arguments(LIB "" "" "OS;ARCHS;SOURCES;CFLAGS;DEFS;DEPS;ADDITIONAL_HEADERS" +    ${ARGN})    set(libnames)    if(APPLE)      foreach(os ${LIB_OS}) @@ -54,8 +57,18 @@ function(add_compiler_rt_object_libraries name)      endforeach()    endif() +  # Add headers to LIB_SOURCES for IDEs +  compiler_rt_process_sources(LIB_SOURCES +    ${LIB_SOURCES} +    ADDITIONAL_HEADERS +      ${LIB_ADDITIONAL_HEADERS} +  ) +    foreach(libname ${libnames})      add_library(${libname} OBJECT ${LIB_SOURCES}) +    if(LIB_DEPS) +      add_dependencies(${libname} ${LIB_DEPS}) +    endif()      # Strip out -msse3 if this isn't macOS.      set(target_flags ${LIB_CFLAGS}) @@ -105,10 +118,14 @@ function(add_asm_sources output)  endfunction()  macro(set_output_name output name arch) -  if(ANDROID AND ${arch} STREQUAL "i386") -    set(${output} "${name}-i686${COMPILER_RT_OS_SUFFIX}") +  if(LLVM_ENABLE_PER_TARGET_RUNTIME_DIR) +    set(${output} ${name})    else() -    set(${output} "${name}-${arch}${COMPILER_RT_OS_SUFFIX}") +    if(ANDROID AND ${arch} STREQUAL "i386") +      set(${output} "${name}-i686${COMPILER_RT_OS_SUFFIX}") +    else() +      set(${output} "${name}-${arch}${COMPILER_RT_OS_SUFFIX}") +    endif()    endif()  endmacro() @@ -124,7 +141,8 @@ endmacro()  #                         DEFS <compile definitions>  #                         LINK_LIBS <linked libraries> (only for shared library)  #                         OBJECT_LIBS <object libraries to use as sources> -#                         PARENT_TARGET <convenience parent target>) +#                         PARENT_TARGET <convenience parent target> +#                         ADDITIONAL_HEADERS <header files>)  function(add_compiler_rt_runtime name type)    if(NOT type MATCHES "^(STATIC|SHARED)$")      message(FATAL_ERROR "type argument must be STATIC or SHARED") @@ -133,7 +151,7 @@ function(add_compiler_rt_runtime name type)    cmake_parse_arguments(LIB      ""      "PARENT_TARGET" -    "OS;ARCHS;SOURCES;CFLAGS;LINK_FLAGS;DEFS;LINK_LIBS;OBJECT_LIBS" +    "OS;ARCHS;SOURCES;CFLAGS;LINK_FLAGS;DEFS;LINK_LIBS;OBJECT_LIBS;ADDITIONAL_HEADERS"      ${ARGN})    set(libnames)    # Until we support this some other way, build compiler-rt runtime without LTO @@ -144,6 +162,18 @@ function(add_compiler_rt_runtime name type)      set(NO_LTO_FLAGS "")    endif() +  list(LENGTH LIB_SOURCES LIB_SOURCES_LENGTH) +  if (${LIB_SOURCES_LENGTH} GREATER 0) +    # Add headers to LIB_SOURCES for IDEs. It doesn't make sense to +    # do this for a runtime library that only consists of OBJECT +    # libraries, so only add the headers when source files are present. +    compiler_rt_process_sources(LIB_SOURCES +      ${LIB_SOURCES} +      ADDITIONAL_HEADERS +        ${LIB_ADDITIONAL_HEADERS} +    ) +  endif() +    if(APPLE)      foreach(os ${LIB_OS})        # Strip out -msse3 if this isn't macOS. @@ -164,6 +194,8 @@ function(add_compiler_rt_runtime name type)          set(output_name_${libname} ${libname}${COMPILER_RT_OS_SUFFIX})          set(sources_${libname} ${LIB_SOURCES})          format_object_libs(sources_${libname} ${os} ${LIB_OBJECT_LIBS}) +        get_compiler_rt_output_dir(${COMPILER_RT_DEFAULT_TARGET_ARCH} output_dir_${libname}) +        get_compiler_rt_install_dir(${COMPILER_RT_DEFAULT_TARGET_ARCH} install_dir_${libname})        endif()      endforeach()    else() @@ -189,6 +221,8 @@ function(add_compiler_rt_runtime name type)        format_object_libs(sources_${libname} ${arch} ${LIB_OBJECT_LIBS})        set(libnames ${libnames} ${libname})        set(extra_cflags_${libname} ${TARGET_${arch}_CFLAGS} ${NO_LTO_FLAGS} ${LIB_CFLAGS}) +      get_compiler_rt_output_dir(${arch} output_dir_${libname}) +      get_compiler_rt_install_dir(${arch} install_dir_${libname})      endforeach()    endif() @@ -200,6 +234,8 @@ function(add_compiler_rt_runtime name type)      # If the parent targets aren't created we should create them      if(NOT TARGET ${LIB_PARENT_TARGET})        add_custom_target(${LIB_PARENT_TARGET}) +      set_target_properties(${LIB_PARENT_TARGET} PROPERTIES +                            FOLDER "Compiler-RT Misc")      endif()      if(NOT TARGET install-${LIB_PARENT_TARGET})        # The parent install target specifies the parent component to scrape up @@ -239,7 +275,7 @@ function(add_compiler_rt_runtime name type)      set_target_link_flags(${libname} ${extra_link_flags_${libname}})      set_property(TARGET ${libname} APPEND PROPERTY                  COMPILE_DEFINITIONS ${LIB_DEFS}) -    set_target_output_directories(${libname} ${COMPILER_RT_LIBRARY_OUTPUT_DIR}) +    set_target_output_directories(${libname} ${output_dir_${libname}})      set_target_properties(${libname} PROPERTIES          OUTPUT_NAME ${output_name_${libname}})      set_target_properties(${libname} PROPERTIES FOLDER "Compiler-RT Runtime") @@ -247,6 +283,9 @@ function(add_compiler_rt_runtime name type)        target_link_libraries(${libname} ${LIB_LINK_LIBS})      endif()      if(${type} STREQUAL "SHARED") +      if(COMMAND llvm_setup_rpath) +        llvm_setup_rpath(${libname}) +      endif()        if(WIN32 AND NOT CYGWIN AND NOT MINGW)          set_target_properties(${libname} PROPERTIES IMPORT_PREFIX "")          set_target_properties(${libname} PROPERTIES IMPORT_SUFFIX ".lib") @@ -261,11 +300,11 @@ function(add_compiler_rt_runtime name type)        endif()      endif()      install(TARGETS ${libname} -      ARCHIVE DESTINATION ${COMPILER_RT_LIBRARY_INSTALL_DIR} +      ARCHIVE DESTINATION ${install_dir_${libname}}                ${COMPONENT_OPTION} -      LIBRARY DESTINATION ${COMPILER_RT_LIBRARY_INSTALL_DIR} +      LIBRARY DESTINATION ${install_dir_${libname}}                ${COMPONENT_OPTION} -      RUNTIME DESTINATION ${COMPILER_RT_LIBRARY_INSTALL_DIR} +      RUNTIME DESTINATION ${install_dir_${libname}}                ${COMPONENT_OPTION})      # We only want to generate per-library install targets if you aren't using @@ -431,7 +470,7 @@ endfunction()  macro(add_compiler_rt_resource_file target_name file_name component)    set(src_file "${CMAKE_CURRENT_SOURCE_DIR}/${file_name}") -  set(dst_file "${COMPILER_RT_OUTPUT_DIR}/${file_name}") +  set(dst_file "${COMPILER_RT_OUTPUT_DIR}/share/${file_name}")    add_custom_command(OUTPUT ${dst_file}      DEPENDS ${src_file}      COMMAND ${CMAKE_COMMAND} -E copy_if_different ${src_file} ${dst_file} @@ -439,7 +478,7 @@ macro(add_compiler_rt_resource_file target_name file_name component)    add_custom_target(${target_name} DEPENDS ${dst_file})    # Install in Clang resource directory.    install(FILES ${file_name} -    DESTINATION ${COMPILER_RT_INSTALL_PATH} +    DESTINATION ${COMPILER_RT_INSTALL_PATH}/share      COMPONENT ${component})    add_dependencies(${component} ${target_name}) @@ -463,53 +502,123 @@ endmacro(add_compiler_rt_script src name)  # Can be used to build sanitized versions of libc++ for running unit tests.  # add_custom_libcxx(<name> <prefix>  #                   DEPS <list of build deps> -#                   CFLAGS <list of compile flags>) +#                   CFLAGS <list of compile flags> +#                   USE_TOOLCHAIN)  macro(add_custom_libcxx name prefix)    if(NOT COMPILER_RT_LIBCXX_PATH)      message(FATAL_ERROR "libcxx not found!")    endif() -  cmake_parse_arguments(LIBCXX "" "" "DEPS;CFLAGS;CMAKE_ARGS" ${ARGN}) -  foreach(flag ${LIBCXX_CFLAGS}) -    set(flagstr "${flagstr} ${flag}") -  endforeach() -  set(LIBCXX_CFLAGS ${flagstr}) +  cmake_parse_arguments(LIBCXX "USE_TOOLCHAIN" "" "DEPS;CFLAGS;CMAKE_ARGS" ${ARGN}) -  if(NOT COMPILER_RT_STANDALONE_BUILD) -    list(APPEND LIBCXX_DEPS clang) +  if(LIBCXX_USE_TOOLCHAIN) +    set(compiler_args -DCMAKE_C_COMPILER=${COMPILER_RT_TEST_COMPILER} +                      -DCMAKE_CXX_COMPILER=${COMPILER_RT_TEST_CXX_COMPILER}) +    if(NOT COMPILER_RT_STANDALONE_BUILD) +      set(toolchain_deps $<TARGET_FILE:clang>) +      set(force_deps DEPENDS $<TARGET_FILE:clang>) +    endif() +  else() +    set(compiler_args -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} +                      -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER})    endif() +  set(STAMP_DIR ${prefix}-stamps/) +  set(BINARY_DIR ${prefix}-bins/) + +  add_custom_target(${name}-clear +    COMMAND ${CMAKE_COMMAND} -E remove_directory ${BINARY_DIR} +    COMMAND ${CMAKE_COMMAND} -E remove_directory ${STAMP_DIR} +    COMMENT "Clobbering ${name} build and stamp directories" +    USES_TERMINAL +    ) +  set_target_properties(${name}-clear PROPERTIES FOLDER "Compiler-RT Misc") + +  add_custom_command( +    OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${name}-clobber-stamp +    DEPENDS ${LIBCXX_DEPS} ${toolchain_deps} +    COMMAND ${CMAKE_COMMAND} -E touch ${BINARY_DIR}/CMakeCache.txt +    COMMAND ${CMAKE_COMMAND} -E touch ${STAMP_DIR}/${name}-mkdir +    COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_CURRENT_BINARY_DIR}/${name}-clobber-stamp +    COMMENT "Clobbering bootstrap build and stamp directories" +    ) + +  add_custom_target(${name}-clobber +    DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${name}-clobber-stamp) +  set_target_properties(${name}-clobber PROPERTIES FOLDER "Compiler-RT Misc") + +  set(PASSTHROUGH_VARIABLES +    CMAKE_C_COMPILER_TARGET +    CMAKE_CXX_COMPILER_TARGET +    CMAKE_INSTALL_PREFIX +    CMAKE_MAKE_PROGRAM +    CMAKE_LINKER +    CMAKE_AR +    CMAKE_RANLIB +    CMAKE_NM +    CMAKE_OBJCOPY +    CMAKE_OBJDUMP +    CMAKE_STRIP +    CMAKE_SYSROOT +    CMAKE_SYSTEM_NAME) +  foreach(variable ${PASSTHROUGH_VARIABLES}) +    if(${variable}) +      list(APPEND CMAKE_PASSTHROUGH_VARIABLES -D${variable}=${${variable}}) +    endif() +  endforeach() + +  string(REPLACE ";" " " FLAGS_STRING "${LIBCXX_CFLAGS}") +  set(LIBCXX_C_FLAGS "${FLAGS_STRING}") +  set(LIBCXX_CXX_FLAGS "${FLAGS_STRING}") +    ExternalProject_Add(${name} +    DEPENDS ${name}-clobber ${LIBCXX_DEPS}      PREFIX ${prefix}      SOURCE_DIR ${COMPILER_RT_LIBCXX_PATH} -    CMAKE_ARGS -DCMAKE_MAKE_PROGRAM:STRING=${CMAKE_MAKE_PROGRAM} -               -DCMAKE_C_COMPILER=${COMPILER_RT_TEST_COMPILER} -               -DCMAKE_CXX_COMPILER=${COMPILER_RT_TEST_CXX_COMPILER} -               -DCMAKE_C_FLAGS=${LIBCXX_CFLAGS} -               -DCMAKE_CXX_FLAGS=${LIBCXX_CFLAGS} +    STAMP_DIR ${STAMP_DIR} +    BINARY_DIR ${BINARY_DIR} +    CMAKE_ARGS ${CMAKE_PASSTHROUGH_VARIABLES} +               ${compiler_args} +               -DCMAKE_C_FLAGS=${LIBCXX_C_FLAGS} +               -DCMAKE_CXX_FLAGS=${LIBCXX_CXX_FLAGS}                 -DCMAKE_BUILD_TYPE=Release -               -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>                 -DLLVM_PATH=${LLVM_MAIN_SRC_DIR} -               -DLIBCXX_STANDALONE_BUILD=On +               -DLLVM_BINARY_DIR=${prefix} +               -DLLVM_LIBRARY_OUTPUT_INTDIR=${prefix}/lib +               -DLIBCXX_STANDALONE_BUILD=ON                 ${LIBCXX_CMAKE_ARGS} -    LOG_BUILD 1 -    LOG_CONFIGURE 1 -    LOG_INSTALL 1 +    INSTALL_COMMAND "" +    STEP_TARGETS configure build +    BUILD_ALWAYS 1 +    USES_TERMINAL_CONFIGURE 1 +    USES_TERMINAL_BUILD 1 +    USES_TERMINAL_INSTALL 1 +    EXCLUDE_FROM_ALL TRUE      ) -  set_target_properties(${name} PROPERTIES EXCLUDE_FROM_ALL TRUE) -  ExternalProject_Add_Step(${name} force-reconfigure -    DEPENDERS configure -    ALWAYS 1 -    ) +  if (CMAKE_GENERATOR MATCHES "Make") +    set(run_clean "$(MAKE)" "-C" "${BINARY_DIR}" "clean") +  else() +    set(run_clean ${CMAKE_COMMAND} --build ${BINARY_DIR} --target clean +                                   --config "$<CONFIGURATION>") +  endif() -  ExternalProject_Add_Step(${name} clobber -    COMMAND ${CMAKE_COMMAND} -E remove_directory <BINARY_DIR> -    COMMAND ${CMAKE_COMMAND} -E make_directory <BINARY_DIR> -    COMMENT "Clobberring ${name} build directory..." -    DEPENDERS configure -    DEPENDS ${LIBCXX_DEPS} +  ExternalProject_Add_Step(${name} clean +    COMMAND ${run_clean} +    COMMENT "Cleaning ${name}..." +    DEPENDEES configure +    ${force_deps} +    WORKING_DIRECTORY ${BINARY_DIR} +    EXCLUDE_FROM_MAIN 1 +    USES_TERMINAL 1      ) +  ExternalProject_Add_StepTargets(${name} clean) + +  if(LIBCXX_USE_TOOLCHAIN) +    add_dependencies(${name}-clean ${name}-clobber) +    set_target_properties(${name}-clean PROPERTIES +      SOURCES ${CMAKE_CURRENT_BINARY_DIR}/${name}-clobber-stamp) +  endif()  endmacro()  function(rt_externalize_debuginfo name) @@ -542,8 +651,10 @@ endfunction()  function(configure_compiler_rt_lit_site_cfg input output)    set_llvm_build_mode() +  get_compiler_rt_output_dir(${COMPILER_RT_DEFAULT_TARGET_ARCH} output_dir) +    string(REPLACE ${CMAKE_CFG_INTDIR} ${LLVM_BUILD_MODE} COMPILER_RT_RESOLVED_TEST_COMPILER ${COMPILER_RT_TEST_COMPILER}) -  string(REPLACE ${CMAKE_CFG_INTDIR} ${LLVM_BUILD_MODE} COMPILER_RT_RESOLVED_LIBRARY_OUTPUT_DIR ${COMPILER_RT_LIBRARY_OUTPUT_DIR}) +  string(REPLACE ${CMAKE_CFG_INTDIR} ${LLVM_BUILD_MODE} COMPILER_RT_RESOLVED_LIBRARY_OUTPUT_DIR ${output_dir})    configure_lit_site_cfg(${input} ${output})  endfunction() diff --git a/cmake/Modules/CompilerRTDarwinUtils.cmake b/cmake/Modules/CompilerRTDarwinUtils.cmake index a25540bf46d1b..04cc955980faa 100644 --- a/cmake/Modules/CompilerRTDarwinUtils.cmake +++ b/cmake/Modules/CompilerRTDarwinUtils.cmake @@ -43,7 +43,7 @@ endfunction()  # link for.  function(darwin_get_toolchain_supported_archs output_var)    execute_process( -    COMMAND ld -v +    COMMAND "${CMAKE_LINKER}" -v      ERROR_VARIABLE LINKER_VERSION)    string(REGEX MATCH "configured to support archs: ([^\n]+)" @@ -230,6 +230,7 @@ macro(darwin_add_builtin_library name suffix)    list(APPEND ${LIB_OS}_${suffix}_libs ${libname})    list(APPEND ${LIB_OS}_${suffix}_lipo_flags -arch ${arch} $<TARGET_FILE:${libname}>) +  set_target_properties(${libname} PROPERTIES FOLDER "Compiler-RT Libraries")  endmacro()  function(darwin_lipo_libs name) @@ -251,6 +252,7 @@ function(darwin_lipo_libs name)      add_dependencies(${LIB_PARENT_TARGET} ${name})      install(FILES ${LIB_OUTPUT_DIR}/lib${name}.a        DESTINATION ${LIB_INSTALL_DIR}) +    set_target_properties(${name} PROPERTIES FOLDER "Compiler-RT Misc")    else()      message(WARNING "Not generating lipo target for ${name} because no input libraries exist.")    endif() diff --git a/cmake/Modules/CompilerRTUtils.cmake b/cmake/Modules/CompilerRTUtils.cmake index 9f79a9b920db5..e5651718fa34d 100644 --- a/cmake/Modules/CompilerRTUtils.cmake +++ b/cmake/Modules/CompilerRTUtils.cmake @@ -168,6 +168,7 @@ macro(detect_target_arch)    check_symbol_exists(__mips64__ "" __MIPS64)    check_symbol_exists(__powerpc64__ "" __PPC64)    check_symbol_exists(__powerpc64le__ "" __PPC64LE) +  check_symbol_exists(__riscv "" __RISCV)    check_symbol_exists(__s390x__ "" __S390X)    check_symbol_exists(__wasm32__ "" __WEBASSEMBLY32)    check_symbol_exists(__wasm64__ "" __WEBASSEMBLY64) @@ -187,6 +188,14 @@ macro(detect_target_arch)      add_default_target_arch(powerpc64)    elseif(__PPC64LE)      add_default_target_arch(powerpc64le) +  elseif(__RISCV) +    if(CMAKE_SIZEOF_VOID_P EQUAL "4") +      add_default_target_arch(riscv32) +    elseif(CMAKE_SIZEOF_VOID_P EQUAL "8") +      add_default_target_arch(riscv64) +    else() +      message(FATAL_ERROR "Unsupport XLEN for RISC-V") +    endif()    elseif(__S390X)      add_default_target_arch(s390x)    elseif(__WEBASSEMBLY32) @@ -305,3 +314,69 @@ function(filter_builtin_sources output_var exclude_or_include excluded_list)    endforeach ()    set(${output_var} ${intermediate} PARENT_SCOPE)  endfunction() + +function(get_compiler_rt_target arch variable) +  if(ANDROID AND ${arch} STREQUAL "i386") +    set(target "i686${COMPILER_RT_OS_SUFFIX}-${COMPILER_RT_DEFAULT_TARGET_OS}") +  else() +    set(target "${arch}-${COMPILER_RT_DEFAULT_TARGET_OS}") +  endif() +  if(COMPILER_RT_DEFAULT_TARGET_ABI) +    set(target "${target}-${COMPILER_RT_DEFAULT_TARGET_ABI}") +  endif() +  set(${variable} ${target} PARENT_SCOPE) +endfunction() + +function(get_compiler_rt_install_dir arch install_dir) +  if(LLVM_ENABLE_PER_TARGET_RUNTIME_DIR AND NOT APPLE) +    get_compiler_rt_target(${arch} target) +    set(${install_dir} ${COMPILER_RT_INSTALL_PATH}/${target}/lib PARENT_SCOPE) +  else() +    set(${install_dir} ${COMPILER_RT_LIBRARY_INSTALL_DIR} PARENT_SCOPE) +  endif() +endfunction() + +function(get_compiler_rt_output_dir arch output_dir) +  if(LLVM_ENABLE_PER_TARGET_RUNTIME_DIR AND NOT APPLE) +    get_compiler_rt_target(${arch} target) +    set(${output_dir} ${COMPILER_RT_OUTPUT_DIR}/${target}/lib PARENT_SCOPE) +  else() +    set(${output_dir} ${COMPILER_RT_LIBRARY_OUTPUT_DIR} PARENT_SCOPE) +  endif() +endfunction() + +# compiler_rt_process_sources( +#   <OUTPUT_VAR> +#   <SOURCE_FILE> ... +#  [ADDITIONAL_HEADERS <header> ...] +# ) +# +# Process the provided sources and write the list of new sources +# into `<OUTPUT_VAR>`. +# +# ADDITIONAL_HEADERS     - Adds the supplied header to list of sources for IDEs. +# +# This function is very similar to `llvm_process_sources()` but exists here +# because we need to support standalone builds of compiler-rt. +function(compiler_rt_process_sources OUTPUT_VAR) +  cmake_parse_arguments( +    ARG +    "" +    "" +    "ADDITIONAL_HEADERS" +    ${ARGN} +  ) +  set(sources ${ARG_UNPARSED_ARGUMENTS}) +  set(headers "") +  if (XCODE OR MSVC_IDE OR CMAKE_EXTRA_GENERATOR) +    # For IDEs we need to tell CMake about header files. +    # Otherwise they won't show up in UI. +    set(headers ${ARG_ADDITIONAL_HEADERS}) +    list(LENGTH headers headers_length) +    if (${headers_length} GREATER 0) +      set_source_files_properties(${headers} +        PROPERTIES HEADER_FILE_ONLY ON) +    endif() +  endif() +  set("${OUTPUT_VAR}" ${sources} ${headers} PARENT_SCOPE) +endfunction() diff --git a/cmake/Modules/HandleCompilerRT.cmake b/cmake/Modules/HandleCompilerRT.cmake index cff5031ec9b23..855d0ff9df1ca 100644 --- a/cmake/Modules/HandleCompilerRT.cmake +++ b/cmake/Modules/HandleCompilerRT.cmake @@ -1,5 +1,4 @@ -function(find_compiler_rt_library name dest) -  set(dest "" PARENT_SCOPE) +function(find_compiler_rt_library name variable)    set(CLANG_COMMAND ${CMAKE_CXX_COMPILER} ${SANITIZER_COMMON_CFLAGS}        "--rtlib=compiler-rt" "--print-libgcc-file-name")    if (CMAKE_CXX_COMPILER_ID MATCHES Clang AND CMAKE_CXX_COMPILER_TARGET) @@ -14,7 +13,7 @@ function(find_compiler_rt_library name dest)    string(REPLACE "builtins" "${name}" LIBRARY_FILE "${LIBRARY_FILE}")    if (NOT HAD_ERROR AND EXISTS "${LIBRARY_FILE}")      message(STATUS "Found compiler-rt ${name} library: ${LIBRARY_FILE}") -    set(${dest} "${LIBRARY_FILE}" PARENT_SCOPE) +    set(${variable} "${LIBRARY_FILE}" PARENT_SCOPE)    else()      message(STATUS "Failed to find compiler-rt ${name} library")    endif() diff --git a/cmake/Modules/SanitizerUtils.cmake b/cmake/Modules/SanitizerUtils.cmake index c80fc3b1eefc2..b6312426cacb1 100644 --- a/cmake/Modules/SanitizerUtils.cmake +++ b/cmake/Modules/SanitizerUtils.cmake @@ -1,3 +1,5 @@ +include(CompilerRTUtils) +  set(SANITIZER_GEN_DYNAMIC_LIST    ${COMPILER_RT_SOURCE_DIR}/lib/sanitizer_common/scripts/gen_dynamic_list.py) @@ -37,9 +39,9 @@ macro(add_sanitizer_rt_symbols name)      add_custom_target(${target_name}-symbols ALL        DEPENDS ${stamp}        SOURCES ${SANITIZER_GEN_DYNAMIC_LIST} ${ARG_EXTRA}) - +    get_compiler_rt_install_dir(${arch} install_dir)      install(FILES $<TARGET_FILE:${target_name}>.syms -            DESTINATION ${COMPILER_RT_LIBRARY_INSTALL_DIR}) +            DESTINATION ${install_dir})      if(ARG_PARENT_TARGET)        add_dependencies(${ARG_PARENT_TARGET} ${target_name}-symbols)      endif() @@ -81,7 +83,7 @@ macro(add_sanitizer_rt_version_list name)  endmacro()  # Add target to check code style for sanitizer runtimes. -if(CMAKE_HOST_UNIX) +if(CMAKE_HOST_UNIX AND NOT OS_NAME MATCHES "OpenBSD")    add_custom_target(SanitizerLintCheck      COMMAND env LLVM_CHECKOUT=${LLVM_MAIN_SRC_DIR} SILENT=1 TMPDIR=        PYTHON_EXECUTABLE=${PYTHON_EXECUTABLE} @@ -90,5 +92,9 @@ if(CMAKE_HOST_UNIX)      DEPENDS ${SANITIZER_LINT_SCRIPT}      COMMENT "Running lint check for sanitizer sources..."      VERBATIM) +else() +  add_custom_target(SanitizerLintCheck +    COMMAND echo "No lint check")  endif() - +set_target_properties(SanitizerLintCheck +  PROPERTIES FOLDER "Compiler-RT Misc") diff --git a/cmake/base-config-ix.cmake b/cmake/base-config-ix.cmake index b208f08524084..91fe2494b4765 100644 --- a/cmake/base-config-ix.cmake +++ b/cmake/base-config-ix.cmake @@ -12,7 +12,14 @@ check_include_file(unwind.h HAVE_UNWIND_H)  add_custom_target(compiler-rt ALL)  add_custom_target(install-compiler-rt)  add_custom_target(install-compiler-rt-stripped) -set_target_properties(compiler-rt PROPERTIES FOLDER "Compiler-RT Misc") +set_property( +  TARGET +    compiler-rt +    install-compiler-rt +    install-compiler-rt-stripped +  PROPERTY +    FOLDER "Compiler-RT Misc" +)  # Setting these variables from an LLVM build is sufficient that compiler-rt can  # construct the output paths, so it can behave as if it were in-tree here. @@ -69,10 +76,17 @@ endif()  if(NOT DEFINED COMPILER_RT_OS_DIR)    string(TOLOWER ${CMAKE_SYSTEM_NAME} COMPILER_RT_OS_DIR)  endif() -set(COMPILER_RT_LIBRARY_OUTPUT_DIR -  ${COMPILER_RT_OUTPUT_DIR}/lib/${COMPILER_RT_OS_DIR}) -set(COMPILER_RT_LIBRARY_INSTALL_DIR -  ${COMPILER_RT_INSTALL_PATH}/lib/${COMPILER_RT_OS_DIR}) +if(LLVM_ENABLE_PER_TARGET_RUNTIME_DIR AND NOT APPLE) +  set(COMPILER_RT_LIBRARY_OUTPUT_DIR +    ${COMPILER_RT_OUTPUT_DIR}) +  set(COMPILER_RT_LIBRARY_INSTALL_DIR +    ${COMPILER_RT_INSTALL_PATH}) +else(LLVM_ENABLE_PER_TARGET_RUNTIME_DIR) +  set(COMPILER_RT_LIBRARY_OUTPUT_DIR +    ${COMPILER_RT_OUTPUT_DIR}/lib/${COMPILER_RT_OS_DIR}) +  set(COMPILER_RT_LIBRARY_INSTALL_DIR +    ${COMPILER_RT_INSTALL_PATH}/lib/${COMPILER_RT_OS_DIR}) +endif()  if(APPLE)    # On Darwin if /usr/include doesn't exist, the user probably has Xcode but not @@ -139,8 +153,16 @@ macro(test_targets)        add_default_target_arch(${COMPILER_RT_DEFAULT_TARGET_ARCH})      elseif("${COMPILER_RT_DEFAULT_TARGET_ARCH}" MATCHES "i[2-6]86|x86|amd64")        if(NOT MSVC) -        test_target_arch(x86_64 "" "-m64") -        test_target_arch(i386 __i386__ "-m32") +        if(CMAKE_SYSTEM_NAME MATCHES "OpenBSD") +          if (CMAKE_SIZEOF_VOID_P EQUAL 4) +            test_target_arch(i386 __i386__ "-m32") +          else() +            test_target_arch(x86_64 "" "-m64") +          endif() +        else() +          test_target_arch(x86_64 "" "-m64") +          test_target_arch(i386 __i386__ "-m32") +        endif()        else()          if (CMAKE_SIZEOF_VOID_P EQUAL 4)            test_target_arch(i386 "" "") @@ -186,6 +208,10 @@ macro(test_targets)        test_target_arch(aarch32 "" "-march=armv8-a")      elseif("${COMPILER_RT_DEFAULT_TARGET_ARCH}" MATCHES "aarch64")        test_target_arch(aarch64 "" "-march=armv8-a") +    elseif("${COMPILER_RT_DEFAULT_TARGET_ARCH}" MATCHES "riscv32") +      test_target_arch(riscv32 "" "") +    elseif("${COMPILER_RT_DEFAULT_TARGET_ARCH}" MATCHES "riscv64") +      test_target_arch(riscv64 "" "")      elseif("${COMPILER_RT_DEFAULT_TARGET_ARCH}" MATCHES "wasm32")        test_target_arch(wasm32 "" "--target=wasm32-unknown-unknown")      elseif("${COMPILER_RT_DEFAULT_TARGET_ARCH}" MATCHES "wasm64") diff --git a/cmake/builtin-config-ix.cmake b/cmake/builtin-config-ix.cmake index bdb2529b5ee20..a5704e5fed537 100644 --- a/cmake/builtin-config-ix.cmake +++ b/cmake/builtin-config-ix.cmake @@ -25,11 +25,14 @@ int foo(int x, int y) {  set(ARM64 aarch64)  set(ARM32 arm armhf armv6m armv7m armv7em armv7 armv7s armv7k) +set(HEXAGON hexagon)  set(X86 i386)  set(X86_64 x86_64)  set(MIPS32 mips mipsel)  set(MIPS64 mips64 mips64el)  set(PPC64 powerpc64 powerpc64le) +set(RISCV32 riscv32) +set(RISCV64 riscv64)  set(WASM32 wasm32)  set(WASM64 wasm64) @@ -40,7 +43,7 @@ if(APPLE)  endif()  set(ALL_BUILTIN_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64} -    ${MIPS32} ${MIPS64} ${PPC64} ${WASM32} ${WASM64}) +    ${HEXAGON} ${MIPS32} ${MIPS64} ${PPC64} ${RISCV32} ${RISCV64} ${WASM32} ${WASM64})  include(CompilerRTUtils)  include(CompilerRTDarwinUtils) diff --git a/cmake/config-ix.cmake b/cmake/config-ix.cmake index 9e0c4774829fc..f3935ffd6fd2d 100644 --- a/cmake/config-ix.cmake +++ b/cmake/config-ix.cmake @@ -13,7 +13,10 @@ function(check_linker_flag flag out_var)  endfunction()  check_library_exists(c fopen "" COMPILER_RT_HAS_LIBC) -if (NOT SANITIZER_USE_COMPILER_RT) +if (COMPILER_RT_USE_BUILTINS_LIBRARY) +  include(HandleCompilerRT) +  find_compiler_rt_library(builtins COMPILER_RT_BUILTINS_LIBRARY) +else()    if (ANDROID)      check_library_exists(gcc __gcc_personality_v0 "" COMPILER_RT_HAS_GCC_LIB)    else() @@ -27,9 +30,7 @@ if (COMPILER_RT_HAS_NODEFAULTLIBS_FLAG)    if (COMPILER_RT_HAS_LIBC)      list(APPEND CMAKE_REQUIRED_LIBRARIES c)    endif () -  if (SANITIZER_USE_COMPILER_RT) -    list(APPEND CMAKE_REQUIRED_FLAGS -rtlib=compiler-rt) -    find_compiler_rt_library(builtins COMPILER_RT_BUILTINS_LIBRARY) +  if (COMPILER_RT_USE_BUILTINS_LIBRARY)      list(APPEND CMAKE_REQUIRED_LIBRARIES "${COMPILER_RT_BUILTINS_LIBRARY}")    elseif (COMPILER_RT_HAS_GCC_S_LIB)      list(APPEND CMAKE_REQUIRED_LIBRARIES gcc_s) @@ -108,6 +109,7 @@ if (ANDROID AND COMPILER_RT_HAS_LIBDL)    # Android's libstdc++ has a dependency on libdl.    list(APPEND CMAKE_REQUIRED_LIBRARIES dl)  endif() +check_library_exists(c++ __cxa_throw "" COMPILER_RT_HAS_LIBCXX)  check_library_exists(stdc++ __cxa_throw "" COMPILER_RT_HAS_LIBSTDCXX)  # Linker flags. @@ -174,11 +176,14 @@ endmacro()  set(ARM64 aarch64)  set(ARM32 arm armhf) +set(HEXAGON hexagon)  set(X86 i386)  set(X86_64 x86_64)  set(MIPS32 mips mipsel)  set(MIPS64 mips64 mips64el)  set(PPC64 powerpc64 powerpc64le) +set(RISCV32 riscv32) +set(RISCV64 riscv64)  set(S390X s390x)  set(WASM32 wasm32)  set(WASM64 wasm64) @@ -194,7 +199,7 @@ set(ALL_SANITIZER_COMMON_SUPPORTED_ARCH ${X86} ${X86_64} ${PPC64}  set(ALL_ASAN_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64}      ${MIPS32} ${MIPS64} ${PPC64} ${S390X})  set(ALL_DFSAN_SUPPORTED_ARCH ${X86_64} ${MIPS64} ${ARM64}) -set(ALL_FUZZER_SUPPORTED_ARCH x86_64) +set(ALL_FUZZER_SUPPORTED_ARCH ${X86_64} ${ARM64})  if(APPLE)    set(ALL_LSAN_SUPPORTED_ARCH ${X86} ${X86_64} ${MIPS64} ${ARM64}) @@ -202,7 +207,7 @@ else()    set(ALL_LSAN_SUPPORTED_ARCH ${X86} ${X86_64} ${MIPS64} ${ARM64} ${ARM32} ${PPC64})  endif()  set(ALL_MSAN_SUPPORTED_ARCH ${X86_64} ${MIPS64} ${ARM64} ${PPC64}) -set(ALL_HWASAN_SUPPORTED_ARCH ${ARM64}) +set(ALL_HWASAN_SUPPORTED_ARCH ${X86_64} ${ARM64})  set(ALL_PROFILE_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64} ${PPC64}      ${MIPS32} ${MIPS64} ${S390X})  set(ALL_TSAN_SUPPORTED_ARCH ${X86_64} ${MIPS64} ${ARM64} ${PPC64}) @@ -211,12 +216,13 @@ set(ALL_UBSAN_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64}  set(ALL_SAFESTACK_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM64} ${MIPS32} ${MIPS64})  set(ALL_CFI_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64} ${MIPS64})  set(ALL_ESAN_SUPPORTED_ARCH ${X86_64} ${MIPS64}) -set(ALL_SCUDO_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64} ${MIPS32} ${MIPS64}) +set(ALL_SCUDO_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64} ${MIPS32} ${MIPS64} ${PPC64})  if(APPLE)  set(ALL_XRAY_SUPPORTED_ARCH ${X86_64})  else()  set(ALL_XRAY_SUPPORTED_ARCH ${X86_64} ${ARM32} ${ARM64} ${MIPS32} ${MIPS64} powerpc64le)  endif() +set(ALL_SHADOWCALLSTACK_SUPPORTED_ARCH ${X86_64} ${ARM64})  if(APPLE)    include(CompilerRTDarwinUtils) @@ -365,7 +371,11 @@ if(APPLE)          if(DARWIN_${platform}_ARCHS)            list(APPEND SANITIZER_COMMON_SUPPORTED_OS ${platform})            list(APPEND PROFILE_SUPPORTED_OS ${platform}) -          list(APPEND TSAN_SUPPORTED_OS ${platform}) + +          list_intersect(DARWIN_${platform}_TSAN_ARCHS DARWIN_${platform}_ARCHS ALL_TSAN_SUPPORTED_ARCH) +          if(DARWIN_${platform}_TSAN_ARCHS) +            list(APPEND TSAN_SUPPORTED_OS ${platform}) +          endif()          endif()          foreach(arch ${DARWIN_${platform}_ARCHS})            list(APPEND COMPILER_RT_SUPPORTED_ARCH ${arch}) @@ -378,7 +388,6 @@ if(APPLE)    # for list_intersect    include(CompilerRTUtils) -    list_intersect(SANITIZER_COMMON_SUPPORTED_ARCH      ALL_SANITIZER_COMMON_SUPPORTED_ARCH      COMPILER_RT_SUPPORTED_ARCH @@ -423,10 +432,13 @@ if(APPLE)      SANITIZER_COMMON_SUPPORTED_ARCH)    list_intersect(FUZZER_SUPPORTED_ARCH      ALL_FUZZER_SUPPORTED_ARCH -    ALL_SANITIZER_COMMON_SUPPORTED_ARCH) +    SANITIZER_COMMON_SUPPORTED_ARCH)    list_intersect(XRAY_SUPPORTED_ARCH      ALL_XRAY_SUPPORTED_ARCH      SANITIZER_COMMON_SUPPORTED_ARCH) +  list_intersect(SHADOWCALLSTACK_SUPPORTED_ARCH +    ALL_SHADOWCALLSTACK_SUPPORTED_ARCH +    SANITIZER_COMMON_SUPPORTED_ARCH)  else()    # Architectures supported by compiler-rt libraries. @@ -453,6 +465,8 @@ else()    filter_available_targets(ESAN_SUPPORTED_ARCH ${ALL_ESAN_SUPPORTED_ARCH})    filter_available_targets(SCUDO_SUPPORTED_ARCH ${ALL_SCUDO_SUPPORTED_ARCH})    filter_available_targets(XRAY_SUPPORTED_ARCH ${ALL_XRAY_SUPPORTED_ARCH}) +  filter_available_targets(SHADOWCALLSTACK_SUPPORTED_ARCH +    ${ALL_SHADOWCALLSTACK_SUPPORTED_ARCH})  endif()  if (MSVC) @@ -486,7 +500,7 @@ set(COMPILER_RT_SANITIZERS_TO_BUILD all CACHE STRING  list_replace(COMPILER_RT_SANITIZERS_TO_BUILD all "${ALL_SANITIZERS}")  if (SANITIZER_COMMON_SUPPORTED_ARCH AND NOT LLVM_USE_SANITIZER AND -    (OS_NAME MATCHES "Android|Darwin|Linux|FreeBSD|NetBSD|Fuchsia|SunOS" OR +    (OS_NAME MATCHES "Android|Darwin|Linux|FreeBSD|NetBSD|OpenBSD|Fuchsia|SunOS" OR      (OS_NAME MATCHES "Windows" AND (NOT MINGW AND NOT CYGWIN))))    set(COMPILER_RT_HAS_SANITIZER_COMMON TRUE)  else() @@ -499,7 +513,8 @@ else()    set(COMPILER_RT_HAS_INTERCEPTION FALSE)  endif() -if (COMPILER_RT_HAS_SANITIZER_COMMON AND ASAN_SUPPORTED_ARCH) +if (COMPILER_RT_HAS_SANITIZER_COMMON AND ASAN_SUPPORTED_ARCH AND +    NOT OS_NAME MATCHES "OpenBSD")    set(COMPILER_RT_HAS_ASAN TRUE)  else()    set(COMPILER_RT_HAS_ASAN FALSE) @@ -528,7 +543,7 @@ else()  endif()  if (COMPILER_RT_HAS_SANITIZER_COMMON AND MSAN_SUPPORTED_ARCH AND -    OS_NAME MATCHES "Linux|NetBSD") +    OS_NAME MATCHES "Linux|FreeBSD|NetBSD")    set(COMPILER_RT_HAS_MSAN TRUE)  else()    set(COMPILER_RT_HAS_MSAN FALSE) @@ -542,7 +557,7 @@ else()  endif()  if (PROFILE_SUPPORTED_ARCH AND NOT LLVM_USE_SANITIZER AND -    OS_NAME MATCHES "Darwin|Linux|FreeBSD|Windows|Android|SunOS") +    OS_NAME MATCHES "Darwin|Linux|FreeBSD|Windows|Android|Fuchsia|SunOS")    set(COMPILER_RT_HAS_PROFILE TRUE)  else()    set(COMPILER_RT_HAS_PROFILE FALSE) @@ -556,14 +571,14 @@ else()  endif()  if (COMPILER_RT_HAS_SANITIZER_COMMON AND UBSAN_SUPPORTED_ARCH AND -    OS_NAME MATCHES "Darwin|Linux|FreeBSD|NetBSD|Windows|Android|Fuchsia|SunOS") +    OS_NAME MATCHES "Darwin|Linux|FreeBSD|NetBSD|OpenBSD|Windows|Android|Fuchsia|SunOS")    set(COMPILER_RT_HAS_UBSAN TRUE)  else()    set(COMPILER_RT_HAS_UBSAN FALSE)  endif()  if (COMPILER_RT_HAS_SANITIZER_COMMON AND UBSAN_SUPPORTED_ARCH AND -    OS_NAME MATCHES "Linux|FreeBSD|NetBSD|Android|Darwin") +    OS_NAME MATCHES "Linux|FreeBSD|NetBSD|OpenBSD|Android|Darwin")    set(COMPILER_RT_HAS_UBSAN_MINIMAL TRUE)  else()    set(COMPILER_RT_HAS_UBSAN_MINIMAL FALSE) @@ -590,22 +605,29 @@ else()  endif()  if (COMPILER_RT_HAS_SANITIZER_COMMON AND SCUDO_SUPPORTED_ARCH AND -    OS_NAME MATCHES "Linux|Android") +    OS_NAME MATCHES "Linux|Android|Fuchsia")    set(COMPILER_RT_HAS_SCUDO TRUE)  else()    set(COMPILER_RT_HAS_SCUDO FALSE)  endif()  if (COMPILER_RT_HAS_SANITIZER_COMMON AND XRAY_SUPPORTED_ARCH AND -    OS_NAME MATCHES "Darwin|Linux") +    OS_NAME MATCHES "Darwin|Linux|FreeBSD|NetBSD|OpenBSD")    set(COMPILER_RT_HAS_XRAY TRUE)  else()    set(COMPILER_RT_HAS_XRAY FALSE)  endif()  if (COMPILER_RT_HAS_SANITIZER_COMMON AND FUZZER_SUPPORTED_ARCH AND -    OS_NAME MATCHES "Android|Darwin|Linux|NetBSD") +    OS_NAME MATCHES "Android|Darwin|Linux|NetBSD|FreeBSD|OpenBSD|Fuchsia")    set(COMPILER_RT_HAS_FUZZER TRUE)  else()    set(COMPILER_RT_HAS_FUZZER FALSE)  endif() + +if (COMPILER_RT_HAS_SANITIZER_COMMON AND SHADOWCALLSTACK_SUPPORTED_ARCH AND +    OS_NAME MATCHES "Linux|Android") +  set(COMPILER_RT_HAS_SHADOWCALLSTACK TRUE) +else() +  set(COMPILER_RT_HAS_SHADOWCALLSTACK FALSE) +endif() diff --git a/include/CMakeLists.txt b/include/CMakeLists.txt index f7efb102ab631..c4b93b89a30cb 100644 --- a/include/CMakeLists.txt +++ b/include/CMakeLists.txt @@ -10,6 +10,7 @@ if (COMPILER_RT_BUILD_SANITIZERS)      sanitizer/linux_syscall_hooks.h      sanitizer/lsan_interface.h      sanitizer/msan_interface.h +    sanitizer/netbsd_syscall_hooks.h      sanitizer/scudo_interface.h      sanitizer/tsan_interface.h      sanitizer/tsan_interface_atomic.h) diff --git a/include/sanitizer/common_interface_defs.h b/include/sanitizer/common_interface_defs.h index 6d4326f740210..d11cb1addc279 100644 --- a/include/sanitizer/common_interface_defs.h +++ b/include/sanitizer/common_interface_defs.h @@ -65,6 +65,11 @@ extern "C" {    void __sanitizer_unaligned_store32(void *p, uint32_t x);    void __sanitizer_unaligned_store64(void *p, uint64_t x); +  // Returns 1 on the first call, then returns 0 thereafter.  Called by the tool +  // to ensure only one report is printed when multiple errors occur +  // simultaneously. +  int __sanitizer_acquire_crash_state(); +    // Annotate the current state of a contiguous container, such as    // std::vector, std::string or similar.    // A contiguous container is a container that keeps all of its elements diff --git a/include/sanitizer/msan_interface.h b/include/sanitizer/msan_interface.h index a87c954c15ec2..0509551bbd171 100644 --- a/include/sanitizer/msan_interface.h +++ b/include/sanitizer/msan_interface.h @@ -104,6 +104,14 @@ extern "C" {       copy. Source and destination regions can overlap. */    void __msan_copy_shadow(const volatile void *dst, const volatile void *src,                            size_t size); + +  /* Disables uninitialized memory checks in interceptors. */ +  void __msan_scoped_disable_interceptor_checks(void); + +  /* Re-enables uninitialized memory checks in interceptors after a previous +     call to __msan_scoped_disable_interceptor_checks. */ +  void __msan_scoped_enable_interceptor_checks(void); +  #ifdef __cplusplus  }  // extern "C"  #endif diff --git a/include/sanitizer/netbsd_syscall_hooks.h b/include/sanitizer/netbsd_syscall_hooks.h new file mode 100644 index 0000000000000..4c6c6a88af29a --- /dev/null +++ b/include/sanitizer/netbsd_syscall_hooks.h @@ -0,0 +1,4734 @@ +//===-- netbsd_syscall_hooks.h --------------------------------------------===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of public sanitizer interface. +// +// System call handlers. +// +// Interface methods declared in this header implement pre- and post- syscall +// actions for the active sanitizer. +// Usage: +//   __sanitizer_syscall_pre_getfoo(...args...); +//   long long res = syscall(SYS_getfoo, ...args...); +//   __sanitizer_syscall_post_getfoo(res, ...args...); +// +// DO NOT EDIT! THIS FILE HAS BEEN GENERATED! +// +// Generated with: generate_netbsd_syscalls.awk +// Generated date: 2018-03-03 +// Generated from: syscalls.master,v 1.291 2018/01/06 16:41:23 kamil Exp +// +//===----------------------------------------------------------------------===// +#ifndef SANITIZER_NETBSD_SYSCALL_HOOKS_H +#define SANITIZER_NETBSD_SYSCALL_HOOKS_H + +#define __sanitizer_syscall_pre_syscall(code, arg0, arg1, arg2, arg3, arg4,    \ +                                        arg5, arg6, arg7)                      \ +  __sanitizer_syscall_pre_impl_syscall(                                        \ +      (long long)(code), (long long)(arg0), (long long)(arg1),                 \ +      (long long)(arg2), (long long)(arg3), (long long)(arg4),                 \ +      (long long)(arg5), (long long)(arg6), (long long)(arg7)) +#define __sanitizer_syscall_post_syscall(res, code, arg0, arg1, arg2, arg3,    \ +                                         arg4, arg5, arg6, arg7)               \ +  __sanitizer_syscall_post_impl_syscall(                                       \ +      res, (long long)(code), (long long)(arg0), (long long)(arg1),            \ +      (long long)(arg2), (long long)(arg3), (long long)(arg4),                 \ +      (long long)(arg5), (long long)(arg6), (long long)(arg7)) +#define __sanitizer_syscall_pre_exit(rval)                                     \ +  __sanitizer_syscall_pre_impl_exit((long long)(rval)) +#define __sanitizer_syscall_post_exit(res, rval)                               \ +  __sanitizer_syscall_post_impl_exit(res, (long long)(rval)) +#define __sanitizer_syscall_pre_fork() __sanitizer_syscall_pre_impl_fork() +#define __sanitizer_syscall_post_fork(res)                                     \ +  __sanitizer_syscall_post_impl_fork(res) +#define __sanitizer_syscall_pre_read(fd, buf, nbyte)                           \ +  __sanitizer_syscall_pre_impl_read((long long)(fd), (long long)(buf),         \ +                                    (long long)(nbyte)) +#define __sanitizer_syscall_post_read(res, fd, buf, nbyte)                     \ +  __sanitizer_syscall_post_impl_read(res, (long long)(fd), (long long)(buf),   \ +                                     (long long)(nbyte)) +#define __sanitizer_syscall_pre_write(fd, buf, nbyte)                          \ +  __sanitizer_syscall_pre_impl_write((long long)(fd), (long long)(buf),        \ +                                     (long long)(nbyte)) +#define __sanitizer_syscall_post_write(res, fd, buf, nbyte)                    \ +  __sanitizer_syscall_post_impl_write(res, (long long)(fd), (long long)(buf),  \ +                                      (long long)(nbyte)) +#define __sanitizer_syscall_pre_open(path, flags, mode)                        \ +  __sanitizer_syscall_pre_impl_open((long long)(path), (long long)(flags),     \ +                                    (long long)(mode)) +#define __sanitizer_syscall_post_open(res, path, flags, mode)                  \ +  __sanitizer_syscall_post_impl_open(res, (long long)(path),                   \ +                                     (long long)(flags), (long long)(mode)) +#define __sanitizer_syscall_pre_close(fd)                                      \ +  __sanitizer_syscall_pre_impl_close((long long)(fd)) +#define __sanitizer_syscall_post_close(res, fd)                                \ +  __sanitizer_syscall_post_impl_close(res, (long long)(fd)) +#define __sanitizer_syscall_pre_compat_50_wait4(pid, status, options, rusage)  \ +  __sanitizer_syscall_pre_impl_compat_50_wait4(                                \ +      (long long)(pid), (long long)(status), (long long)(options),             \ +      (long long)(rusage)) +#define __sanitizer_syscall_post_compat_50_wait4(res, pid, status, options,    \ +                                                 rusage)                       \ +  __sanitizer_syscall_post_impl_compat_50_wait4(                               \ +      res, (long long)(pid), (long long)(status), (long long)(options),        \ +      (long long)(rusage)) +#define __sanitizer_syscall_pre_compat_43_ocreat(path, mode)                   \ +  __sanitizer_syscall_pre_impl_compat_43_ocreat((long long)(path),             \ +                                                (long long)(mode)) +#define __sanitizer_syscall_post_compat_43_ocreat(res, path, mode)             \ +  __sanitizer_syscall_post_impl_compat_43_ocreat(res, (long long)(path),       \ +                                                 (long long)(mode)) +#define __sanitizer_syscall_pre_link(path, link)                               \ +  __sanitizer_syscall_pre_impl_link((long long)(path), (long long)(link)) +#define __sanitizer_syscall_post_link(res, path, link)                         \ +  __sanitizer_syscall_post_impl_link(res, (long long)(path), (long long)(link)) +#define __sanitizer_syscall_pre_unlink(path)                                   \ +  __sanitizer_syscall_pre_impl_unlink((long long)(path)) +#define __sanitizer_syscall_post_unlink(res, path)                             \ +  __sanitizer_syscall_post_impl_unlink(res, (long long)(path)) +/* syscall 11 has been skipped */ +#define __sanitizer_syscall_pre_chdir(path)                                    \ +  __sanitizer_syscall_pre_impl_chdir((long long)(path)) +#define __sanitizer_syscall_post_chdir(res, path)                              \ +  __sanitizer_syscall_post_impl_chdir(res, (long long)(path)) +#define __sanitizer_syscall_pre_fchdir(fd)                                     \ +  __sanitizer_syscall_pre_impl_fchdir((long long)(fd)) +#define __sanitizer_syscall_post_fchdir(res, fd)                               \ +  __sanitizer_syscall_post_impl_fchdir(res, (long long)(fd)) +#define __sanitizer_syscall_pre_compat_50_mknod(path, mode, dev)               \ +  __sanitizer_syscall_pre_impl_compat_50_mknod(                                \ +      (long long)(path), (long long)(mode), (long long)(dev)) +#define __sanitizer_syscall_post_compat_50_mknod(res, path, mode, dev)         \ +  __sanitizer_syscall_post_impl_compat_50_mknod(                               \ +      res, (long long)(path), (long long)(mode), (long long)(dev)) +#define __sanitizer_syscall_pre_chmod(path, mode)                              \ +  __sanitizer_syscall_pre_impl_chmod((long long)(path), (long long)(mode)) +#define __sanitizer_syscall_post_chmod(res, path, mode)                        \ +  __sanitizer_syscall_post_impl_chmod(res, (long long)(path), (long long)(mode)) +#define __sanitizer_syscall_pre_chown(path, uid, gid)                          \ +  __sanitizer_syscall_pre_impl_chown((long long)(path), (long long)(uid),      \ +                                     (long long)(gid)) +#define __sanitizer_syscall_post_chown(res, path, uid, gid)                    \ +  __sanitizer_syscall_post_impl_chown(res, (long long)(path),                  \ +                                      (long long)(uid), (long long)(gid)) +#define __sanitizer_syscall_pre_break(nsize)                                   \ +  __sanitizer_syscall_pre_impl_break((long long)(nsize)) +#define __sanitizer_syscall_post_break(res, nsize)                             \ +  __sanitizer_syscall_post_impl_break(res, (long long)(nsize)) +#define __sanitizer_syscall_pre_compat_20_getfsstat(buf, bufsize, flags)       \ +  __sanitizer_syscall_pre_impl_compat_20_getfsstat(                            \ +      (long long)(buf), (long long)(bufsize), (long long)(flags)) +#define __sanitizer_syscall_post_compat_20_getfsstat(res, buf, bufsize, flags) \ +  __sanitizer_syscall_post_impl_compat_20_getfsstat(                           \ +      res, (long long)(buf), (long long)(bufsize), (long long)(flags)) +#define __sanitizer_syscall_pre_compat_43_olseek(fd, offset, whence)           \ +  __sanitizer_syscall_pre_impl_compat_43_olseek(                               \ +      (long long)(fd), (long long)(offset), (long long)(whence)) +#define __sanitizer_syscall_post_compat_43_olseek(res, fd, offset, whence)     \ +  __sanitizer_syscall_post_impl_compat_43_olseek(                              \ +      res, (long long)(fd), (long long)(offset), (long long)(whence)) +#define __sanitizer_syscall_pre_getpid() __sanitizer_syscall_pre_impl_getpid() +#define __sanitizer_syscall_post_getpid(res)                                   \ +  __sanitizer_syscall_post_impl_getpid(res) +#define __sanitizer_syscall_pre_compat_40_mount(type, path, flags, data)       \ +  __sanitizer_syscall_pre_impl_compat_40_mount(                                \ +      (long long)(type), (long long)(path), (long long)(flags),                \ +      (long long)(data)) +#define __sanitizer_syscall_post_compat_40_mount(res, type, path, flags, data) \ +  __sanitizer_syscall_post_impl_compat_40_mount(                               \ +      res, (long long)(type), (long long)(path), (long long)(flags),           \ +      (long long)(data)) +#define __sanitizer_syscall_pre_unmount(path, flags)                           \ +  __sanitizer_syscall_pre_impl_unmount((long long)(path), (long long)(flags)) +#define __sanitizer_syscall_post_unmount(res, path, flags)                     \ +  __sanitizer_syscall_post_impl_unmount(res, (long long)(path),                \ +                                        (long long)(flags)) +#define __sanitizer_syscall_pre_setuid(uid)                                    \ +  __sanitizer_syscall_pre_impl_setuid((long long)(uid)) +#define __sanitizer_syscall_post_setuid(res, uid)                              \ +  __sanitizer_syscall_post_impl_setuid(res, (long long)(uid)) +#define __sanitizer_syscall_pre_getuid() __sanitizer_syscall_pre_impl_getuid() +#define __sanitizer_syscall_post_getuid(res)                                   \ +  __sanitizer_syscall_post_impl_getuid(res) +#define __sanitizer_syscall_pre_geteuid() __sanitizer_syscall_pre_impl_geteuid() +#define __sanitizer_syscall_post_geteuid(res)                                  \ +  __sanitizer_syscall_post_impl_geteuid(res) +#define __sanitizer_syscall_pre_ptrace(req, pid, addr, data)                   \ +  __sanitizer_syscall_pre_impl_ptrace((long long)(req), (long long)(pid),      \ +                                      (long long)(addr), (long long)(data)) +#define __sanitizer_syscall_post_ptrace(res, req, pid, addr, data)             \ +  __sanitizer_syscall_post_impl_ptrace(res, (long long)(req),                  \ +                                       (long long)(pid), (long long)(addr),    \ +                                       (long long)(data)) +#define __sanitizer_syscall_pre_recvmsg(s, msg, flags)                         \ +  __sanitizer_syscall_pre_impl_recvmsg((long long)(s), (long long)(msg),       \ +                                       (long long)(flags)) +#define __sanitizer_syscall_post_recvmsg(res, s, msg, flags)                   \ +  __sanitizer_syscall_post_impl_recvmsg(res, (long long)(s), (long long)(msg), \ +                                        (long long)(flags)) +#define __sanitizer_syscall_pre_sendmsg(s, msg, flags)                         \ +  __sanitizer_syscall_pre_impl_sendmsg((long long)(s), (long long)(msg),       \ +                                       (long long)(flags)) +#define __sanitizer_syscall_post_sendmsg(res, s, msg, flags)                   \ +  __sanitizer_syscall_post_impl_sendmsg(res, (long long)(s), (long long)(msg), \ +                                        (long long)(flags)) +#define __sanitizer_syscall_pre_recvfrom(s, buf, len, flags, from,             \ +                                         fromlenaddr)                          \ +  __sanitizer_syscall_pre_impl_recvfrom(                                       \ +      (long long)(s), (long long)(buf), (long long)(len), (long long)(flags),  \ +      (long long)(from), (long long)(fromlenaddr)) +#define __sanitizer_syscall_post_recvfrom(res, s, buf, len, flags, from,       \ +                                          fromlenaddr)                         \ +  __sanitizer_syscall_post_impl_recvfrom(                                      \ +      res, (long long)(s), (long long)(buf), (long long)(len),                 \ +      (long long)(flags), (long long)(from), (long long)(fromlenaddr)) +#define __sanitizer_syscall_pre_accept(s, name, anamelen)                      \ +  __sanitizer_syscall_pre_impl_accept((long long)(s), (long long)(name),       \ +                                      (long long)(anamelen)) +#define __sanitizer_syscall_post_accept(res, s, name, anamelen)                \ +  __sanitizer_syscall_post_impl_accept(res, (long long)(s), (long long)(name), \ +                                       (long long)(anamelen)) +#define __sanitizer_syscall_pre_getpeername(fdes, asa, alen)                   \ +  __sanitizer_syscall_pre_impl_getpeername(                                    \ +      (long long)(fdes), (long long)(asa), (long long)(alen)) +#define __sanitizer_syscall_post_getpeername(res, fdes, asa, alen)             \ +  __sanitizer_syscall_post_impl_getpeername(                                   \ +      res, (long long)(fdes), (long long)(asa), (long long)(alen)) +#define __sanitizer_syscall_pre_getsockname(fdes, asa, alen)                   \ +  __sanitizer_syscall_pre_impl_getsockname(                                    \ +      (long long)(fdes), (long long)(asa), (long long)(alen)) +#define __sanitizer_syscall_post_getsockname(res, fdes, asa, alen)             \ +  __sanitizer_syscall_post_impl_getsockname(                                   \ +      res, (long long)(fdes), (long long)(asa), (long long)(alen)) +#define __sanitizer_syscall_pre_access(path, flags)                            \ +  __sanitizer_syscall_pre_impl_access((long long)(path), (long long)(flags)) +#define __sanitizer_syscall_post_access(res, path, flags)                      \ +  __sanitizer_syscall_post_impl_access(res, (long long)(path),                 \ +                                       (long long)(flags)) +#define __sanitizer_syscall_pre_chflags(path, flags)                           \ +  __sanitizer_syscall_pre_impl_chflags((long long)(path), (long long)(flags)) +#define __sanitizer_syscall_post_chflags(res, path, flags)                     \ +  __sanitizer_syscall_post_impl_chflags(res, (long long)(path),                \ +                                        (long long)(flags)) +#define __sanitizer_syscall_pre_fchflags(fd, flags)                            \ +  __sanitizer_syscall_pre_impl_fchflags((long long)(fd), (long long)(flags)) +#define __sanitizer_syscall_post_fchflags(res, fd, flags)                      \ +  __sanitizer_syscall_post_impl_fchflags(res, (long long)(fd),                 \ +                                         (long long)(flags)) +#define __sanitizer_syscall_pre_sync() __sanitizer_syscall_pre_impl_sync() +#define __sanitizer_syscall_post_sync(res)                                     \ +  __sanitizer_syscall_post_impl_sync(res) +#define __sanitizer_syscall_pre_kill(pid, signum)                              \ +  __sanitizer_syscall_pre_impl_kill((long long)(pid), (long long)(signum)) +#define __sanitizer_syscall_post_kill(res, pid, signum)                        \ +  __sanitizer_syscall_post_impl_kill(res, (long long)(pid), (long long)(signum)) +#define __sanitizer_syscall_pre_compat_43_stat43(path, ub)                     \ +  __sanitizer_syscall_pre_impl_compat_43_stat43((long long)(path),             \ +                                                (long long)(ub)) +#define __sanitizer_syscall_post_compat_43_stat43(res, path, ub)               \ +  __sanitizer_syscall_post_impl_compat_43_stat43(res, (long long)(path),       \ +                                                 (long long)(ub)) +#define __sanitizer_syscall_pre_getppid() __sanitizer_syscall_pre_impl_getppid() +#define __sanitizer_syscall_post_getppid(res)                                  \ +  __sanitizer_syscall_post_impl_getppid(res) +#define __sanitizer_syscall_pre_compat_43_lstat43(path, ub)                    \ +  __sanitizer_syscall_pre_impl_compat_43_lstat43((long long)(path),            \ +                                                 (long long)(ub)) +#define __sanitizer_syscall_post_compat_43_lstat43(res, path, ub)              \ +  __sanitizer_syscall_post_impl_compat_43_lstat43(res, (long long)(path),      \ +                                                  (long long)(ub)) +#define __sanitizer_syscall_pre_dup(fd)                                        \ +  __sanitizer_syscall_pre_impl_dup((long long)(fd)) +#define __sanitizer_syscall_post_dup(res, fd)                                  \ +  __sanitizer_syscall_post_impl_dup(res, (long long)(fd)) +#define __sanitizer_syscall_pre_pipe() __sanitizer_syscall_pre_impl_pipe() +#define __sanitizer_syscall_post_pipe(res)                                     \ +  __sanitizer_syscall_post_impl_pipe(res) +#define __sanitizer_syscall_pre_getegid() __sanitizer_syscall_pre_impl_getegid() +#define __sanitizer_syscall_post_getegid(res)                                  \ +  __sanitizer_syscall_post_impl_getegid(res) +#define __sanitizer_syscall_pre_profil(samples, size, offset, scale)           \ +  __sanitizer_syscall_pre_impl_profil((long long)(samples), (long long)(size), \ +                                      (long long)(offset), (long long)(scale)) +#define __sanitizer_syscall_post_profil(res, samples, size, offset, scale)     \ +  __sanitizer_syscall_post_impl_profil(res, (long long)(samples),              \ +                                       (long long)(size), (long long)(offset), \ +                                       (long long)(scale)) +#define __sanitizer_syscall_pre_ktrace(fname, ops, facs, pid)                  \ +  __sanitizer_syscall_pre_impl_ktrace((long long)(fname), (long long)(ops),    \ +                                      (long long)(facs), (long long)(pid)) +#define __sanitizer_syscall_post_ktrace(res, fname, ops, facs, pid)            \ +  __sanitizer_syscall_post_impl_ktrace(res, (long long)(fname),                \ +                                       (long long)(ops), (long long)(facs),    \ +                                       (long long)(pid)) +#define __sanitizer_syscall_pre_compat_13_sigaction13(signum, nsa, osa)        \ +  __sanitizer_syscall_pre_impl_compat_13_sigaction13(                          \ +      (long long)(signum), (long long)(nsa), (long long)(osa)) +#define __sanitizer_syscall_post_compat_13_sigaction13(res, signum, nsa, osa)  \ +  __sanitizer_syscall_post_impl_compat_13_sigaction13(                         \ +      res, (long long)(signum), (long long)(nsa), (long long)(osa)) +#define __sanitizer_syscall_pre_getgid() __sanitizer_syscall_pre_impl_getgid() +#define __sanitizer_syscall_post_getgid(res)                                   \ +  __sanitizer_syscall_post_impl_getgid(res) +#define __sanitizer_syscall_pre_compat_13_sigprocmask13(how, mask)             \ +  __sanitizer_syscall_pre_impl_compat_13_sigprocmask13((long long)(how),       \ +                                                       (long long)(mask)) +#define __sanitizer_syscall_post_compat_13_sigprocmask13(res, how, mask)       \ +  __sanitizer_syscall_post_impl_compat_13_sigprocmask13(res, (long long)(how), \ +                                                        (long long)(mask)) +#define __sanitizer_syscall_pre___getlogin(namebuf, namelen)                   \ +  __sanitizer_syscall_pre_impl___getlogin((long long)(namebuf),                \ +                                          (long long)(namelen)) +#define __sanitizer_syscall_post___getlogin(res, namebuf, namelen)             \ +  __sanitizer_syscall_post_impl___getlogin(res, (long long)(namebuf),          \ +                                           (long long)(namelen)) +#define __sanitizer_syscall_pre___setlogin(namebuf)                            \ +  __sanitizer_syscall_pre_impl___setlogin((long long)(namebuf)) +#define __sanitizer_syscall_post___setlogin(res, namebuf)                      \ +  __sanitizer_syscall_post_impl___setlogin(res, (long long)(namebuf)) +#define __sanitizer_syscall_pre_acct(path)                                     \ +  __sanitizer_syscall_pre_impl_acct((long long)(path)) +#define __sanitizer_syscall_post_acct(res, path)                               \ +  __sanitizer_syscall_post_impl_acct(res, (long long)(path)) +#define __sanitizer_syscall_pre_compat_13_sigpending13()                       \ +  __sanitizer_syscall_pre_impl_compat_13_sigpending13() +#define __sanitizer_syscall_post_compat_13_sigpending13(res)                   \ +  __sanitizer_syscall_post_impl_compat_13_sigpending13(res) +#define __sanitizer_syscall_pre_compat_13_sigaltstack13(nss, oss)              \ +  __sanitizer_syscall_pre_impl_compat_13_sigaltstack13((long long)(nss),       \ +                                                       (long long)(oss)) +#define __sanitizer_syscall_post_compat_13_sigaltstack13(res, nss, oss)        \ +  __sanitizer_syscall_post_impl_compat_13_sigaltstack13(res, (long long)(nss), \ +                                                        (long long)(oss)) +#define __sanitizer_syscall_pre_ioctl(fd, com, data)                           \ +  __sanitizer_syscall_pre_impl_ioctl((long long)(fd), (long long)(com),        \ +                                     (long long)(data)) +#define __sanitizer_syscall_post_ioctl(res, fd, com, data)                     \ +  __sanitizer_syscall_post_impl_ioctl(res, (long long)(fd), (long long)(com),  \ +                                      (long long)(data)) +#define __sanitizer_syscall_pre_compat_12_oreboot(opt)                         \ +  __sanitizer_syscall_pre_impl_compat_12_oreboot((long long)(opt)) +#define __sanitizer_syscall_post_compat_12_oreboot(res, opt)                   \ +  __sanitizer_syscall_post_impl_compat_12_oreboot(res, (long long)(opt)) +#define __sanitizer_syscall_pre_revoke(path)                                   \ +  __sanitizer_syscall_pre_impl_revoke((long long)(path)) +#define __sanitizer_syscall_post_revoke(res, path)                             \ +  __sanitizer_syscall_post_impl_revoke(res, (long long)(path)) +#define __sanitizer_syscall_pre_symlink(path, link)                            \ +  __sanitizer_syscall_pre_impl_symlink((long long)(path), (long long)(link)) +#define __sanitizer_syscall_post_symlink(res, path, link)                      \ +  __sanitizer_syscall_post_impl_symlink(res, (long long)(path),                \ +                                        (long long)(link)) +#define __sanitizer_syscall_pre_readlink(path, buf, count)                     \ +  __sanitizer_syscall_pre_impl_readlink((long long)(path), (long long)(buf),   \ +                                        (long long)(count)) +#define __sanitizer_syscall_post_readlink(res, path, buf, count)               \ +  __sanitizer_syscall_post_impl_readlink(res, (long long)(path),               \ +                                         (long long)(buf), (long long)(count)) +#define __sanitizer_syscall_pre_execve(path, argp, envp)                       \ +  __sanitizer_syscall_pre_impl_execve((long long)(path), (long long)(argp),    \ +                                      (long long)(envp)) +#define __sanitizer_syscall_post_execve(res, path, argp, envp)                 \ +  __sanitizer_syscall_post_impl_execve(res, (long long)(path),                 \ +                                       (long long)(argp), (long long)(envp)) +#define __sanitizer_syscall_pre_umask(newmask)                                 \ +  __sanitizer_syscall_pre_impl_umask((long long)(newmask)) +#define __sanitizer_syscall_post_umask(res, newmask)                           \ +  __sanitizer_syscall_post_impl_umask(res, (long long)(newmask)) +#define __sanitizer_syscall_pre_chroot(path)                                   \ +  __sanitizer_syscall_pre_impl_chroot((long long)(path)) +#define __sanitizer_syscall_post_chroot(res, path)                             \ +  __sanitizer_syscall_post_impl_chroot(res, (long long)(path)) +#define __sanitizer_syscall_pre_compat_43_fstat43(fd, sb)                      \ +  __sanitizer_syscall_pre_impl_compat_43_fstat43((long long)(fd),              \ +                                                 (long long)(sb)) +#define __sanitizer_syscall_post_compat_43_fstat43(res, fd, sb)                \ +  __sanitizer_syscall_post_impl_compat_43_fstat43(res, (long long)(fd),        \ +                                                  (long long)(sb)) +#define __sanitizer_syscall_pre_compat_43_ogetkerninfo(op, where, size, arg)   \ +  __sanitizer_syscall_pre_impl_compat_43_ogetkerninfo(                         \ +      (long long)(op), (long long)(where), (long long)(size),                  \ +      (long long)(arg)) +#define __sanitizer_syscall_post_compat_43_ogetkerninfo(res, op, where, size,  \ +                                                        arg)                   \ +  __sanitizer_syscall_post_impl_compat_43_ogetkerninfo(                        \ +      res, (long long)(op), (long long)(where), (long long)(size),             \ +      (long long)(arg)) +#define __sanitizer_syscall_pre_compat_43_ogetpagesize()                       \ +  __sanitizer_syscall_pre_impl_compat_43_ogetpagesize() +#define __sanitizer_syscall_post_compat_43_ogetpagesize(res)                   \ +  __sanitizer_syscall_post_impl_compat_43_ogetpagesize(res) +#define __sanitizer_syscall_pre_compat_12_msync(addr, len)                     \ +  __sanitizer_syscall_pre_impl_compat_12_msync((long long)(addr),              \ +                                               (long long)(len)) +#define __sanitizer_syscall_post_compat_12_msync(res, addr, len)               \ +  __sanitizer_syscall_post_impl_compat_12_msync(res, (long long)(addr),        \ +                                                (long long)(len)) +#define __sanitizer_syscall_pre_vfork() __sanitizer_syscall_pre_impl_vfork() +#define __sanitizer_syscall_post_vfork(res)                                    \ +  __sanitizer_syscall_post_impl_vfork(res) +/* syscall 67 has been skipped */ +/* syscall 68 has been skipped */ +/* syscall 69 has been skipped */ +/* syscall 70 has been skipped */ +#define __sanitizer_syscall_pre_compat_43_ommap(addr, len, prot, flags, fd,    \ +                                                pos)                           \ +  __sanitizer_syscall_pre_impl_compat_43_ommap(                                \ +      (long long)(addr), (long long)(len), (long long)(prot),                  \ +      (long long)(flags), (long long)(fd), (long long)(pos)) +#define __sanitizer_syscall_post_compat_43_ommap(res, addr, len, prot, flags,  \ +                                                 fd, pos)                      \ +  __sanitizer_syscall_post_impl_compat_43_ommap(                               \ +      res, (long long)(addr), (long long)(len), (long long)(prot),             \ +      (long long)(flags), (long long)(fd), (long long)(pos)) +#define __sanitizer_syscall_pre_vadvise(anom)                                  \ +  __sanitizer_syscall_pre_impl_vadvise((long long)(anom)) +#define __sanitizer_syscall_post_vadvise(res, anom)                            \ +  __sanitizer_syscall_post_impl_vadvise(res, (long long)(anom)) +#define __sanitizer_syscall_pre_munmap(addr, len)                              \ +  __sanitizer_syscall_pre_impl_munmap((long long)(addr), (long long)(len)) +#define __sanitizer_syscall_post_munmap(res, addr, len)                        \ +  __sanitizer_syscall_post_impl_munmap(res, (long long)(addr), (long long)(len)) +#define __sanitizer_syscall_pre_mprotect(addr, len, prot)                      \ +  __sanitizer_syscall_pre_impl_mprotect((long long)(addr), (long long)(len),   \ +                                        (long long)(prot)) +#define __sanitizer_syscall_post_mprotect(res, addr, len, prot)                \ +  __sanitizer_syscall_post_impl_mprotect(res, (long long)(addr),               \ +                                         (long long)(len), (long long)(prot)) +#define __sanitizer_syscall_pre_madvise(addr, len, behav)                      \ +  __sanitizer_syscall_pre_impl_madvise((long long)(addr), (long long)(len),    \ +                                       (long long)(behav)) +#define __sanitizer_syscall_post_madvise(res, addr, len, behav)                \ +  __sanitizer_syscall_post_impl_madvise(res, (long long)(addr),                \ +                                        (long long)(len), (long long)(behav)) +/* syscall 76 has been skipped */ +/* syscall 77 has been skipped */ +#define __sanitizer_syscall_pre_mincore(addr, len, vec)                        \ +  __sanitizer_syscall_pre_impl_mincore((long long)(addr), (long long)(len),    \ +                                       (long long)(vec)) +#define __sanitizer_syscall_post_mincore(res, addr, len, vec)                  \ +  __sanitizer_syscall_post_impl_mincore(res, (long long)(addr),                \ +                                        (long long)(len), (long long)(vec)) +#define __sanitizer_syscall_pre_getgroups(gidsetsize, gidset)                  \ +  __sanitizer_syscall_pre_impl_getgroups((long long)(gidsetsize),              \ +                                         (long long)(gidset)) +#define __sanitizer_syscall_post_getgroups(res, gidsetsize, gidset)            \ +  __sanitizer_syscall_post_impl_getgroups(res, (long long)(gidsetsize),        \ +                                          (long long)(gidset)) +#define __sanitizer_syscall_pre_setgroups(gidsetsize, gidset)                  \ +  __sanitizer_syscall_pre_impl_setgroups((long long)(gidsetsize),              \ +                                         (long long)(gidset)) +#define __sanitizer_syscall_post_setgroups(res, gidsetsize, gidset)            \ +  __sanitizer_syscall_post_impl_setgroups(res, (long long)(gidsetsize),        \ +                                          (long long)(gidset)) +#define __sanitizer_syscall_pre_getpgrp() __sanitizer_syscall_pre_impl_getpgrp() +#define __sanitizer_syscall_post_getpgrp(res)                                  \ +  __sanitizer_syscall_post_impl_getpgrp(res) +#define __sanitizer_syscall_pre_setpgid(pid, pgid)                             \ +  __sanitizer_syscall_pre_impl_setpgid((long long)(pid), (long long)(pgid)) +#define __sanitizer_syscall_post_setpgid(res, pid, pgid)                       \ +  __sanitizer_syscall_post_impl_setpgid(res, (long long)(pid),                 \ +                                        (long long)(pgid)) +#define __sanitizer_syscall_pre_compat_50_setitimer(which, itv, oitv)          \ +  __sanitizer_syscall_pre_impl_compat_50_setitimer(                            \ +      (long long)(which), (long long)(itv), (long long)(oitv)) +#define __sanitizer_syscall_post_compat_50_setitimer(res, which, itv, oitv)    \ +  __sanitizer_syscall_post_impl_compat_50_setitimer(                           \ +      res, (long long)(which), (long long)(itv), (long long)(oitv)) +#define __sanitizer_syscall_pre_compat_43_owait()                              \ +  __sanitizer_syscall_pre_impl_compat_43_owait() +#define __sanitizer_syscall_post_compat_43_owait(res)                          \ +  __sanitizer_syscall_post_impl_compat_43_owait(res) +#define __sanitizer_syscall_pre_compat_12_oswapon(name)                        \ +  __sanitizer_syscall_pre_impl_compat_12_oswapon((long long)(name)) +#define __sanitizer_syscall_post_compat_12_oswapon(res, name)                  \ +  __sanitizer_syscall_post_impl_compat_12_oswapon(res, (long long)(name)) +#define __sanitizer_syscall_pre_compat_50_getitimer(which, itv)                \ +  __sanitizer_syscall_pre_impl_compat_50_getitimer((long long)(which),         \ +                                                   (long long)(itv)) +#define __sanitizer_syscall_post_compat_50_getitimer(res, which, itv)          \ +  __sanitizer_syscall_post_impl_compat_50_getitimer(res, (long long)(which),   \ +                                                    (long long)(itv)) +#define __sanitizer_syscall_pre_compat_43_ogethostname(hostname, len)          \ +  __sanitizer_syscall_pre_impl_compat_43_ogethostname((long long)(hostname),   \ +                                                      (long long)(len)) +#define __sanitizer_syscall_post_compat_43_ogethostname(res, hostname, len)    \ +  __sanitizer_syscall_post_impl_compat_43_ogethostname(                        \ +      res, (long long)(hostname), (long long)(len)) +#define __sanitizer_syscall_pre_compat_43_osethostname(hostname, len)          \ +  __sanitizer_syscall_pre_impl_compat_43_osethostname((long long)(hostname),   \ +                                                      (long long)(len)) +#define __sanitizer_syscall_post_compat_43_osethostname(res, hostname, len)    \ +  __sanitizer_syscall_post_impl_compat_43_osethostname(                        \ +      res, (long long)(hostname), (long long)(len)) +#define __sanitizer_syscall_pre_compat_43_ogetdtablesize()                     \ +  __sanitizer_syscall_pre_impl_compat_43_ogetdtablesize() +#define __sanitizer_syscall_post_compat_43_ogetdtablesize(res)                 \ +  __sanitizer_syscall_post_impl_compat_43_ogetdtablesize(res) +#define __sanitizer_syscall_pre_dup2(from, to)                                 \ +  __sanitizer_syscall_pre_impl_dup2((long long)(from), (long long)(to)) +#define __sanitizer_syscall_post_dup2(res, from, to)                           \ +  __sanitizer_syscall_post_impl_dup2(res, (long long)(from), (long long)(to)) +/* syscall 91 has been skipped */ +#define __sanitizer_syscall_pre_fcntl(fd, cmd, arg)                            \ +  __sanitizer_syscall_pre_impl_fcntl((long long)(fd), (long long)(cmd),        \ +                                     (long long)(arg)) +#define __sanitizer_syscall_post_fcntl(res, fd, cmd, arg)                      \ +  __sanitizer_syscall_post_impl_fcntl(res, (long long)(fd), (long long)(cmd),  \ +                                      (long long)(arg)) +#define __sanitizer_syscall_pre_compat_50_select(nd, in, ou, ex, tv)           \ +  __sanitizer_syscall_pre_impl_compat_50_select(                               \ +      (long long)(nd), (long long)(in), (long long)(ou), (long long)(ex),      \ +      (long long)(tv)) +#define __sanitizer_syscall_post_compat_50_select(res, nd, in, ou, ex, tv)     \ +  __sanitizer_syscall_post_impl_compat_50_select(                              \ +      res, (long long)(nd), (long long)(in), (long long)(ou), (long long)(ex), \ +      (long long)(tv)) +/* syscall 94 has been skipped */ +#define __sanitizer_syscall_pre_fsync(fd)                                      \ +  __sanitizer_syscall_pre_impl_fsync((long long)(fd)) +#define __sanitizer_syscall_post_fsync(res, fd)                                \ +  __sanitizer_syscall_post_impl_fsync(res, (long long)(fd)) +#define __sanitizer_syscall_pre_setpriority(which, who, prio)                  \ +  __sanitizer_syscall_pre_impl_setpriority(                                    \ +      (long long)(which), (long long)(who), (long long)(prio)) +#define __sanitizer_syscall_post_setpriority(res, which, who, prio)            \ +  __sanitizer_syscall_post_impl_setpriority(                                   \ +      res, (long long)(which), (long long)(who), (long long)(prio)) +#define __sanitizer_syscall_pre_compat_30_socket(domain, type, protocol)       \ +  __sanitizer_syscall_pre_impl_compat_30_socket(                               \ +      (long long)(domain), (long long)(type), (long long)(protocol)) +#define __sanitizer_syscall_post_compat_30_socket(res, domain, type, protocol) \ +  __sanitizer_syscall_post_impl_compat_30_socket(                              \ +      res, (long long)(domain), (long long)(type), (long long)(protocol)) +#define __sanitizer_syscall_pre_connect(s, name, namelen)                      \ +  __sanitizer_syscall_pre_impl_connect((long long)(s), (long long)(name),      \ +                                       (long long)(namelen)) +#define __sanitizer_syscall_post_connect(res, s, name, namelen)                \ +  __sanitizer_syscall_post_impl_connect(                                       \ +      res, (long long)(s), (long long)(name), (long long)(namelen)) +#define __sanitizer_syscall_pre_compat_43_oaccept(s, name, anamelen)           \ +  __sanitizer_syscall_pre_impl_compat_43_oaccept(                              \ +      (long long)(s), (long long)(name), (long long)(anamelen)) +#define __sanitizer_syscall_post_compat_43_oaccept(res, s, name, anamelen)     \ +  __sanitizer_syscall_post_impl_compat_43_oaccept(                             \ +      res, (long long)(s), (long long)(name), (long long)(anamelen)) +#define __sanitizer_syscall_pre_getpriority(which, who)                        \ +  __sanitizer_syscall_pre_impl_getpriority((long long)(which), (long long)(who)) +#define __sanitizer_syscall_post_getpriority(res, which, who)                  \ +  __sanitizer_syscall_post_impl_getpriority(res, (long long)(which),           \ +                                            (long long)(who)) +#define __sanitizer_syscall_pre_compat_43_osend(s, buf, len, flags)            \ +  __sanitizer_syscall_pre_impl_compat_43_osend(                                \ +      (long long)(s), (long long)(buf), (long long)(len), (long long)(flags)) +#define __sanitizer_syscall_post_compat_43_osend(res, s, buf, len, flags)      \ +  __sanitizer_syscall_post_impl_compat_43_osend(                               \ +      res, (long long)(s), (long long)(buf), (long long)(len),                 \ +      (long long)(flags)) +#define __sanitizer_syscall_pre_compat_43_orecv(s, buf, len, flags)            \ +  __sanitizer_syscall_pre_impl_compat_43_orecv(                                \ +      (long long)(s), (long long)(buf), (long long)(len), (long long)(flags)) +#define __sanitizer_syscall_post_compat_43_orecv(res, s, buf, len, flags)      \ +  __sanitizer_syscall_post_impl_compat_43_orecv(                               \ +      res, (long long)(s), (long long)(buf), (long long)(len),                 \ +      (long long)(flags)) +#define __sanitizer_syscall_pre_compat_13_sigreturn13(sigcntxp)                \ +  __sanitizer_syscall_pre_impl_compat_13_sigreturn13((long long)(sigcntxp)) +#define __sanitizer_syscall_post_compat_13_sigreturn13(res, sigcntxp)          \ +  __sanitizer_syscall_post_impl_compat_13_sigreturn13(res,                     \ +                                                      (long long)(sigcntxp)) +#define __sanitizer_syscall_pre_bind(s, name, namelen)                         \ +  __sanitizer_syscall_pre_impl_bind((long long)(s), (long long)(name),         \ +                                    (long long)(namelen)) +#define __sanitizer_syscall_post_bind(res, s, name, namelen)                   \ +  __sanitizer_syscall_post_impl_bind(res, (long long)(s), (long long)(name),   \ +                                     (long long)(namelen)) +#define __sanitizer_syscall_pre_setsockopt(s, level, name, val, valsize)       \ +  __sanitizer_syscall_pre_impl_setsockopt((long long)(s), (long long)(level),  \ +                                          (long long)(name), (long long)(val), \ +                                          (long long)(valsize)) +#define __sanitizer_syscall_post_setsockopt(res, s, level, name, val, valsize) \ +  __sanitizer_syscall_post_impl_setsockopt(                                    \ +      res, (long long)(s), (long long)(level), (long long)(name),              \ +      (long long)(val), (long long)(valsize)) +#define __sanitizer_syscall_pre_listen(s, backlog)                             \ +  __sanitizer_syscall_pre_impl_listen((long long)(s), (long long)(backlog)) +#define __sanitizer_syscall_post_listen(res, s, backlog)                       \ +  __sanitizer_syscall_post_impl_listen(res, (long long)(s),                    \ +                                       (long long)(backlog)) +/* syscall 107 has been skipped */ +#define __sanitizer_syscall_pre_compat_43_osigvec(signum, nsv, osv)            \ +  __sanitizer_syscall_pre_impl_compat_43_osigvec(                              \ +      (long long)(signum), (long long)(nsv), (long long)(osv)) +#define __sanitizer_syscall_post_compat_43_osigvec(res, signum, nsv, osv)      \ +  __sanitizer_syscall_post_impl_compat_43_osigvec(                             \ +      res, (long long)(signum), (long long)(nsv), (long long)(osv)) +#define __sanitizer_syscall_pre_compat_43_osigblock(mask)                      \ +  __sanitizer_syscall_pre_impl_compat_43_osigblock((long long)(mask)) +#define __sanitizer_syscall_post_compat_43_osigblock(res, mask)                \ +  __sanitizer_syscall_post_impl_compat_43_osigblock(res, (long long)(mask)) +#define __sanitizer_syscall_pre_compat_43_osigsetmask(mask)                    \ +  __sanitizer_syscall_pre_impl_compat_43_osigsetmask((long long)(mask)) +#define __sanitizer_syscall_post_compat_43_osigsetmask(res, mask)              \ +  __sanitizer_syscall_post_impl_compat_43_osigsetmask(res, (long long)(mask)) +#define __sanitizer_syscall_pre_compat_13_sigsuspend13(mask)                   \ +  __sanitizer_syscall_pre_impl_compat_13_sigsuspend13((long long)(mask)) +#define __sanitizer_syscall_post_compat_13_sigsuspend13(res, mask)             \ +  __sanitizer_syscall_post_impl_compat_13_sigsuspend13(res, (long long)(mask)) +#define __sanitizer_syscall_pre_compat_43_osigstack(nss, oss)                  \ +  __sanitizer_syscall_pre_impl_compat_43_osigstack((long long)(nss),           \ +                                                   (long long)(oss)) +#define __sanitizer_syscall_post_compat_43_osigstack(res, nss, oss)            \ +  __sanitizer_syscall_post_impl_compat_43_osigstack(res, (long long)(nss),     \ +                                                    (long long)(oss)) +#define __sanitizer_syscall_pre_compat_43_orecvmsg(s, msg, flags)              \ +  __sanitizer_syscall_pre_impl_compat_43_orecvmsg(                             \ +      (long long)(s), (long long)(msg), (long long)(flags)) +#define __sanitizer_syscall_post_compat_43_orecvmsg(res, s, msg, flags)        \ +  __sanitizer_syscall_post_impl_compat_43_orecvmsg(                            \ +      res, (long long)(s), (long long)(msg), (long long)(flags)) +#define __sanitizer_syscall_pre_compat_43_osendmsg(s, msg, flags)              \ +  __sanitizer_syscall_pre_impl_compat_43_osendmsg(                             \ +      (long long)(s), (long long)(msg), (long long)(flags)) +#define __sanitizer_syscall_post_compat_43_osendmsg(res, s, msg, flags)        \ +  __sanitizer_syscall_post_impl_compat_43_osendmsg(                            \ +      res, (long long)(s), (long long)(msg), (long long)(flags)) +/* syscall 115 has been skipped */ +#define __sanitizer_syscall_pre_compat_50_gettimeofday(tp, tzp)                \ +  __sanitizer_syscall_pre_impl_compat_50_gettimeofday((long long)(tp),         \ +                                                      (long long)(tzp)) +#define __sanitizer_syscall_post_compat_50_gettimeofday(res, tp, tzp)          \ +  __sanitizer_syscall_post_impl_compat_50_gettimeofday(res, (long long)(tp),   \ +                                                       (long long)(tzp)) +#define __sanitizer_syscall_pre_compat_50_getrusage(who, rusage)               \ +  __sanitizer_syscall_pre_impl_compat_50_getrusage((long long)(who),           \ +                                                   (long long)(rusage)) +#define __sanitizer_syscall_post_compat_50_getrusage(res, who, rusage)         \ +  __sanitizer_syscall_post_impl_compat_50_getrusage(res, (long long)(who),     \ +                                                    (long long)(rusage)) +#define __sanitizer_syscall_pre_getsockopt(s, level, name, val, avalsize)      \ +  __sanitizer_syscall_pre_impl_getsockopt((long long)(s), (long long)(level),  \ +                                          (long long)(name), (long long)(val), \ +                                          (long long)(avalsize)) +#define __sanitizer_syscall_post_getsockopt(res, s, level, name, val,          \ +                                            avalsize)                          \ +  __sanitizer_syscall_post_impl_getsockopt(                                    \ +      res, (long long)(s), (long long)(level), (long long)(name),              \ +      (long long)(val), (long long)(avalsize)) +/* syscall 119 has been skipped */ +#define __sanitizer_syscall_pre_readv(fd, iovp, iovcnt)                        \ +  __sanitizer_syscall_pre_impl_readv((long long)(fd), (long long)(iovp),       \ +                                     (long long)(iovcnt)) +#define __sanitizer_syscall_post_readv(res, fd, iovp, iovcnt)                  \ +  __sanitizer_syscall_post_impl_readv(res, (long long)(fd), (long long)(iovp), \ +                                      (long long)(iovcnt)) +#define __sanitizer_syscall_pre_writev(fd, iovp, iovcnt)                       \ +  __sanitizer_syscall_pre_impl_writev((long long)(fd), (long long)(iovp),      \ +                                      (long long)(iovcnt)) +#define __sanitizer_syscall_post_writev(res, fd, iovp, iovcnt)                 \ +  __sanitizer_syscall_post_impl_writev(res, (long long)(fd),                   \ +                                       (long long)(iovp), (long long)(iovcnt)) +#define __sanitizer_syscall_pre_compat_50_settimeofday(tv, tzp)                \ +  __sanitizer_syscall_pre_impl_compat_50_settimeofday((long long)(tv),         \ +                                                      (long long)(tzp)) +#define __sanitizer_syscall_post_compat_50_settimeofday(res, tv, tzp)          \ +  __sanitizer_syscall_post_impl_compat_50_settimeofday(res, (long long)(tv),   \ +                                                       (long long)(tzp)) +#define __sanitizer_syscall_pre_fchown(fd, uid, gid)                           \ +  __sanitizer_syscall_pre_impl_fchown((long long)(fd), (long long)(uid),       \ +                                      (long long)(gid)) +#define __sanitizer_syscall_post_fchown(res, fd, uid, gid)                     \ +  __sanitizer_syscall_post_impl_fchown(res, (long long)(fd), (long long)(uid), \ +                                       (long long)(gid)) +#define __sanitizer_syscall_pre_fchmod(fd, mode)                               \ +  __sanitizer_syscall_pre_impl_fchmod((long long)(fd), (long long)(mode)) +#define __sanitizer_syscall_post_fchmod(res, fd, mode)                         \ +  __sanitizer_syscall_post_impl_fchmod(res, (long long)(fd), (long long)(mode)) +#define __sanitizer_syscall_pre_compat_43_orecvfrom(s, buf, len, flags, from,  \ +                                                    fromlenaddr)               \ +  __sanitizer_syscall_pre_impl_compat_43_orecvfrom(                            \ +      (long long)(s), (long long)(buf), (long long)(len), (long long)(flags),  \ +      (long long)(from), (long long)(fromlenaddr)) +#define __sanitizer_syscall_post_compat_43_orecvfrom(res, s, buf, len, flags,  \ +                                                     from, fromlenaddr)        \ +  __sanitizer_syscall_post_impl_compat_43_orecvfrom(                           \ +      res, (long long)(s), (long long)(buf), (long long)(len),                 \ +      (long long)(flags), (long long)(from), (long long)(fromlenaddr)) +#define __sanitizer_syscall_pre_setreuid(ruid, euid)                           \ +  __sanitizer_syscall_pre_impl_setreuid((long long)(ruid), (long long)(euid)) +#define __sanitizer_syscall_post_setreuid(res, ruid, euid)                     \ +  __sanitizer_syscall_post_impl_setreuid(res, (long long)(ruid),               \ +                                         (long long)(euid)) +#define __sanitizer_syscall_pre_setregid(rgid, egid)                           \ +  __sanitizer_syscall_pre_impl_setregid((long long)(rgid), (long long)(egid)) +#define __sanitizer_syscall_post_setregid(res, rgid, egid)                     \ +  __sanitizer_syscall_post_impl_setregid(res, (long long)(rgid),               \ +                                         (long long)(egid)) +#define __sanitizer_syscall_pre_rename(from, to)                               \ +  __sanitizer_syscall_pre_impl_rename((long long)(from), (long long)(to)) +#define __sanitizer_syscall_post_rename(res, from, to)                         \ +  __sanitizer_syscall_post_impl_rename(res, (long long)(from), (long long)(to)) +#define __sanitizer_syscall_pre_compat_43_otruncate(path, length)              \ +  __sanitizer_syscall_pre_impl_compat_43_otruncate((long long)(path),          \ +                                                   (long long)(length)) +#define __sanitizer_syscall_post_compat_43_otruncate(res, path, length)        \ +  __sanitizer_syscall_post_impl_compat_43_otruncate(res, (long long)(path),    \ +                                                    (long long)(length)) +#define __sanitizer_syscall_pre_compat_43_oftruncate(fd, length)               \ +  __sanitizer_syscall_pre_impl_compat_43_oftruncate((long long)(fd),           \ +                                                    (long long)(length)) +#define __sanitizer_syscall_post_compat_43_oftruncate(res, fd, length)         \ +  __sanitizer_syscall_post_impl_compat_43_oftruncate(res, (long long)(fd),     \ +                                                     (long long)(length)) +#define __sanitizer_syscall_pre_flock(fd, how)                                 \ +  __sanitizer_syscall_pre_impl_flock((long long)(fd), (long long)(how)) +#define __sanitizer_syscall_post_flock(res, fd, how)                           \ +  __sanitizer_syscall_post_impl_flock(res, (long long)(fd), (long long)(how)) +#define __sanitizer_syscall_pre_mkfifo(path, mode)                             \ +  __sanitizer_syscall_pre_impl_mkfifo((long long)(path), (long long)(mode)) +#define __sanitizer_syscall_post_mkfifo(res, path, mode)                       \ +  __sanitizer_syscall_post_impl_mkfifo(res, (long long)(path),                 \ +                                       (long long)(mode)) +#define __sanitizer_syscall_pre_sendto(s, buf, len, flags, to, tolen)          \ +  __sanitizer_syscall_pre_impl_sendto((long long)(s), (long long)(buf),        \ +                                      (long long)(len), (long long)(flags),    \ +                                      (long long)(to), (long long)(tolen)) +#define __sanitizer_syscall_post_sendto(res, s, buf, len, flags, to, tolen)    \ +  __sanitizer_syscall_post_impl_sendto(res, (long long)(s), (long long)(buf),  \ +                                       (long long)(len), (long long)(flags),   \ +                                       (long long)(to), (long long)(tolen)) +#define __sanitizer_syscall_pre_shutdown(s, how)                               \ +  __sanitizer_syscall_pre_impl_shutdown((long long)(s), (long long)(how)) +#define __sanitizer_syscall_post_shutdown(res, s, how)                         \ +  __sanitizer_syscall_post_impl_shutdown(res, (long long)(s), (long long)(how)) +#define __sanitizer_syscall_pre_socketpair(domain, type, protocol, rsv)        \ +  __sanitizer_syscall_pre_impl_socketpair(                                     \ +      (long long)(domain), (long long)(type), (long long)(protocol),           \ +      (long long)(rsv)) +#define __sanitizer_syscall_post_socketpair(res, domain, type, protocol, rsv)  \ +  __sanitizer_syscall_post_impl_socketpair(                                    \ +      res, (long long)(domain), (long long)(type), (long long)(protocol),      \ +      (long long)(rsv)) +#define __sanitizer_syscall_pre_mkdir(path, mode)                              \ +  __sanitizer_syscall_pre_impl_mkdir((long long)(path), (long long)(mode)) +#define __sanitizer_syscall_post_mkdir(res, path, mode)                        \ +  __sanitizer_syscall_post_impl_mkdir(res, (long long)(path), (long long)(mode)) +#define __sanitizer_syscall_pre_rmdir(path)                                    \ +  __sanitizer_syscall_pre_impl_rmdir((long long)(path)) +#define __sanitizer_syscall_post_rmdir(res, path)                              \ +  __sanitizer_syscall_post_impl_rmdir(res, (long long)(path)) +#define __sanitizer_syscall_pre_compat_50_utimes(path, tptr)                   \ +  __sanitizer_syscall_pre_impl_compat_50_utimes((long long)(path),             \ +                                                (long long)(tptr)) +#define __sanitizer_syscall_post_compat_50_utimes(res, path, tptr)             \ +  __sanitizer_syscall_post_impl_compat_50_utimes(res, (long long)(path),       \ +                                                 (long long)(tptr)) +/* syscall 139 has been skipped */ +#define __sanitizer_syscall_pre_compat_50_adjtime(delta, olddelta)             \ +  __sanitizer_syscall_pre_impl_compat_50_adjtime((long long)(delta),           \ +                                                 (long long)(olddelta)) +#define __sanitizer_syscall_post_compat_50_adjtime(res, delta, olddelta)       \ +  __sanitizer_syscall_post_impl_compat_50_adjtime(res, (long long)(delta),     \ +                                                  (long long)(olddelta)) +#define __sanitizer_syscall_pre_compat_43_ogetpeername(fdes, asa, alen)        \ +  __sanitizer_syscall_pre_impl_compat_43_ogetpeername(                         \ +      (long long)(fdes), (long long)(asa), (long long)(alen)) +#define __sanitizer_syscall_post_compat_43_ogetpeername(res, fdes, asa, alen)  \ +  __sanitizer_syscall_post_impl_compat_43_ogetpeername(                        \ +      res, (long long)(fdes), (long long)(asa), (long long)(alen)) +#define __sanitizer_syscall_pre_compat_43_ogethostid()                         \ +  __sanitizer_syscall_pre_impl_compat_43_ogethostid() +#define __sanitizer_syscall_post_compat_43_ogethostid(res)                     \ +  __sanitizer_syscall_post_impl_compat_43_ogethostid(res) +#define __sanitizer_syscall_pre_compat_43_osethostid(hostid)                   \ +  __sanitizer_syscall_pre_impl_compat_43_osethostid((long long)(hostid)) +#define __sanitizer_syscall_post_compat_43_osethostid(res, hostid)             \ +  __sanitizer_syscall_post_impl_compat_43_osethostid(res, (long long)(hostid)) +#define __sanitizer_syscall_pre_compat_43_ogetrlimit(which, rlp)               \ +  __sanitizer_syscall_pre_impl_compat_43_ogetrlimit((long long)(which),        \ +                                                    (long long)(rlp)) +#define __sanitizer_syscall_post_compat_43_ogetrlimit(res, which, rlp)         \ +  __sanitizer_syscall_post_impl_compat_43_ogetrlimit(res, (long long)(which),  \ +                                                     (long long)(rlp)) +#define __sanitizer_syscall_pre_compat_43_osetrlimit(which, rlp)               \ +  __sanitizer_syscall_pre_impl_compat_43_osetrlimit((long long)(which),        \ +                                                    (long long)(rlp)) +#define __sanitizer_syscall_post_compat_43_osetrlimit(res, which, rlp)         \ +  __sanitizer_syscall_post_impl_compat_43_osetrlimit(res, (long long)(which),  \ +                                                     (long long)(rlp)) +#define __sanitizer_syscall_pre_compat_43_okillpg(pgid, signum)                \ +  __sanitizer_syscall_pre_impl_compat_43_okillpg((long long)(pgid),            \ +                                                 (long long)(signum)) +#define __sanitizer_syscall_post_compat_43_okillpg(res, pgid, signum)          \ +  __sanitizer_syscall_post_impl_compat_43_okillpg(res, (long long)(pgid),      \ +                                                  (long long)(signum)) +#define __sanitizer_syscall_pre_setsid() __sanitizer_syscall_pre_impl_setsid() +#define __sanitizer_syscall_post_setsid(res)                                   \ +  __sanitizer_syscall_post_impl_setsid(res) +#define __sanitizer_syscall_pre_compat_50_quotactl(path, cmd, uid, arg)        \ +  __sanitizer_syscall_pre_impl_compat_50_quotactl(                             \ +      (long long)(path), (long long)(cmd), (long long)(uid), (long long)(arg)) +#define __sanitizer_syscall_post_compat_50_quotactl(res, path, cmd, uid, arg)  \ +  __sanitizer_syscall_post_impl_compat_50_quotactl(                            \ +      res, (long long)(path), (long long)(cmd), (long long)(uid),              \ +      (long long)(arg)) +#define __sanitizer_syscall_pre_compat_43_oquota()                             \ +  __sanitizer_syscall_pre_impl_compat_43_oquota() +#define __sanitizer_syscall_post_compat_43_oquota(res)                         \ +  __sanitizer_syscall_post_impl_compat_43_oquota(res) +#define __sanitizer_syscall_pre_compat_43_ogetsockname(fdec, asa, alen)        \ +  __sanitizer_syscall_pre_impl_compat_43_ogetsockname(                         \ +      (long long)(fdec), (long long)(asa), (long long)(alen)) +#define __sanitizer_syscall_post_compat_43_ogetsockname(res, fdec, asa, alen)  \ +  __sanitizer_syscall_post_impl_compat_43_ogetsockname(                        \ +      res, (long long)(fdec), (long long)(asa), (long long)(alen)) +/* syscall 151 has been skipped */ +/* syscall 152 has been skipped */ +/* syscall 153 has been skipped */ +/* syscall 154 has been skipped */ +#define __sanitizer_syscall_pre_nfssvc(flag, argp)                             \ +  __sanitizer_syscall_pre_impl_nfssvc((long long)(flag), (long long)(argp)) +#define __sanitizer_syscall_post_nfssvc(res, flag, argp)                       \ +  __sanitizer_syscall_post_impl_nfssvc(res, (long long)(flag),                 \ +                                       (long long)(argp)) +#define __sanitizer_syscall_pre_compat_43_ogetdirentries(fd, buf, count,       \ +                                                         basep)                \ +  __sanitizer_syscall_pre_impl_compat_43_ogetdirentries(                       \ +      (long long)(fd), (long long)(buf), (long long)(count),                   \ +      (long long)(basep)) +#define __sanitizer_syscall_post_compat_43_ogetdirentries(res, fd, buf, count, \ +                                                          basep)               \ +  __sanitizer_syscall_post_impl_compat_43_ogetdirentries(                      \ +      res, (long long)(fd), (long long)(buf), (long long)(count),              \ +      (long long)(basep)) +#define __sanitizer_syscall_pre_compat_20_statfs(path, buf)                    \ +  __sanitizer_syscall_pre_impl_compat_20_statfs((long long)(path),             \ +                                                (long long)(buf)) +#define __sanitizer_syscall_post_compat_20_statfs(res, path, buf)              \ +  __sanitizer_syscall_post_impl_compat_20_statfs(res, (long long)(path),       \ +                                                 (long long)(buf)) +#define __sanitizer_syscall_pre_compat_20_fstatfs(fd, buf)                     \ +  __sanitizer_syscall_pre_impl_compat_20_fstatfs((long long)(fd),              \ +                                                 (long long)(buf)) +#define __sanitizer_syscall_post_compat_20_fstatfs(res, fd, buf)               \ +  __sanitizer_syscall_post_impl_compat_20_fstatfs(res, (long long)(fd),        \ +                                                  (long long)(buf)) +/* syscall 159 has been skipped */ +/* syscall 160 has been skipped */ +#define __sanitizer_syscall_pre_compat_30_getfh(fname, fhp)                    \ +  __sanitizer_syscall_pre_impl_compat_30_getfh((long long)(fname),             \ +                                               (long long)(fhp)) +#define __sanitizer_syscall_post_compat_30_getfh(res, fname, fhp)              \ +  __sanitizer_syscall_post_impl_compat_30_getfh(res, (long long)(fname),       \ +                                                (long long)(fhp)) +#define __sanitizer_syscall_pre_compat_09_ogetdomainname(domainname, len)      \ +  __sanitizer_syscall_pre_impl_compat_09_ogetdomainname(                       \ +      (long long)(domainname), (long long)(len)) +#define __sanitizer_syscall_post_compat_09_ogetdomainname(res, domainname,     \ +                                                          len)                 \ +  __sanitizer_syscall_post_impl_compat_09_ogetdomainname(                      \ +      res, (long long)(domainname), (long long)(len)) +#define __sanitizer_syscall_pre_compat_09_osetdomainname(domainname, len)      \ +  __sanitizer_syscall_pre_impl_compat_09_osetdomainname(                       \ +      (long long)(domainname), (long long)(len)) +#define __sanitizer_syscall_post_compat_09_osetdomainname(res, domainname,     \ +                                                          len)                 \ +  __sanitizer_syscall_post_impl_compat_09_osetdomainname(                      \ +      res, (long long)(domainname), (long long)(len)) +#define __sanitizer_syscall_pre_compat_09_ouname(name)                         \ +  __sanitizer_syscall_pre_impl_compat_09_ouname((long long)(name)) +#define __sanitizer_syscall_post_compat_09_ouname(res, name)                   \ +  __sanitizer_syscall_post_impl_compat_09_ouname(res, (long long)(name)) +#define __sanitizer_syscall_pre_sysarch(op, parms)                             \ +  __sanitizer_syscall_pre_impl_sysarch((long long)(op), (long long)(parms)) +#define __sanitizer_syscall_post_sysarch(res, op, parms)                       \ +  __sanitizer_syscall_post_impl_sysarch(res, (long long)(op),                  \ +                                        (long long)(parms)) +/* syscall 166 has been skipped */ +/* syscall 167 has been skipped */ +/* syscall 168 has been skipped */ +#if !defined(_LP64) +#define __sanitizer_syscall_pre_compat_10_osemsys(which, a2, a3, a4, a5)       \ +  __sanitizer_syscall_pre_impl_compat_10_osemsys(                              \ +      (long long)(which), (long long)(a2), (long long)(a3), (long long)(a4),   \ +      (long long)(a5)) +#define __sanitizer_syscall_post_compat_10_osemsys(res, which, a2, a3, a4, a5) \ +  __sanitizer_syscall_post_impl_compat_10_osemsys(                             \ +      res, (long long)(which), (long long)(a2), (long long)(a3),               \ +      (long long)(a4), (long long)(a5)) +#else +/* syscall 169 has been skipped */ +#endif +#if !defined(_LP64) +#define __sanitizer_syscall_pre_compat_10_omsgsys(which, a2, a3, a4, a5, a6)   \ +  __sanitizer_syscall_pre_impl_compat_10_omsgsys(                              \ +      (long long)(which), (long long)(a2), (long long)(a3), (long long)(a4),   \ +      (long long)(a5), (long long)(a6)) +#define __sanitizer_syscall_post_compat_10_omsgsys(res, which, a2, a3, a4, a5, \ +                                                   a6)                         \ +  __sanitizer_syscall_post_impl_compat_10_omsgsys(                             \ +      res, (long long)(which), (long long)(a2), (long long)(a3),               \ +      (long long)(a4), (long long)(a5), (long long)(a6)) +#else +/* syscall 170 has been skipped */ +#endif +#if !defined(_LP64) +#define __sanitizer_syscall_pre_compat_10_oshmsys(which, a2, a3, a4)           \ +  __sanitizer_syscall_pre_impl_compat_10_oshmsys(                              \ +      (long long)(which), (long long)(a2), (long long)(a3), (long long)(a4)) +#define __sanitizer_syscall_post_compat_10_oshmsys(res, which, a2, a3, a4)     \ +  __sanitizer_syscall_post_impl_compat_10_oshmsys(                             \ +      res, (long long)(which), (long long)(a2), (long long)(a3),               \ +      (long long)(a4)) +#else +/* syscall 171 has been skipped */ +#endif +/* syscall 172 has been skipped */ +#define __sanitizer_syscall_pre_pread(fd, buf, nbyte, PAD, offset)             \ +  __sanitizer_syscall_pre_impl_pread((long long)(fd), (long long)(buf),        \ +                                     (long long)(nbyte), (long long)(PAD),     \ +                                     (long long)(offset)) +#define __sanitizer_syscall_post_pread(res, fd, buf, nbyte, PAD, offset)       \ +  __sanitizer_syscall_post_impl_pread(res, (long long)(fd), (long long)(buf),  \ +                                      (long long)(nbyte), (long long)(PAD),    \ +                                      (long long)(offset)) +#define __sanitizer_syscall_pre_pwrite(fd, buf, nbyte, PAD, offset)            \ +  __sanitizer_syscall_pre_impl_pwrite((long long)(fd), (long long)(buf),       \ +                                      (long long)(nbyte), (long long)(PAD),    \ +                                      (long long)(offset)) +#define __sanitizer_syscall_post_pwrite(res, fd, buf, nbyte, PAD, offset)      \ +  __sanitizer_syscall_post_impl_pwrite(res, (long long)(fd), (long long)(buf), \ +                                       (long long)(nbyte), (long long)(PAD),   \ +                                       (long long)(offset)) +#define __sanitizer_syscall_pre_compat_30_ntp_gettime(ntvp)                    \ +  __sanitizer_syscall_pre_impl_compat_30_ntp_gettime((long long)(ntvp)) +#define __sanitizer_syscall_post_compat_30_ntp_gettime(res, ntvp)              \ +  __sanitizer_syscall_post_impl_compat_30_ntp_gettime(res, (long long)(ntvp)) +#if defined(NTP) || !defined(_KERNEL_OPT) +#define __sanitizer_syscall_pre_ntp_adjtime(tp)                                \ +  __sanitizer_syscall_pre_impl_ntp_adjtime((long long)(tp)) +#define __sanitizer_syscall_post_ntp_adjtime(res, tp)                          \ +  __sanitizer_syscall_post_impl_ntp_adjtime(res, (long long)(tp)) +#else +/* syscall 176 has been skipped */ +#endif +/* syscall 177 has been skipped */ +/* syscall 178 has been skipped */ +/* syscall 179 has been skipped */ +/* syscall 180 has been skipped */ +#define __sanitizer_syscall_pre_setgid(gid)                                    \ +  __sanitizer_syscall_pre_impl_setgid((long long)(gid)) +#define __sanitizer_syscall_post_setgid(res, gid)                              \ +  __sanitizer_syscall_post_impl_setgid(res, (long long)(gid)) +#define __sanitizer_syscall_pre_setegid(egid)                                  \ +  __sanitizer_syscall_pre_impl_setegid((long long)(egid)) +#define __sanitizer_syscall_post_setegid(res, egid)                            \ +  __sanitizer_syscall_post_impl_setegid(res, (long long)(egid)) +#define __sanitizer_syscall_pre_seteuid(euid)                                  \ +  __sanitizer_syscall_pre_impl_seteuid((long long)(euid)) +#define __sanitizer_syscall_post_seteuid(res, euid)                            \ +  __sanitizer_syscall_post_impl_seteuid(res, (long long)(euid)) +#define __sanitizer_syscall_pre_lfs_bmapv(fsidp, blkiov, blkcnt)               \ +  __sanitizer_syscall_pre_impl_lfs_bmapv(                                      \ +      (long long)(fsidp), (long long)(blkiov), (long long)(blkcnt)) +#define __sanitizer_syscall_post_lfs_bmapv(res, fsidp, blkiov, blkcnt)         \ +  __sanitizer_syscall_post_impl_lfs_bmapv(                                     \ +      res, (long long)(fsidp), (long long)(blkiov), (long long)(blkcnt)) +#define __sanitizer_syscall_pre_lfs_markv(fsidp, blkiov, blkcnt)               \ +  __sanitizer_syscall_pre_impl_lfs_markv(                                      \ +      (long long)(fsidp), (long long)(blkiov), (long long)(blkcnt)) +#define __sanitizer_syscall_post_lfs_markv(res, fsidp, blkiov, blkcnt)         \ +  __sanitizer_syscall_post_impl_lfs_markv(                                     \ +      res, (long long)(fsidp), (long long)(blkiov), (long long)(blkcnt)) +#define __sanitizer_syscall_pre_lfs_segclean(fsidp, segment)                   \ +  __sanitizer_syscall_pre_impl_lfs_segclean((long long)(fsidp),                \ +                                            (long long)(segment)) +#define __sanitizer_syscall_post_lfs_segclean(res, fsidp, segment)             \ +  __sanitizer_syscall_post_impl_lfs_segclean(res, (long long)(fsidp),          \ +                                             (long long)(segment)) +#define __sanitizer_syscall_pre_compat_50_lfs_segwait(fsidp, tv)               \ +  __sanitizer_syscall_pre_impl_compat_50_lfs_segwait((long long)(fsidp),       \ +                                                     (long long)(tv)) +#define __sanitizer_syscall_post_compat_50_lfs_segwait(res, fsidp, tv)         \ +  __sanitizer_syscall_post_impl_compat_50_lfs_segwait(res, (long long)(fsidp), \ +                                                      (long long)(tv)) +#define __sanitizer_syscall_pre_compat_12_stat12(path, ub)                     \ +  __sanitizer_syscall_pre_impl_compat_12_stat12((long long)(path),             \ +                                                (long long)(ub)) +#define __sanitizer_syscall_post_compat_12_stat12(res, path, ub)               \ +  __sanitizer_syscall_post_impl_compat_12_stat12(res, (long long)(path),       \ +                                                 (long long)(ub)) +#define __sanitizer_syscall_pre_compat_12_fstat12(fd, sb)                      \ +  __sanitizer_syscall_pre_impl_compat_12_fstat12((long long)(fd),              \ +                                                 (long long)(sb)) +#define __sanitizer_syscall_post_compat_12_fstat12(res, fd, sb)                \ +  __sanitizer_syscall_post_impl_compat_12_fstat12(res, (long long)(fd),        \ +                                                  (long long)(sb)) +#define __sanitizer_syscall_pre_compat_12_lstat12(path, ub)                    \ +  __sanitizer_syscall_pre_impl_compat_12_lstat12((long long)(path),            \ +                                                 (long long)(ub)) +#define __sanitizer_syscall_post_compat_12_lstat12(res, path, ub)              \ +  __sanitizer_syscall_post_impl_compat_12_lstat12(res, (long long)(path),      \ +                                                  (long long)(ub)) +#define __sanitizer_syscall_pre_pathconf(path, name)                           \ +  __sanitizer_syscall_pre_impl_pathconf((long long)(path), (long long)(name)) +#define __sanitizer_syscall_post_pathconf(res, path, name)                     \ +  __sanitizer_syscall_post_impl_pathconf(res, (long long)(path),               \ +                                         (long long)(name)) +#define __sanitizer_syscall_pre_fpathconf(fd, name)                            \ +  __sanitizer_syscall_pre_impl_fpathconf((long long)(fd), (long long)(name)) +#define __sanitizer_syscall_post_fpathconf(res, fd, name)                      \ +  __sanitizer_syscall_post_impl_fpathconf(res, (long long)(fd),                \ +                                          (long long)(name)) +/* syscall 193 has been skipped */ +#define __sanitizer_syscall_pre_getrlimit(which, rlp)                          \ +  __sanitizer_syscall_pre_impl_getrlimit((long long)(which), (long long)(rlp)) +#define __sanitizer_syscall_post_getrlimit(res, which, rlp)                    \ +  __sanitizer_syscall_post_impl_getrlimit(res, (long long)(which),             \ +                                          (long long)(rlp)) +#define __sanitizer_syscall_pre_setrlimit(which, rlp)                          \ +  __sanitizer_syscall_pre_impl_setrlimit((long long)(which), (long long)(rlp)) +#define __sanitizer_syscall_post_setrlimit(res, which, rlp)                    \ +  __sanitizer_syscall_post_impl_setrlimit(res, (long long)(which),             \ +                                          (long long)(rlp)) +#define __sanitizer_syscall_pre_compat_12_getdirentries(fd, buf, count, basep) \ +  __sanitizer_syscall_pre_impl_compat_12_getdirentries(                        \ +      (long long)(fd), (long long)(buf), (long long)(count),                   \ +      (long long)(basep)) +#define __sanitizer_syscall_post_compat_12_getdirentries(res, fd, buf, count,  \ +                                                         basep)                \ +  __sanitizer_syscall_post_impl_compat_12_getdirentries(                       \ +      res, (long long)(fd), (long long)(buf), (long long)(count),              \ +      (long long)(basep)) +#define __sanitizer_syscall_pre_mmap(addr, len, prot, flags, fd, PAD, pos)     \ +  __sanitizer_syscall_pre_impl_mmap(                                           \ +      (long long)(addr), (long long)(len), (long long)(prot),                  \ +      (long long)(flags), (long long)(fd), (long long)(PAD), (long long)(pos)) +#define __sanitizer_syscall_post_mmap(res, addr, len, prot, flags, fd, PAD,    \ +                                      pos)                                     \ +  __sanitizer_syscall_post_impl_mmap(                                          \ +      res, (long long)(addr), (long long)(len), (long long)(prot),             \ +      (long long)(flags), (long long)(fd), (long long)(PAD), (long long)(pos)) +#define __sanitizer_syscall_pre___syscall(code, arg0, arg1, arg2, arg3, arg4,  \ +                                          arg5, arg6, arg7)                    \ +  __sanitizer_syscall_pre_impl___syscall(                                      \ +      (long long)(code), (long long)(arg0), (long long)(arg1),                 \ +      (long long)(arg2), (long long)(arg3), (long long)(arg4),                 \ +      (long long)(arg5), (long long)(arg6), (long long)(arg7)) +#define __sanitizer_syscall_post___syscall(res, code, arg0, arg1, arg2, arg3,  \ +                                           arg4, arg5, arg6, arg7)             \ +  __sanitizer_syscall_post_impl___syscall(                                     \ +      res, (long long)(code), (long long)(arg0), (long long)(arg1),            \ +      (long long)(arg2), (long long)(arg3), (long long)(arg4),                 \ +      (long long)(arg5), (long long)(arg6), (long long)(arg7)) +#define __sanitizer_syscall_pre_lseek(fd, PAD, offset, whence)                 \ +  __sanitizer_syscall_pre_impl_lseek((long long)(fd), (long long)(PAD),        \ +                                     (long long)(offset), (long long)(whence)) +#define __sanitizer_syscall_post_lseek(res, fd, PAD, offset, whence)           \ +  __sanitizer_syscall_post_impl_lseek(res, (long long)(fd), (long long)(PAD),  \ +                                      (long long)(offset),                     \ +                                      (long long)(whence)) +#define __sanitizer_syscall_pre_truncate(path, PAD, length)                    \ +  __sanitizer_syscall_pre_impl_truncate((long long)(path), (long long)(PAD),   \ +                                        (long long)(length)) +#define __sanitizer_syscall_post_truncate(res, path, PAD, length)              \ +  __sanitizer_syscall_post_impl_truncate(                                      \ +      res, (long long)(path), (long long)(PAD), (long long)(length)) +#define __sanitizer_syscall_pre_ftruncate(fd, PAD, length)                     \ +  __sanitizer_syscall_pre_impl_ftruncate((long long)(fd), (long long)(PAD),    \ +                                         (long long)(length)) +#define __sanitizer_syscall_post_ftruncate(res, fd, PAD, length)               \ +  __sanitizer_syscall_post_impl_ftruncate(                                     \ +      res, (long long)(fd), (long long)(PAD), (long long)(length)) +#define __sanitizer_syscall_pre___sysctl(name, namelen, oldv, oldlenp, newv,   \ +                                         newlen)                               \ +  __sanitizer_syscall_pre_impl___sysctl(                                       \ +      (long long)(name), (long long)(namelen), (long long)(oldv),              \ +      (long long)(oldlenp), (long long)(newv), (long long)(newlen)) +#define __sanitizer_syscall_post___sysctl(res, name, namelen, oldv, oldlenp,   \ +                                          newv, newlen)                        \ +  __sanitizer_syscall_post_impl___sysctl(                                      \ +      res, (long long)(name), (long long)(namelen), (long long)(oldv),         \ +      (long long)(oldlenp), (long long)(newv), (long long)(newlen)) +#define __sanitizer_syscall_pre_mlock(addr, len)                               \ +  __sanitizer_syscall_pre_impl_mlock((long long)(addr), (long long)(len)) +#define __sanitizer_syscall_post_mlock(res, addr, len)                         \ +  __sanitizer_syscall_post_impl_mlock(res, (long long)(addr), (long long)(len)) +#define __sanitizer_syscall_pre_munlock(addr, len)                             \ +  __sanitizer_syscall_pre_impl_munlock((long long)(addr), (long long)(len)) +#define __sanitizer_syscall_post_munlock(res, addr, len)                       \ +  __sanitizer_syscall_post_impl_munlock(res, (long long)(addr),                \ +                                        (long long)(len)) +#define __sanitizer_syscall_pre_undelete(path)                                 \ +  __sanitizer_syscall_pre_impl_undelete((long long)(path)) +#define __sanitizer_syscall_post_undelete(res, path)                           \ +  __sanitizer_syscall_post_impl_undelete(res, (long long)(path)) +#define __sanitizer_syscall_pre_compat_50_futimes(fd, tptr)                    \ +  __sanitizer_syscall_pre_impl_compat_50_futimes((long long)(fd),              \ +                                                 (long long)(tptr)) +#define __sanitizer_syscall_post_compat_50_futimes(res, fd, tptr)              \ +  __sanitizer_syscall_post_impl_compat_50_futimes(res, (long long)(fd),        \ +                                                  (long long)(tptr)) +#define __sanitizer_syscall_pre_getpgid(pid)                                   \ +  __sanitizer_syscall_pre_impl_getpgid((long long)(pid)) +#define __sanitizer_syscall_post_getpgid(res, pid)                             \ +  __sanitizer_syscall_post_impl_getpgid(res, (long long)(pid)) +#define __sanitizer_syscall_pre_reboot(opt, bootstr)                           \ +  __sanitizer_syscall_pre_impl_reboot((long long)(opt), (long long)(bootstr)) +#define __sanitizer_syscall_post_reboot(res, opt, bootstr)                     \ +  __sanitizer_syscall_post_impl_reboot(res, (long long)(opt),                  \ +                                       (long long)(bootstr)) +#define __sanitizer_syscall_pre_poll(fds, nfds, timeout)                       \ +  __sanitizer_syscall_pre_impl_poll((long long)(fds), (long long)(nfds),       \ +                                    (long long)(timeout)) +#define __sanitizer_syscall_post_poll(res, fds, nfds, timeout)                 \ +  __sanitizer_syscall_post_impl_poll(res, (long long)(fds), (long long)(nfds), \ +                                     (long long)(timeout)) +#define __sanitizer_syscall_pre_afssys(id, a1, a2, a3, a4, a5, a6)             \ +  __sanitizer_syscall_pre_impl_afssys(                                         \ +      (long long)(id), (long long)(a1), (long long)(a2), (long long)(a3),      \ +      (long long)(a4), (long long)(a5), (long long)(a6)) +#define __sanitizer_syscall_post_afssys(res, id, a1, a2, a3, a4, a5, a6)       \ +  __sanitizer_syscall_post_impl_afssys(                                        \ +      res, (long long)(id), (long long)(a1), (long long)(a2), (long long)(a3), \ +      (long long)(a4), (long long)(a5), (long long)(a6)) +/* syscall 211 has been skipped */ +/* syscall 212 has been skipped */ +/* syscall 213 has been skipped */ +/* syscall 214 has been skipped */ +/* syscall 215 has been skipped */ +/* syscall 216 has been skipped */ +/* syscall 217 has been skipped */ +/* syscall 218 has been skipped */ +/* syscall 219 has been skipped */ +#define __sanitizer_syscall_pre_compat_14___semctl(semid, semnum, cmd, arg)    \ +  __sanitizer_syscall_pre_impl_compat_14___semctl(                             \ +      (long long)(semid), (long long)(semnum), (long long)(cmd),               \ +      (long long)(arg)) +#define __sanitizer_syscall_post_compat_14___semctl(res, semid, semnum, cmd,   \ +                                                    arg)                       \ +  __sanitizer_syscall_post_impl_compat_14___semctl(                            \ +      res, (long long)(semid), (long long)(semnum), (long long)(cmd),          \ +      (long long)(arg)) +#define __sanitizer_syscall_pre_semget(key, nsems, semflg)                     \ +  __sanitizer_syscall_pre_impl_semget((long long)(key), (long long)(nsems),    \ +                                      (long long)(semflg)) +#define __sanitizer_syscall_post_semget(res, key, nsems, semflg)               \ +  __sanitizer_syscall_post_impl_semget(                                        \ +      res, (long long)(key), (long long)(nsems), (long long)(semflg)) +#define __sanitizer_syscall_pre_semop(semid, sops, nsops)                      \ +  __sanitizer_syscall_pre_impl_semop((long long)(semid), (long long)(sops),    \ +                                     (long long)(nsops)) +#define __sanitizer_syscall_post_semop(res, semid, sops, nsops)                \ +  __sanitizer_syscall_post_impl_semop(res, (long long)(semid),                 \ +                                      (long long)(sops), (long long)(nsops)) +#define __sanitizer_syscall_pre_semconfig(flag)                                \ +  __sanitizer_syscall_pre_impl_semconfig((long long)(flag)) +#define __sanitizer_syscall_post_semconfig(res, flag)                          \ +  __sanitizer_syscall_post_impl_semconfig(res, (long long)(flag)) +#define __sanitizer_syscall_pre_compat_14_msgctl(msqid, cmd, buf)              \ +  __sanitizer_syscall_pre_impl_compat_14_msgctl(                               \ +      (long long)(msqid), (long long)(cmd), (long long)(buf)) +#define __sanitizer_syscall_post_compat_14_msgctl(res, msqid, cmd, buf)        \ +  __sanitizer_syscall_post_impl_compat_14_msgctl(                              \ +      res, (long long)(msqid), (long long)(cmd), (long long)(buf)) +#define __sanitizer_syscall_pre_msgget(key, msgflg)                            \ +  __sanitizer_syscall_pre_impl_msgget((long long)(key), (long long)(msgflg)) +#define __sanitizer_syscall_post_msgget(res, key, msgflg)                      \ +  __sanitizer_syscall_post_impl_msgget(res, (long long)(key),                  \ +                                       (long long)(msgflg)) +#define __sanitizer_syscall_pre_msgsnd(msqid, msgp, msgsz, msgflg)             \ +  __sanitizer_syscall_pre_impl_msgsnd((long long)(msqid), (long long)(msgp),   \ +                                      (long long)(msgsz), (long long)(msgflg)) +#define __sanitizer_syscall_post_msgsnd(res, msqid, msgp, msgsz, msgflg)       \ +  __sanitizer_syscall_post_impl_msgsnd(res, (long long)(msqid),                \ +                                       (long long)(msgp), (long long)(msgsz),  \ +                                       (long long)(msgflg)) +#define __sanitizer_syscall_pre_msgrcv(msqid, msgp, msgsz, msgtyp, msgflg)     \ +  __sanitizer_syscall_pre_impl_msgrcv((long long)(msqid), (long long)(msgp),   \ +                                      (long long)(msgsz), (long long)(msgtyp), \ +                                      (long long)(msgflg)) +#define __sanitizer_syscall_post_msgrcv(res, msqid, msgp, msgsz, msgtyp,       \ +                                        msgflg)                                \ +  __sanitizer_syscall_post_impl_msgrcv(                                        \ +      res, (long long)(msqid), (long long)(msgp), (long long)(msgsz),          \ +      (long long)(msgtyp), (long long)(msgflg)) +#define __sanitizer_syscall_pre_shmat(shmid, shmaddr, shmflg)                  \ +  __sanitizer_syscall_pre_impl_shmat((long long)(shmid), (long long)(shmaddr), \ +                                     (long long)(shmflg)) +#define __sanitizer_syscall_post_shmat(res, shmid, shmaddr, shmflg)            \ +  __sanitizer_syscall_post_impl_shmat(                                         \ +      res, (long long)(shmid), (long long)(shmaddr), (long long)(shmflg)) +#define __sanitizer_syscall_pre_compat_14_shmctl(shmid, cmd, buf)              \ +  __sanitizer_syscall_pre_impl_compat_14_shmctl(                               \ +      (long long)(shmid), (long long)(cmd), (long long)(buf)) +#define __sanitizer_syscall_post_compat_14_shmctl(res, shmid, cmd, buf)        \ +  __sanitizer_syscall_post_impl_compat_14_shmctl(                              \ +      res, (long long)(shmid), (long long)(cmd), (long long)(buf)) +#define __sanitizer_syscall_pre_shmdt(shmaddr)                                 \ +  __sanitizer_syscall_pre_impl_shmdt((long long)(shmaddr)) +#define __sanitizer_syscall_post_shmdt(res, shmaddr)                           \ +  __sanitizer_syscall_post_impl_shmdt(res, (long long)(shmaddr)) +#define __sanitizer_syscall_pre_shmget(key, size, shmflg)                      \ +  __sanitizer_syscall_pre_impl_shmget((long long)(key), (long long)(size),     \ +                                      (long long)(shmflg)) +#define __sanitizer_syscall_post_shmget(res, key, size, shmflg)                \ +  __sanitizer_syscall_post_impl_shmget(res, (long long)(key),                  \ +                                       (long long)(size), (long long)(shmflg)) +#define __sanitizer_syscall_pre_compat_50_clock_gettime(clock_id, tp)          \ +  __sanitizer_syscall_pre_impl_compat_50_clock_gettime((long long)(clock_id),  \ +                                                       (long long)(tp)) +#define __sanitizer_syscall_post_compat_50_clock_gettime(res, clock_id, tp)    \ +  __sanitizer_syscall_post_impl_compat_50_clock_gettime(                       \ +      res, (long long)(clock_id), (long long)(tp)) +#define __sanitizer_syscall_pre_compat_50_clock_settime(clock_id, tp)          \ +  __sanitizer_syscall_pre_impl_compat_50_clock_settime((long long)(clock_id),  \ +                                                       (long long)(tp)) +#define __sanitizer_syscall_post_compat_50_clock_settime(res, clock_id, tp)    \ +  __sanitizer_syscall_post_impl_compat_50_clock_settime(                       \ +      res, (long long)(clock_id), (long long)(tp)) +#define __sanitizer_syscall_pre_compat_50_clock_getres(clock_id, tp)           \ +  __sanitizer_syscall_pre_impl_compat_50_clock_getres((long long)(clock_id),   \ +                                                      (long long)(tp)) +#define __sanitizer_syscall_post_compat_50_clock_getres(res, clock_id, tp)     \ +  __sanitizer_syscall_post_impl_compat_50_clock_getres(                        \ +      res, (long long)(clock_id), (long long)(tp)) +#define __sanitizer_syscall_pre_timer_create(clock_id, evp, timerid)           \ +  __sanitizer_syscall_pre_impl_timer_create(                                   \ +      (long long)(clock_id), (long long)(evp), (long long)(timerid)) +#define __sanitizer_syscall_post_timer_create(res, clock_id, evp, timerid)     \ +  __sanitizer_syscall_post_impl_timer_create(                                  \ +      res, (long long)(clock_id), (long long)(evp), (long long)(timerid)) +#define __sanitizer_syscall_pre_timer_delete(timerid)                          \ +  __sanitizer_syscall_pre_impl_timer_delete((long long)(timerid)) +#define __sanitizer_syscall_post_timer_delete(res, timerid)                    \ +  __sanitizer_syscall_post_impl_timer_delete(res, (long long)(timerid)) +#define __sanitizer_syscall_pre_compat_50_timer_settime(timerid, flags, value, \ +                                                        ovalue)                \ +  __sanitizer_syscall_pre_impl_compat_50_timer_settime(                        \ +      (long long)(timerid), (long long)(flags), (long long)(value),            \ +      (long long)(ovalue)) +#define __sanitizer_syscall_post_compat_50_timer_settime(res, timerid, flags,  \ +                                                         value, ovalue)        \ +  __sanitizer_syscall_post_impl_compat_50_timer_settime(                       \ +      res, (long long)(timerid), (long long)(flags), (long long)(value),       \ +      (long long)(ovalue)) +#define __sanitizer_syscall_pre_compat_50_timer_gettime(timerid, value)        \ +  __sanitizer_syscall_pre_impl_compat_50_timer_gettime((long long)(timerid),   \ +                                                       (long long)(value)) +#define __sanitizer_syscall_post_compat_50_timer_gettime(res, timerid, value)  \ +  __sanitizer_syscall_post_impl_compat_50_timer_gettime(                       \ +      res, (long long)(timerid), (long long)(value)) +#define __sanitizer_syscall_pre_timer_getoverrun(timerid)                      \ +  __sanitizer_syscall_pre_impl_timer_getoverrun((long long)(timerid)) +#define __sanitizer_syscall_post_timer_getoverrun(res, timerid)                \ +  __sanitizer_syscall_post_impl_timer_getoverrun(res, (long long)(timerid)) +#define __sanitizer_syscall_pre_compat_50_nanosleep(rqtp, rmtp)                \ +  __sanitizer_syscall_pre_impl_compat_50_nanosleep((long long)(rqtp),          \ +                                                   (long long)(rmtp)) +#define __sanitizer_syscall_post_compat_50_nanosleep(res, rqtp, rmtp)          \ +  __sanitizer_syscall_post_impl_compat_50_nanosleep(res, (long long)(rqtp),    \ +                                                    (long long)(rmtp)) +#define __sanitizer_syscall_pre_fdatasync(fd)                                  \ +  __sanitizer_syscall_pre_impl_fdatasync((long long)(fd)) +#define __sanitizer_syscall_post_fdatasync(res, fd)                            \ +  __sanitizer_syscall_post_impl_fdatasync(res, (long long)(fd)) +#define __sanitizer_syscall_pre_mlockall(flags)                                \ +  __sanitizer_syscall_pre_impl_mlockall((long long)(flags)) +#define __sanitizer_syscall_post_mlockall(res, flags)                          \ +  __sanitizer_syscall_post_impl_mlockall(res, (long long)(flags)) +#define __sanitizer_syscall_pre_munlockall()                                   \ +  __sanitizer_syscall_pre_impl_munlockall() +#define __sanitizer_syscall_post_munlockall(res)                               \ +  __sanitizer_syscall_post_impl_munlockall(res) +#define __sanitizer_syscall_pre_compat_50___sigtimedwait(set, info, timeout)   \ +  __sanitizer_syscall_pre_impl_compat_50___sigtimedwait(                       \ +      (long long)(set), (long long)(info), (long long)(timeout)) +#define __sanitizer_syscall_post_compat_50___sigtimedwait(res, set, info,      \ +                                                          timeout)             \ +  __sanitizer_syscall_post_impl_compat_50___sigtimedwait(                      \ +      res, (long long)(set), (long long)(info), (long long)(timeout)) +#define __sanitizer_syscall_pre_sigqueueinfo(pid, info)                        \ +  __sanitizer_syscall_pre_impl_sigqueueinfo((long long)(pid), (long long)(info)) +#define __sanitizer_syscall_post_sigqueueinfo(res, pid, info)                  \ +  __sanitizer_syscall_post_impl_sigqueueinfo(res, (long long)(pid),            \ +                                             (long long)(info)) +#define __sanitizer_syscall_pre_modctl(cmd, arg)                               \ +  __sanitizer_syscall_pre_impl_modctl((long long)(cmd), (long long)(arg)) +#define __sanitizer_syscall_post_modctl(res, cmd, arg)                         \ +  __sanitizer_syscall_post_impl_modctl(res, (long long)(cmd), (long long)(arg)) +#define __sanitizer_syscall_pre__ksem_init(value, idp)                         \ +  __sanitizer_syscall_pre_impl__ksem_init((long long)(value), (long long)(idp)) +#define __sanitizer_syscall_post__ksem_init(res, value, idp)                   \ +  __sanitizer_syscall_post_impl__ksem_init(res, (long long)(value),            \ +                                           (long long)(idp)) +#define __sanitizer_syscall_pre__ksem_open(name, oflag, mode, value, idp)      \ +  __sanitizer_syscall_pre_impl__ksem_open(                                     \ +      (long long)(name), (long long)(oflag), (long long)(mode),                \ +      (long long)(value), (long long)(idp)) +#define __sanitizer_syscall_post__ksem_open(res, name, oflag, mode, value,     \ +                                            idp)                               \ +  __sanitizer_syscall_post_impl__ksem_open(                                    \ +      res, (long long)(name), (long long)(oflag), (long long)(mode),           \ +      (long long)(value), (long long)(idp)) +#define __sanitizer_syscall_pre__ksem_unlink(name)                             \ +  __sanitizer_syscall_pre_impl__ksem_unlink((long long)(name)) +#define __sanitizer_syscall_post__ksem_unlink(res, name)                       \ +  __sanitizer_syscall_post_impl__ksem_unlink(res, (long long)(name)) +#define __sanitizer_syscall_pre__ksem_close(id)                                \ +  __sanitizer_syscall_pre_impl__ksem_close((long long)(id)) +#define __sanitizer_syscall_post__ksem_close(res, id)                          \ +  __sanitizer_syscall_post_impl__ksem_close(res, (long long)(id)) +#define __sanitizer_syscall_pre__ksem_post(id)                                 \ +  __sanitizer_syscall_pre_impl__ksem_post((long long)(id)) +#define __sanitizer_syscall_post__ksem_post(res, id)                           \ +  __sanitizer_syscall_post_impl__ksem_post(res, (long long)(id)) +#define __sanitizer_syscall_pre__ksem_wait(id)                                 \ +  __sanitizer_syscall_pre_impl__ksem_wait((long long)(id)) +#define __sanitizer_syscall_post__ksem_wait(res, id)                           \ +  __sanitizer_syscall_post_impl__ksem_wait(res, (long long)(id)) +#define __sanitizer_syscall_pre__ksem_trywait(id)                              \ +  __sanitizer_syscall_pre_impl__ksem_trywait((long long)(id)) +#define __sanitizer_syscall_post__ksem_trywait(res, id)                        \ +  __sanitizer_syscall_post_impl__ksem_trywait(res, (long long)(id)) +#define __sanitizer_syscall_pre__ksem_getvalue(id, value)                      \ +  __sanitizer_syscall_pre_impl__ksem_getvalue((long long)(id),                 \ +                                              (long long)(value)) +#define __sanitizer_syscall_post__ksem_getvalue(res, id, value)                \ +  __sanitizer_syscall_post_impl__ksem_getvalue(res, (long long)(id),           \ +                                               (long long)(value)) +#define __sanitizer_syscall_pre__ksem_destroy(id)                              \ +  __sanitizer_syscall_pre_impl__ksem_destroy((long long)(id)) +#define __sanitizer_syscall_post__ksem_destroy(res, id)                        \ +  __sanitizer_syscall_post_impl__ksem_destroy(res, (long long)(id)) +#define __sanitizer_syscall_pre__ksem_timedwait(id, abstime)                   \ +  __sanitizer_syscall_pre_impl__ksem_timedwait((long long)(id),                \ +                                               (long long)(abstime)) +#define __sanitizer_syscall_post__ksem_timedwait(res, id, abstime)             \ +  __sanitizer_syscall_post_impl__ksem_timedwait(res, (long long)(id),          \ +                                                (long long)(abstime)) +#define __sanitizer_syscall_pre_mq_open(name, oflag, mode, attr)               \ +  __sanitizer_syscall_pre_impl_mq_open((long long)(name), (long long)(oflag),  \ +                                       (long long)(mode), (long long)(attr)) +#define __sanitizer_syscall_post_mq_open(res, name, oflag, mode, attr)         \ +  __sanitizer_syscall_post_impl_mq_open(res, (long long)(name),                \ +                                        (long long)(oflag), (long long)(mode), \ +                                        (long long)(attr)) +#define __sanitizer_syscall_pre_mq_close(mqdes)                                \ +  __sanitizer_syscall_pre_impl_mq_close((long long)(mqdes)) +#define __sanitizer_syscall_post_mq_close(res, mqdes)                          \ +  __sanitizer_syscall_post_impl_mq_close(res, (long long)(mqdes)) +#define __sanitizer_syscall_pre_mq_unlink(name)                                \ +  __sanitizer_syscall_pre_impl_mq_unlink((long long)(name)) +#define __sanitizer_syscall_post_mq_unlink(res, name)                          \ +  __sanitizer_syscall_post_impl_mq_unlink(res, (long long)(name)) +#define __sanitizer_syscall_pre_mq_getattr(mqdes, mqstat)                      \ +  __sanitizer_syscall_pre_impl_mq_getattr((long long)(mqdes),                  \ +                                          (long long)(mqstat)) +#define __sanitizer_syscall_post_mq_getattr(res, mqdes, mqstat)                \ +  __sanitizer_syscall_post_impl_mq_getattr(res, (long long)(mqdes),            \ +                                           (long long)(mqstat)) +#define __sanitizer_syscall_pre_mq_setattr(mqdes, mqstat, omqstat)             \ +  __sanitizer_syscall_pre_impl_mq_setattr(                                     \ +      (long long)(mqdes), (long long)(mqstat), (long long)(omqstat)) +#define __sanitizer_syscall_post_mq_setattr(res, mqdes, mqstat, omqstat)       \ +  __sanitizer_syscall_post_impl_mq_setattr(                                    \ +      res, (long long)(mqdes), (long long)(mqstat), (long long)(omqstat)) +#define __sanitizer_syscall_pre_mq_notify(mqdes, notification)                 \ +  __sanitizer_syscall_pre_impl_mq_notify((long long)(mqdes),                   \ +                                         (long long)(notification)) +#define __sanitizer_syscall_post_mq_notify(res, mqdes, notification)           \ +  __sanitizer_syscall_post_impl_mq_notify(res, (long long)(mqdes),             \ +                                          (long long)(notification)) +#define __sanitizer_syscall_pre_mq_send(mqdes, msg_ptr, msg_len, msg_prio)     \ +  __sanitizer_syscall_pre_impl_mq_send(                                        \ +      (long long)(mqdes), (long long)(msg_ptr), (long long)(msg_len),          \ +      (long long)(msg_prio)) +#define __sanitizer_syscall_post_mq_send(res, mqdes, msg_ptr, msg_len,         \ +                                         msg_prio)                             \ +  __sanitizer_syscall_post_impl_mq_send(                                       \ +      res, (long long)(mqdes), (long long)(msg_ptr), (long long)(msg_len),     \ +      (long long)(msg_prio)) +#define __sanitizer_syscall_pre_mq_receive(mqdes, msg_ptr, msg_len, msg_prio)  \ +  __sanitizer_syscall_pre_impl_mq_receive(                                     \ +      (long long)(mqdes), (long long)(msg_ptr), (long long)(msg_len),          \ +      (long long)(msg_prio)) +#define __sanitizer_syscall_post_mq_receive(res, mqdes, msg_ptr, msg_len,      \ +                                            msg_prio)                          \ +  __sanitizer_syscall_post_impl_mq_receive(                                    \ +      res, (long long)(mqdes), (long long)(msg_ptr), (long long)(msg_len),     \ +      (long long)(msg_prio)) +#define __sanitizer_syscall_pre_compat_50_mq_timedsend(                        \ +    mqdes, msg_ptr, msg_len, msg_prio, abs_timeout)                            \ +  __sanitizer_syscall_pre_impl_compat_50_mq_timedsend(                         \ +      (long long)(mqdes), (long long)(msg_ptr), (long long)(msg_len),          \ +      (long long)(msg_prio), (long long)(abs_timeout)) +#define __sanitizer_syscall_post_compat_50_mq_timedsend(                       \ +    res, mqdes, msg_ptr, msg_len, msg_prio, abs_timeout)                       \ +  __sanitizer_syscall_post_impl_compat_50_mq_timedsend(                        \ +      res, (long long)(mqdes), (long long)(msg_ptr), (long long)(msg_len),     \ +      (long long)(msg_prio), (long long)(abs_timeout)) +#define __sanitizer_syscall_pre_compat_50_mq_timedreceive(                     \ +    mqdes, msg_ptr, msg_len, msg_prio, abs_timeout)                            \ +  __sanitizer_syscall_pre_impl_compat_50_mq_timedreceive(                      \ +      (long long)(mqdes), (long long)(msg_ptr), (long long)(msg_len),          \ +      (long long)(msg_prio), (long long)(abs_timeout)) +#define __sanitizer_syscall_post_compat_50_mq_timedreceive(                    \ +    res, mqdes, msg_ptr, msg_len, msg_prio, abs_timeout)                       \ +  __sanitizer_syscall_post_impl_compat_50_mq_timedreceive(                     \ +      res, (long long)(mqdes), (long long)(msg_ptr), (long long)(msg_len),     \ +      (long long)(msg_prio), (long long)(abs_timeout)) +/* syscall 267 has been skipped */ +/* syscall 268 has been skipped */ +/* syscall 269 has been skipped */ +#define __sanitizer_syscall_pre___posix_rename(from, to)                       \ +  __sanitizer_syscall_pre_impl___posix_rename((long long)(from),               \ +                                              (long long)(to)) +#define __sanitizer_syscall_post___posix_rename(res, from, to)                 \ +  __sanitizer_syscall_post_impl___posix_rename(res, (long long)(from),         \ +                                               (long long)(to)) +#define __sanitizer_syscall_pre_swapctl(cmd, arg, misc)                        \ +  __sanitizer_syscall_pre_impl_swapctl((long long)(cmd), (long long)(arg),     \ +                                       (long long)(misc)) +#define __sanitizer_syscall_post_swapctl(res, cmd, arg, misc)                  \ +  __sanitizer_syscall_post_impl_swapctl(res, (long long)(cmd),                 \ +                                        (long long)(arg), (long long)(misc)) +#define __sanitizer_syscall_pre_compat_30_getdents(fd, buf, count)             \ +  __sanitizer_syscall_pre_impl_compat_30_getdents(                             \ +      (long long)(fd), (long long)(buf), (long long)(count)) +#define __sanitizer_syscall_post_compat_30_getdents(res, fd, buf, count)       \ +  __sanitizer_syscall_post_impl_compat_30_getdents(                            \ +      res, (long long)(fd), (long long)(buf), (long long)(count)) +#define __sanitizer_syscall_pre_minherit(addr, len, inherit)                   \ +  __sanitizer_syscall_pre_impl_minherit((long long)(addr), (long long)(len),   \ +                                        (long long)(inherit)) +#define __sanitizer_syscall_post_minherit(res, addr, len, inherit)             \ +  __sanitizer_syscall_post_impl_minherit(                                      \ +      res, (long long)(addr), (long long)(len), (long long)(inherit)) +#define __sanitizer_syscall_pre_lchmod(path, mode)                             \ +  __sanitizer_syscall_pre_impl_lchmod((long long)(path), (long long)(mode)) +#define __sanitizer_syscall_post_lchmod(res, path, mode)                       \ +  __sanitizer_syscall_post_impl_lchmod(res, (long long)(path),                 \ +                                       (long long)(mode)) +#define __sanitizer_syscall_pre_lchown(path, uid, gid)                         \ +  __sanitizer_syscall_pre_impl_lchown((long long)(path), (long long)(uid),     \ +                                      (long long)(gid)) +#define __sanitizer_syscall_post_lchown(res, path, uid, gid)                   \ +  __sanitizer_syscall_post_impl_lchown(res, (long long)(path),                 \ +                                       (long long)(uid), (long long)(gid)) +#define __sanitizer_syscall_pre_compat_50_lutimes(path, tptr)                  \ +  __sanitizer_syscall_pre_impl_compat_50_lutimes((long long)(path),            \ +                                                 (long long)(tptr)) +#define __sanitizer_syscall_post_compat_50_lutimes(res, path, tptr)            \ +  __sanitizer_syscall_post_impl_compat_50_lutimes(res, (long long)(path),      \ +                                                  (long long)(tptr)) +#define __sanitizer_syscall_pre___msync13(addr, len, flags)                    \ +  __sanitizer_syscall_pre_impl___msync13((long long)(addr), (long long)(len),  \ +                                         (long long)(flags)) +#define __sanitizer_syscall_post___msync13(res, addr, len, flags)              \ +  __sanitizer_syscall_post_impl___msync13(                                     \ +      res, (long long)(addr), (long long)(len), (long long)(flags)) +#define __sanitizer_syscall_pre_compat_30___stat13(path, ub)                   \ +  __sanitizer_syscall_pre_impl_compat_30___stat13((long long)(path),           \ +                                                  (long long)(ub)) +#define __sanitizer_syscall_post_compat_30___stat13(res, path, ub)             \ +  __sanitizer_syscall_post_impl_compat_30___stat13(res, (long long)(path),     \ +                                                   (long long)(ub)) +#define __sanitizer_syscall_pre_compat_30___fstat13(fd, sb)                    \ +  __sanitizer_syscall_pre_impl_compat_30___fstat13((long long)(fd),            \ +                                                   (long long)(sb)) +#define __sanitizer_syscall_post_compat_30___fstat13(res, fd, sb)              \ +  __sanitizer_syscall_post_impl_compat_30___fstat13(res, (long long)(fd),      \ +                                                    (long long)(sb)) +#define __sanitizer_syscall_pre_compat_30___lstat13(path, ub)                  \ +  __sanitizer_syscall_pre_impl_compat_30___lstat13((long long)(path),          \ +                                                   (long long)(ub)) +#define __sanitizer_syscall_post_compat_30___lstat13(res, path, ub)            \ +  __sanitizer_syscall_post_impl_compat_30___lstat13(res, (long long)(path),    \ +                                                    (long long)(ub)) +#define __sanitizer_syscall_pre___sigaltstack14(nss, oss)                      \ +  __sanitizer_syscall_pre_impl___sigaltstack14((long long)(nss),               \ +                                               (long long)(oss)) +#define __sanitizer_syscall_post___sigaltstack14(res, nss, oss)                \ +  __sanitizer_syscall_post_impl___sigaltstack14(res, (long long)(nss),         \ +                                                (long long)(oss)) +#define __sanitizer_syscall_pre___vfork14()                                    \ +  __sanitizer_syscall_pre_impl___vfork14() +#define __sanitizer_syscall_post___vfork14(res)                                \ +  __sanitizer_syscall_post_impl___vfork14(res) +#define __sanitizer_syscall_pre___posix_chown(path, uid, gid)                  \ +  __sanitizer_syscall_pre_impl___posix_chown(                                  \ +      (long long)(path), (long long)(uid), (long long)(gid)) +#define __sanitizer_syscall_post___posix_chown(res, path, uid, gid)            \ +  __sanitizer_syscall_post_impl___posix_chown(                                 \ +      res, (long long)(path), (long long)(uid), (long long)(gid)) +#define __sanitizer_syscall_pre___posix_fchown(fd, uid, gid)                   \ +  __sanitizer_syscall_pre_impl___posix_fchown(                                 \ +      (long long)(fd), (long long)(uid), (long long)(gid)) +#define __sanitizer_syscall_post___posix_fchown(res, fd, uid, gid)             \ +  __sanitizer_syscall_post_impl___posix_fchown(                                \ +      res, (long long)(fd), (long long)(uid), (long long)(gid)) +#define __sanitizer_syscall_pre___posix_lchown(path, uid, gid)                 \ +  __sanitizer_syscall_pre_impl___posix_lchown(                                 \ +      (long long)(path), (long long)(uid), (long long)(gid)) +#define __sanitizer_syscall_post___posix_lchown(res, path, uid, gid)           \ +  __sanitizer_syscall_post_impl___posix_lchown(                                \ +      res, (long long)(path), (long long)(uid), (long long)(gid)) +#define __sanitizer_syscall_pre_getsid(pid)                                    \ +  __sanitizer_syscall_pre_impl_getsid((long long)(pid)) +#define __sanitizer_syscall_post_getsid(res, pid)                              \ +  __sanitizer_syscall_post_impl_getsid(res, (long long)(pid)) +#define __sanitizer_syscall_pre___clone(flags, stack)                          \ +  __sanitizer_syscall_pre_impl___clone((long long)(flags), (long long)(stack)) +#define __sanitizer_syscall_post___clone(res, flags, stack)                    \ +  __sanitizer_syscall_post_impl___clone(res, (long long)(flags),               \ +                                        (long long)(stack)) +#define __sanitizer_syscall_pre_fktrace(fd, ops, facs, pid)                    \ +  __sanitizer_syscall_pre_impl_fktrace((long long)(fd), (long long)(ops),      \ +                                       (long long)(facs), (long long)(pid)) +#define __sanitizer_syscall_post_fktrace(res, fd, ops, facs, pid)              \ +  __sanitizer_syscall_post_impl_fktrace(res, (long long)(fd),                  \ +                                        (long long)(ops), (long long)(facs),   \ +                                        (long long)(pid)) +#define __sanitizer_syscall_pre_preadv(fd, iovp, iovcnt, PAD, offset)          \ +  __sanitizer_syscall_pre_impl_preadv((long long)(fd), (long long)(iovp),      \ +                                      (long long)(iovcnt), (long long)(PAD),   \ +                                      (long long)(offset)) +#define __sanitizer_syscall_post_preadv(res, fd, iovp, iovcnt, PAD, offset)    \ +  __sanitizer_syscall_post_impl_preadv(res, (long long)(fd),                   \ +                                       (long long)(iovp), (long long)(iovcnt), \ +                                       (long long)(PAD), (long long)(offset)) +#define __sanitizer_syscall_pre_pwritev(fd, iovp, iovcnt, PAD, offset)         \ +  __sanitizer_syscall_pre_impl_pwritev((long long)(fd), (long long)(iovp),     \ +                                       (long long)(iovcnt), (long long)(PAD),  \ +                                       (long long)(offset)) +#define __sanitizer_syscall_post_pwritev(res, fd, iovp, iovcnt, PAD, offset)   \ +  __sanitizer_syscall_post_impl_pwritev(                                       \ +      res, (long long)(fd), (long long)(iovp), (long long)(iovcnt),            \ +      (long long)(PAD), (long long)(offset)) +#define __sanitizer_syscall_pre_compat_16___sigaction14(signum, nsa, osa)      \ +  __sanitizer_syscall_pre_impl_compat_16___sigaction14(                        \ +      (long long)(signum), (long long)(nsa), (long long)(osa)) +#define __sanitizer_syscall_post_compat_16___sigaction14(res, signum, nsa,     \ +                                                         osa)                  \ +  __sanitizer_syscall_post_impl_compat_16___sigaction14(                       \ +      res, (long long)(signum), (long long)(nsa), (long long)(osa)) +#define __sanitizer_syscall_pre___sigpending14(set)                            \ +  __sanitizer_syscall_pre_impl___sigpending14((long long)(set)) +#define __sanitizer_syscall_post___sigpending14(res, set)                      \ +  __sanitizer_syscall_post_impl___sigpending14(res, (long long)(set)) +#define __sanitizer_syscall_pre___sigprocmask14(how, set, oset)                \ +  __sanitizer_syscall_pre_impl___sigprocmask14(                                \ +      (long long)(how), (long long)(set), (long long)(oset)) +#define __sanitizer_syscall_post___sigprocmask14(res, how, set, oset)          \ +  __sanitizer_syscall_post_impl___sigprocmask14(                               \ +      res, (long long)(how), (long long)(set), (long long)(oset)) +#define __sanitizer_syscall_pre___sigsuspend14(set)                            \ +  __sanitizer_syscall_pre_impl___sigsuspend14((long long)(set)) +#define __sanitizer_syscall_post___sigsuspend14(res, set)                      \ +  __sanitizer_syscall_post_impl___sigsuspend14(res, (long long)(set)) +#define __sanitizer_syscall_pre_compat_16___sigreturn14(sigcntxp)              \ +  __sanitizer_syscall_pre_impl_compat_16___sigreturn14((long long)(sigcntxp)) +#define __sanitizer_syscall_post_compat_16___sigreturn14(res, sigcntxp)        \ +  __sanitizer_syscall_post_impl_compat_16___sigreturn14(res,                   \ +                                                        (long long)(sigcntxp)) +#define __sanitizer_syscall_pre___getcwd(bufp, length)                         \ +  __sanitizer_syscall_pre_impl___getcwd((long long)(bufp), (long long)(length)) +#define __sanitizer_syscall_post___getcwd(res, bufp, length)                   \ +  __sanitizer_syscall_post_impl___getcwd(res, (long long)(bufp),               \ +                                         (long long)(length)) +#define __sanitizer_syscall_pre_fchroot(fd)                                    \ +  __sanitizer_syscall_pre_impl_fchroot((long long)(fd)) +#define __sanitizer_syscall_post_fchroot(res, fd)                              \ +  __sanitizer_syscall_post_impl_fchroot(res, (long long)(fd)) +#define __sanitizer_syscall_pre_compat_30_fhopen(fhp, flags)                   \ +  __sanitizer_syscall_pre_impl_compat_30_fhopen((long long)(fhp),              \ +                                                (long long)(flags)) +#define __sanitizer_syscall_post_compat_30_fhopen(res, fhp, flags)             \ +  __sanitizer_syscall_post_impl_compat_30_fhopen(res, (long long)(fhp),        \ +                                                 (long long)(flags)) +#define __sanitizer_syscall_pre_compat_30_fhstat(fhp, sb)                      \ +  __sanitizer_syscall_pre_impl_compat_30_fhstat((long long)(fhp),              \ +                                                (long long)(sb)) +#define __sanitizer_syscall_post_compat_30_fhstat(res, fhp, sb)                \ +  __sanitizer_syscall_post_impl_compat_30_fhstat(res, (long long)(fhp),        \ +                                                 (long long)(sb)) +#define __sanitizer_syscall_pre_compat_20_fhstatfs(fhp, buf)                   \ +  __sanitizer_syscall_pre_impl_compat_20_fhstatfs((long long)(fhp),            \ +                                                  (long long)(buf)) +#define __sanitizer_syscall_post_compat_20_fhstatfs(res, fhp, buf)             \ +  __sanitizer_syscall_post_impl_compat_20_fhstatfs(res, (long long)(fhp),      \ +                                                   (long long)(buf)) +#define __sanitizer_syscall_pre_compat_50_____semctl13(semid, semnum, cmd,     \ +                                                       arg)                    \ +  __sanitizer_syscall_pre_impl_compat_50_____semctl13(                         \ +      (long long)(semid), (long long)(semnum), (long long)(cmd),               \ +      (long long)(arg)) +#define __sanitizer_syscall_post_compat_50_____semctl13(res, semid, semnum,    \ +                                                        cmd, arg)              \ +  __sanitizer_syscall_post_impl_compat_50_____semctl13(                        \ +      res, (long long)(semid), (long long)(semnum), (long long)(cmd),          \ +      (long long)(arg)) +#define __sanitizer_syscall_pre_compat_50___msgctl13(msqid, cmd, buf)          \ +  __sanitizer_syscall_pre_impl_compat_50___msgctl13(                           \ +      (long long)(msqid), (long long)(cmd), (long long)(buf)) +#define __sanitizer_syscall_post_compat_50___msgctl13(res, msqid, cmd, buf)    \ +  __sanitizer_syscall_post_impl_compat_50___msgctl13(                          \ +      res, (long long)(msqid), (long long)(cmd), (long long)(buf)) +#define __sanitizer_syscall_pre_compat_50___shmctl13(shmid, cmd, buf)          \ +  __sanitizer_syscall_pre_impl_compat_50___shmctl13(                           \ +      (long long)(shmid), (long long)(cmd), (long long)(buf)) +#define __sanitizer_syscall_post_compat_50___shmctl13(res, shmid, cmd, buf)    \ +  __sanitizer_syscall_post_impl_compat_50___shmctl13(                          \ +      res, (long long)(shmid), (long long)(cmd), (long long)(buf)) +#define __sanitizer_syscall_pre_lchflags(path, flags)                          \ +  __sanitizer_syscall_pre_impl_lchflags((long long)(path), (long long)(flags)) +#define __sanitizer_syscall_post_lchflags(res, path, flags)                    \ +  __sanitizer_syscall_post_impl_lchflags(res, (long long)(path),               \ +                                         (long long)(flags)) +#define __sanitizer_syscall_pre_issetugid()                                    \ +  __sanitizer_syscall_pre_impl_issetugid() +#define __sanitizer_syscall_post_issetugid(res)                                \ +  __sanitizer_syscall_post_impl_issetugid(res) +#define __sanitizer_syscall_pre_utrace(label, addr, len)                       \ +  __sanitizer_syscall_pre_impl_utrace((long long)(label), (long long)(addr),   \ +                                      (long long)(len)) +#define __sanitizer_syscall_post_utrace(res, label, addr, len)                 \ +  __sanitizer_syscall_post_impl_utrace(res, (long long)(label),                \ +                                       (long long)(addr), (long long)(len)) +#define __sanitizer_syscall_pre_getcontext(ucp)                                \ +  __sanitizer_syscall_pre_impl_getcontext((long long)(ucp)) +#define __sanitizer_syscall_post_getcontext(res, ucp)                          \ +  __sanitizer_syscall_post_impl_getcontext(res, (long long)(ucp)) +#define __sanitizer_syscall_pre_setcontext(ucp)                                \ +  __sanitizer_syscall_pre_impl_setcontext((long long)(ucp)) +#define __sanitizer_syscall_post_setcontext(res, ucp)                          \ +  __sanitizer_syscall_post_impl_setcontext(res, (long long)(ucp)) +#define __sanitizer_syscall_pre__lwp_create(ucp, flags, new_lwp)               \ +  __sanitizer_syscall_pre_impl__lwp_create(                                    \ +      (long long)(ucp), (long long)(flags), (long long)(new_lwp)) +#define __sanitizer_syscall_post__lwp_create(res, ucp, flags, new_lwp)         \ +  __sanitizer_syscall_post_impl__lwp_create(                                   \ +      res, (long long)(ucp), (long long)(flags), (long long)(new_lwp)) +#define __sanitizer_syscall_pre__lwp_exit()                                    \ +  __sanitizer_syscall_pre_impl__lwp_exit() +#define __sanitizer_syscall_post__lwp_exit(res)                                \ +  __sanitizer_syscall_post_impl__lwp_exit(res) +#define __sanitizer_syscall_pre__lwp_self()                                    \ +  __sanitizer_syscall_pre_impl__lwp_self() +#define __sanitizer_syscall_post__lwp_self(res)                                \ +  __sanitizer_syscall_post_impl__lwp_self(res) +#define __sanitizer_syscall_pre__lwp_wait(wait_for, departed)                  \ +  __sanitizer_syscall_pre_impl__lwp_wait((long long)(wait_for),                \ +                                         (long long)(departed)) +#define __sanitizer_syscall_post__lwp_wait(res, wait_for, departed)            \ +  __sanitizer_syscall_post_impl__lwp_wait(res, (long long)(wait_for),          \ +                                          (long long)(departed)) +#define __sanitizer_syscall_pre__lwp_suspend(target)                           \ +  __sanitizer_syscall_pre_impl__lwp_suspend((long long)(target)) +#define __sanitizer_syscall_post__lwp_suspend(res, target)                     \ +  __sanitizer_syscall_post_impl__lwp_suspend(res, (long long)(target)) +#define __sanitizer_syscall_pre__lwp_continue(target)                          \ +  __sanitizer_syscall_pre_impl__lwp_continue((long long)(target)) +#define __sanitizer_syscall_post__lwp_continue(res, target)                    \ +  __sanitizer_syscall_post_impl__lwp_continue(res, (long long)(target)) +#define __sanitizer_syscall_pre__lwp_wakeup(target)                            \ +  __sanitizer_syscall_pre_impl__lwp_wakeup((long long)(target)) +#define __sanitizer_syscall_post__lwp_wakeup(res, target)                      \ +  __sanitizer_syscall_post_impl__lwp_wakeup(res, (long long)(target)) +#define __sanitizer_syscall_pre__lwp_getprivate()                              \ +  __sanitizer_syscall_pre_impl__lwp_getprivate() +#define __sanitizer_syscall_post__lwp_getprivate(res)                          \ +  __sanitizer_syscall_post_impl__lwp_getprivate(res) +#define __sanitizer_syscall_pre__lwp_setprivate(ptr)                           \ +  __sanitizer_syscall_pre_impl__lwp_setprivate((long long)(ptr)) +#define __sanitizer_syscall_post__lwp_setprivate(res, ptr)                     \ +  __sanitizer_syscall_post_impl__lwp_setprivate(res, (long long)(ptr)) +#define __sanitizer_syscall_pre__lwp_kill(target, signo)                       \ +  __sanitizer_syscall_pre_impl__lwp_kill((long long)(target),                  \ +                                         (long long)(signo)) +#define __sanitizer_syscall_post__lwp_kill(res, target, signo)                 \ +  __sanitizer_syscall_post_impl__lwp_kill(res, (long long)(target),            \ +                                          (long long)(signo)) +#define __sanitizer_syscall_pre__lwp_detach(target)                            \ +  __sanitizer_syscall_pre_impl__lwp_detach((long long)(target)) +#define __sanitizer_syscall_post__lwp_detach(res, target)                      \ +  __sanitizer_syscall_post_impl__lwp_detach(res, (long long)(target)) +#define __sanitizer_syscall_pre_compat_50__lwp_park(ts, unpark, hint,          \ +                                                    unparkhint)                \ +  __sanitizer_syscall_pre_impl_compat_50__lwp_park(                            \ +      (long long)(ts), (long long)(unpark), (long long)(hint),                 \ +      (long long)(unparkhint)) +#define __sanitizer_syscall_post_compat_50__lwp_park(res, ts, unpark, hint,    \ +                                                     unparkhint)               \ +  __sanitizer_syscall_post_impl_compat_50__lwp_park(                           \ +      res, (long long)(ts), (long long)(unpark), (long long)(hint),            \ +      (long long)(unparkhint)) +#define __sanitizer_syscall_pre__lwp_unpark(target, hint)                      \ +  __sanitizer_syscall_pre_impl__lwp_unpark((long long)(target),                \ +                                           (long long)(hint)) +#define __sanitizer_syscall_post__lwp_unpark(res, target, hint)                \ +  __sanitizer_syscall_post_impl__lwp_unpark(res, (long long)(target),          \ +                                            (long long)(hint)) +#define __sanitizer_syscall_pre__lwp_unpark_all(targets, ntargets, hint)       \ +  __sanitizer_syscall_pre_impl__lwp_unpark_all(                                \ +      (long long)(targets), (long long)(ntargets), (long long)(hint)) +#define __sanitizer_syscall_post__lwp_unpark_all(res, targets, ntargets, hint) \ +  __sanitizer_syscall_post_impl__lwp_unpark_all(                               \ +      res, (long long)(targets), (long long)(ntargets), (long long)(hint)) +#define __sanitizer_syscall_pre__lwp_setname(target, name)                     \ +  __sanitizer_syscall_pre_impl__lwp_setname((long long)(target),               \ +                                            (long long)(name)) +#define __sanitizer_syscall_post__lwp_setname(res, target, name)               \ +  __sanitizer_syscall_post_impl__lwp_setname(res, (long long)(target),         \ +                                             (long long)(name)) +#define __sanitizer_syscall_pre__lwp_getname(target, name, len)                \ +  __sanitizer_syscall_pre_impl__lwp_getname(                                   \ +      (long long)(target), (long long)(name), (long long)(len)) +#define __sanitizer_syscall_post__lwp_getname(res, target, name, len)          \ +  __sanitizer_syscall_post_impl__lwp_getname(                                  \ +      res, (long long)(target), (long long)(name), (long long)(len)) +#define __sanitizer_syscall_pre__lwp_ctl(features, address)                    \ +  __sanitizer_syscall_pre_impl__lwp_ctl((long long)(features),                 \ +                                        (long long)(address)) +#define __sanitizer_syscall_post__lwp_ctl(res, features, address)              \ +  __sanitizer_syscall_post_impl__lwp_ctl(res, (long long)(features),           \ +                                         (long long)(address)) +/* syscall 326 has been skipped */ +/* syscall 327 has been skipped */ +/* syscall 328 has been skipped */ +/* syscall 329 has been skipped */ +#define __sanitizer_syscall_pre_compat_60_sa_register(newv, oldv, flags,       \ +                                                      stackinfo_offset)        \ +  __sanitizer_syscall_pre_impl_compat_60_sa_register(                          \ +      (long long)(newv), (long long)(oldv), (long long)(flags),                \ +      (long long)(stackinfo_offset)) +#define __sanitizer_syscall_post_compat_60_sa_register(res, newv, oldv, flags, \ +                                                       stackinfo_offset)       \ +  __sanitizer_syscall_post_impl_compat_60_sa_register(                         \ +      res, (long long)(newv), (long long)(oldv), (long long)(flags),           \ +      (long long)(stackinfo_offset)) +#define __sanitizer_syscall_pre_compat_60_sa_stacks(num, stacks)               \ +  __sanitizer_syscall_pre_impl_compat_60_sa_stacks((long long)(num),           \ +                                                   (long long)(stacks)) +#define __sanitizer_syscall_post_compat_60_sa_stacks(res, num, stacks)         \ +  __sanitizer_syscall_post_impl_compat_60_sa_stacks(res, (long long)(num),     \ +                                                    (long long)(stacks)) +#define __sanitizer_syscall_pre_compat_60_sa_enable()                          \ +  __sanitizer_syscall_pre_impl_compat_60_sa_enable() +#define __sanitizer_syscall_post_compat_60_sa_enable(res)                      \ +  __sanitizer_syscall_post_impl_compat_60_sa_enable(res) +#define __sanitizer_syscall_pre_compat_60_sa_setconcurrency(concurrency)       \ +  __sanitizer_syscall_pre_impl_compat_60_sa_setconcurrency(                    \ +      (long long)(concurrency)) +#define __sanitizer_syscall_post_compat_60_sa_setconcurrency(res, concurrency) \ +  __sanitizer_syscall_post_impl_compat_60_sa_setconcurrency(                   \ +      res, (long long)(concurrency)) +#define __sanitizer_syscall_pre_compat_60_sa_yield()                           \ +  __sanitizer_syscall_pre_impl_compat_60_sa_yield() +#define __sanitizer_syscall_post_compat_60_sa_yield(res)                       \ +  __sanitizer_syscall_post_impl_compat_60_sa_yield(res) +#define __sanitizer_syscall_pre_compat_60_sa_preempt(sa_id)                    \ +  __sanitizer_syscall_pre_impl_compat_60_sa_preempt((long long)(sa_id)) +#define __sanitizer_syscall_post_compat_60_sa_preempt(res, sa_id)              \ +  __sanitizer_syscall_post_impl_compat_60_sa_preempt(res, (long long)(sa_id)) +/* syscall 336 has been skipped */ +/* syscall 337 has been skipped */ +/* syscall 338 has been skipped */ +/* syscall 339 has been skipped */ +#define __sanitizer_syscall_pre___sigaction_sigtramp(signum, nsa, osa, tramp,  \ +                                                     vers)                     \ +  __sanitizer_syscall_pre_impl___sigaction_sigtramp(                           \ +      (long long)(signum), (long long)(nsa), (long long)(osa),                 \ +      (long long)(tramp), (long long)(vers)) +#define __sanitizer_syscall_post___sigaction_sigtramp(res, signum, nsa, osa,   \ +                                                      tramp, vers)             \ +  __sanitizer_syscall_post_impl___sigaction_sigtramp(                          \ +      res, (long long)(signum), (long long)(nsa), (long long)(osa),            \ +      (long long)(tramp), (long long)(vers)) +#define __sanitizer_syscall_pre_pmc_get_info(ctr, op, args)                    \ +  __sanitizer_syscall_pre_impl_pmc_get_info((long long)(ctr), (long long)(op), \ +                                            (long long)(args)) +#define __sanitizer_syscall_post_pmc_get_info(res, ctr, op, args)              \ +  __sanitizer_syscall_post_impl_pmc_get_info(                                  \ +      res, (long long)(ctr), (long long)(op), (long long)(args)) +#define __sanitizer_syscall_pre_pmc_control(ctr, op, args)                     \ +  __sanitizer_syscall_pre_impl_pmc_control((long long)(ctr), (long long)(op),  \ +                                           (long long)(args)) +#define __sanitizer_syscall_post_pmc_control(res, ctr, op, args)               \ +  __sanitizer_syscall_post_impl_pmc_control(                                   \ +      res, (long long)(ctr), (long long)(op), (long long)(args)) +#define __sanitizer_syscall_pre_rasctl(addr, len, op)                          \ +  __sanitizer_syscall_pre_impl_rasctl((long long)(addr), (long long)(len),     \ +                                      (long long)(op)) +#define __sanitizer_syscall_post_rasctl(res, addr, len, op)                    \ +  __sanitizer_syscall_post_impl_rasctl(res, (long long)(addr),                 \ +                                       (long long)(len), (long long)(op)) +#define __sanitizer_syscall_pre_kqueue() __sanitizer_syscall_pre_impl_kqueue() +#define __sanitizer_syscall_post_kqueue(res)                                   \ +  __sanitizer_syscall_post_impl_kqueue(res) +#define __sanitizer_syscall_pre_compat_50_kevent(fd, changelist, nchanges,     \ +                                                 eventlist, nevents, timeout)  \ +  __sanitizer_syscall_pre_impl_compat_50_kevent(                               \ +      (long long)(fd), (long long)(changelist), (long long)(nchanges),         \ +      (long long)(eventlist), (long long)(nevents), (long long)(timeout)) +#define __sanitizer_syscall_post_compat_50_kevent(                             \ +    res, fd, changelist, nchanges, eventlist, nevents, timeout)                \ +  __sanitizer_syscall_post_impl_compat_50_kevent(                              \ +      res, (long long)(fd), (long long)(changelist), (long long)(nchanges),    \ +      (long long)(eventlist), (long long)(nevents), (long long)(timeout)) +#define __sanitizer_syscall_pre__sched_setparam(pid, lid, policy, params)      \ +  __sanitizer_syscall_pre_impl__sched_setparam(                                \ +      (long long)(pid), (long long)(lid), (long long)(policy),                 \ +      (long long)(params)) +#define __sanitizer_syscall_post__sched_setparam(res, pid, lid, policy,        \ +                                                 params)                       \ +  __sanitizer_syscall_post_impl__sched_setparam(                               \ +      res, (long long)(pid), (long long)(lid), (long long)(policy),            \ +      (long long)(params)) +#define __sanitizer_syscall_pre__sched_getparam(pid, lid, policy, params)      \ +  __sanitizer_syscall_pre_impl__sched_getparam(                                \ +      (long long)(pid), (long long)(lid), (long long)(policy),                 \ +      (long long)(params)) +#define __sanitizer_syscall_post__sched_getparam(res, pid, lid, policy,        \ +                                                 params)                       \ +  __sanitizer_syscall_post_impl__sched_getparam(                               \ +      res, (long long)(pid), (long long)(lid), (long long)(policy),            \ +      (long long)(params)) +#define __sanitizer_syscall_pre__sched_setaffinity(pid, lid, size, cpuset)     \ +  __sanitizer_syscall_pre_impl__sched_setaffinity(                             \ +      (long long)(pid), (long long)(lid), (long long)(size),                   \ +      (long long)(cpuset)) +#define __sanitizer_syscall_post__sched_setaffinity(res, pid, lid, size,       \ +                                                    cpuset)                    \ +  __sanitizer_syscall_post_impl__sched_setaffinity(                            \ +      res, (long long)(pid), (long long)(lid), (long long)(size),              \ +      (long long)(cpuset)) +#define __sanitizer_syscall_pre__sched_getaffinity(pid, lid, size, cpuset)     \ +  __sanitizer_syscall_pre_impl__sched_getaffinity(                             \ +      (long long)(pid), (long long)(lid), (long long)(size),                   \ +      (long long)(cpuset)) +#define __sanitizer_syscall_post__sched_getaffinity(res, pid, lid, size,       \ +                                                    cpuset)                    \ +  __sanitizer_syscall_post_impl__sched_getaffinity(                            \ +      res, (long long)(pid), (long long)(lid), (long long)(size),              \ +      (long long)(cpuset)) +#define __sanitizer_syscall_pre_sched_yield()                                  \ +  __sanitizer_syscall_pre_impl_sched_yield() +#define __sanitizer_syscall_post_sched_yield(res)                              \ +  __sanitizer_syscall_post_impl_sched_yield(res) +#define __sanitizer_syscall_pre__sched_protect(priority)                       \ +  __sanitizer_syscall_pre_impl__sched_protect((long long)(priority)) +#define __sanitizer_syscall_post__sched_protect(res, priority)                 \ +  __sanitizer_syscall_post_impl__sched_protect(res, (long long)(priority)) +/* syscall 352 has been skipped */ +/* syscall 353 has been skipped */ +#define __sanitizer_syscall_pre_fsync_range(fd, flags, start, length)          \ +  __sanitizer_syscall_pre_impl_fsync_range(                                    \ +      (long long)(fd), (long long)(flags), (long long)(start),                 \ +      (long long)(length)) +#define __sanitizer_syscall_post_fsync_range(res, fd, flags, start, length)    \ +  __sanitizer_syscall_post_impl_fsync_range(                                   \ +      res, (long long)(fd), (long long)(flags), (long long)(start),            \ +      (long long)(length)) +#define __sanitizer_syscall_pre_uuidgen(store, count)                          \ +  __sanitizer_syscall_pre_impl_uuidgen((long long)(store), (long long)(count)) +#define __sanitizer_syscall_post_uuidgen(res, store, count)                    \ +  __sanitizer_syscall_post_impl_uuidgen(res, (long long)(store),               \ +                                        (long long)(count)) +#define __sanitizer_syscall_pre_getvfsstat(buf, bufsize, flags)                \ +  __sanitizer_syscall_pre_impl_getvfsstat(                                     \ +      (long long)(buf), (long long)(bufsize), (long long)(flags)) +#define __sanitizer_syscall_post_getvfsstat(res, buf, bufsize, flags)          \ +  __sanitizer_syscall_post_impl_getvfsstat(                                    \ +      res, (long long)(buf), (long long)(bufsize), (long long)(flags)) +#define __sanitizer_syscall_pre_statvfs1(path, buf, flags)                     \ +  __sanitizer_syscall_pre_impl_statvfs1((long long)(path), (long long)(buf),   \ +                                        (long long)(flags)) +#define __sanitizer_syscall_post_statvfs1(res, path, buf, flags)               \ +  __sanitizer_syscall_post_impl_statvfs1(res, (long long)(path),               \ +                                         (long long)(buf), (long long)(flags)) +#define __sanitizer_syscall_pre_fstatvfs1(fd, buf, flags)                      \ +  __sanitizer_syscall_pre_impl_fstatvfs1((long long)(fd), (long long)(buf),    \ +                                         (long long)(flags)) +#define __sanitizer_syscall_post_fstatvfs1(res, fd, buf, flags)                \ +  __sanitizer_syscall_post_impl_fstatvfs1(                                     \ +      res, (long long)(fd), (long long)(buf), (long long)(flags)) +#define __sanitizer_syscall_pre_compat_30_fhstatvfs1(fhp, buf, flags)          \ +  __sanitizer_syscall_pre_impl_compat_30_fhstatvfs1(                           \ +      (long long)(fhp), (long long)(buf), (long long)(flags)) +#define __sanitizer_syscall_post_compat_30_fhstatvfs1(res, fhp, buf, flags)    \ +  __sanitizer_syscall_post_impl_compat_30_fhstatvfs1(                          \ +      res, (long long)(fhp), (long long)(buf), (long long)(flags)) +#define __sanitizer_syscall_pre_extattrctl(path, cmd, filename, attrnamespace, \ +                                           attrname)                           \ +  __sanitizer_syscall_pre_impl_extattrctl(                                     \ +      (long long)(path), (long long)(cmd), (long long)(filename),              \ +      (long long)(attrnamespace), (long long)(attrname)) +#define __sanitizer_syscall_post_extattrctl(res, path, cmd, filename,          \ +                                            attrnamespace, attrname)           \ +  __sanitizer_syscall_post_impl_extattrctl(                                    \ +      res, (long long)(path), (long long)(cmd), (long long)(filename),         \ +      (long long)(attrnamespace), (long long)(attrname)) +#define __sanitizer_syscall_pre_extattr_set_file(path, attrnamespace,          \ +                                                 attrname, data, nbytes)       \ +  __sanitizer_syscall_pre_impl_extattr_set_file(                               \ +      (long long)(path), (long long)(attrnamespace), (long long)(attrname),    \ +      (long long)(data), (long long)(nbytes)) +#define __sanitizer_syscall_post_extattr_set_file(res, path, attrnamespace,    \ +                                                  attrname, data, nbytes)      \ +  __sanitizer_syscall_post_impl_extattr_set_file(                              \ +      res, (long long)(path), (long long)(attrnamespace),                      \ +      (long long)(attrname), (long long)(data), (long long)(nbytes)) +#define __sanitizer_syscall_pre_extattr_get_file(path, attrnamespace,          \ +                                                 attrname, data, nbytes)       \ +  __sanitizer_syscall_pre_impl_extattr_get_file(                               \ +      (long long)(path), (long long)(attrnamespace), (long long)(attrname),    \ +      (long long)(data), (long long)(nbytes)) +#define __sanitizer_syscall_post_extattr_get_file(res, path, attrnamespace,    \ +                                                  attrname, data, nbytes)      \ +  __sanitizer_syscall_post_impl_extattr_get_file(                              \ +      res, (long long)(path), (long long)(attrnamespace),                      \ +      (long long)(attrname), (long long)(data), (long long)(nbytes)) +#define __sanitizer_syscall_pre_extattr_delete_file(path, attrnamespace,       \ +                                                    attrname)                  \ +  __sanitizer_syscall_pre_impl_extattr_delete_file(                            \ +      (long long)(path), (long long)(attrnamespace), (long long)(attrname)) +#define __sanitizer_syscall_post_extattr_delete_file(res, path, attrnamespace, \ +                                                     attrname)                 \ +  __sanitizer_syscall_post_impl_extattr_delete_file(                           \ +      res, (long long)(path), (long long)(attrnamespace),                      \ +      (long long)(attrname)) +#define __sanitizer_syscall_pre_extattr_set_fd(fd, attrnamespace, attrname,    \ +                                               data, nbytes)                   \ +  __sanitizer_syscall_pre_impl_extattr_set_fd(                                 \ +      (long long)(fd), (long long)(attrnamespace), (long long)(attrname),      \ +      (long long)(data), (long long)(nbytes)) +#define __sanitizer_syscall_post_extattr_set_fd(res, fd, attrnamespace,        \ +                                                attrname, data, nbytes)        \ +  __sanitizer_syscall_post_impl_extattr_set_fd(                                \ +      res, (long long)(fd), (long long)(attrnamespace), (long long)(attrname), \ +      (long long)(data), (long long)(nbytes)) +#define __sanitizer_syscall_pre_extattr_get_fd(fd, attrnamespace, attrname,    \ +                                               data, nbytes)                   \ +  __sanitizer_syscall_pre_impl_extattr_get_fd(                                 \ +      (long long)(fd), (long long)(attrnamespace), (long long)(attrname),      \ +      (long long)(data), (long long)(nbytes)) +#define __sanitizer_syscall_post_extattr_get_fd(res, fd, attrnamespace,        \ +                                                attrname, data, nbytes)        \ +  __sanitizer_syscall_post_impl_extattr_get_fd(                                \ +      res, (long long)(fd), (long long)(attrnamespace), (long long)(attrname), \ +      (long long)(data), (long long)(nbytes)) +#define __sanitizer_syscall_pre_extattr_delete_fd(fd, attrnamespace, attrname) \ +  __sanitizer_syscall_pre_impl_extattr_delete_fd(                              \ +      (long long)(fd), (long long)(attrnamespace), (long long)(attrname)) +#define __sanitizer_syscall_post_extattr_delete_fd(res, fd, attrnamespace,     \ +                                                   attrname)                   \ +  __sanitizer_syscall_post_impl_extattr_delete_fd(                             \ +      res, (long long)(fd), (long long)(attrnamespace), (long long)(attrname)) +#define __sanitizer_syscall_pre_extattr_set_link(path, attrnamespace,          \ +                                                 attrname, data, nbytes)       \ +  __sanitizer_syscall_pre_impl_extattr_set_link(                               \ +      (long long)(path), (long long)(attrnamespace), (long long)(attrname),    \ +      (long long)(data), (long long)(nbytes)) +#define __sanitizer_syscall_post_extattr_set_link(res, path, attrnamespace,    \ +                                                  attrname, data, nbytes)      \ +  __sanitizer_syscall_post_impl_extattr_set_link(                              \ +      res, (long long)(path), (long long)(attrnamespace),                      \ +      (long long)(attrname), (long long)(data), (long long)(nbytes)) +#define __sanitizer_syscall_pre_extattr_get_link(path, attrnamespace,          \ +                                                 attrname, data, nbytes)       \ +  __sanitizer_syscall_pre_impl_extattr_get_link(                               \ +      (long long)(path), (long long)(attrnamespace), (long long)(attrname),    \ +      (long long)(data), (long long)(nbytes)) +#define __sanitizer_syscall_post_extattr_get_link(res, path, attrnamespace,    \ +                                                  attrname, data, nbytes)      \ +  __sanitizer_syscall_post_impl_extattr_get_link(                              \ +      res, (long long)(path), (long long)(attrnamespace),                      \ +      (long long)(attrname), (long long)(data), (long long)(nbytes)) +#define __sanitizer_syscall_pre_extattr_delete_link(path, attrnamespace,       \ +                                                    attrname)                  \ +  __sanitizer_syscall_pre_impl_extattr_delete_link(                            \ +      (long long)(path), (long long)(attrnamespace), (long long)(attrname)) +#define __sanitizer_syscall_post_extattr_delete_link(res, path, attrnamespace, \ +                                                     attrname)                 \ +  __sanitizer_syscall_post_impl_extattr_delete_link(                           \ +      res, (long long)(path), (long long)(attrnamespace),                      \ +      (long long)(attrname)) +#define __sanitizer_syscall_pre_extattr_list_fd(fd, attrnamespace, data,       \ +                                                nbytes)                        \ +  __sanitizer_syscall_pre_impl_extattr_list_fd(                                \ +      (long long)(fd), (long long)(attrnamespace), (long long)(data),          \ +      (long long)(nbytes)) +#define __sanitizer_syscall_post_extattr_list_fd(res, fd, attrnamespace, data, \ +                                                 nbytes)                       \ +  __sanitizer_syscall_post_impl_extattr_list_fd(                               \ +      res, (long long)(fd), (long long)(attrnamespace), (long long)(data),     \ +      (long long)(nbytes)) +#define __sanitizer_syscall_pre_extattr_list_file(path, attrnamespace, data,   \ +                                                  nbytes)                      \ +  __sanitizer_syscall_pre_impl_extattr_list_file(                              \ +      (long long)(path), (long long)(attrnamespace), (long long)(data),        \ +      (long long)(nbytes)) +#define __sanitizer_syscall_post_extattr_list_file(res, path, attrnamespace,   \ +                                                   data, nbytes)               \ +  __sanitizer_syscall_post_impl_extattr_list_file(                             \ +      res, (long long)(path), (long long)(attrnamespace), (long long)(data),   \ +      (long long)(nbytes)) +#define __sanitizer_syscall_pre_extattr_list_link(path, attrnamespace, data,   \ +                                                  nbytes)                      \ +  __sanitizer_syscall_pre_impl_extattr_list_link(                              \ +      (long long)(path), (long long)(attrnamespace), (long long)(data),        \ +      (long long)(nbytes)) +#define __sanitizer_syscall_post_extattr_list_link(res, path, attrnamespace,   \ +                                                   data, nbytes)               \ +  __sanitizer_syscall_post_impl_extattr_list_link(                             \ +      res, (long long)(path), (long long)(attrnamespace), (long long)(data),   \ +      (long long)(nbytes)) +#define __sanitizer_syscall_pre_compat_50_pselect(nd, in, ou, ex, ts, mask)    \ +  __sanitizer_syscall_pre_impl_compat_50_pselect(                              \ +      (long long)(nd), (long long)(in), (long long)(ou), (long long)(ex),      \ +      (long long)(ts), (long long)(mask)) +#define __sanitizer_syscall_post_compat_50_pselect(res, nd, in, ou, ex, ts,    \ +                                                   mask)                       \ +  __sanitizer_syscall_post_impl_compat_50_pselect(                             \ +      res, (long long)(nd), (long long)(in), (long long)(ou), (long long)(ex), \ +      (long long)(ts), (long long)(mask)) +#define __sanitizer_syscall_pre_compat_50_pollts(fds, nfds, ts, mask)          \ +  __sanitizer_syscall_pre_impl_compat_50_pollts(                               \ +      (long long)(fds), (long long)(nfds), (long long)(ts), (long long)(mask)) +#define __sanitizer_syscall_post_compat_50_pollts(res, fds, nfds, ts, mask)    \ +  __sanitizer_syscall_post_impl_compat_50_pollts(                              \ +      res, (long long)(fds), (long long)(nfds), (long long)(ts),               \ +      (long long)(mask)) +#define __sanitizer_syscall_pre_setxattr(path, name, value, size, flags)       \ +  __sanitizer_syscall_pre_impl_setxattr((long long)(path), (long long)(name),  \ +                                        (long long)(value), (long long)(size), \ +                                        (long long)(flags)) +#define __sanitizer_syscall_post_setxattr(res, path, name, value, size, flags) \ +  __sanitizer_syscall_post_impl_setxattr(                                      \ +      res, (long long)(path), (long long)(name), (long long)(value),           \ +      (long long)(size), (long long)(flags)) +#define __sanitizer_syscall_pre_lsetxattr(path, name, value, size, flags)      \ +  __sanitizer_syscall_pre_impl_lsetxattr(                                      \ +      (long long)(path), (long long)(name), (long long)(value),                \ +      (long long)(size), (long long)(flags)) +#define __sanitizer_syscall_post_lsetxattr(res, path, name, value, size,       \ +                                           flags)                              \ +  __sanitizer_syscall_post_impl_lsetxattr(                                     \ +      res, (long long)(path), (long long)(name), (long long)(value),           \ +      (long long)(size), (long long)(flags)) +#define __sanitizer_syscall_pre_fsetxattr(fd, name, value, size, flags)        \ +  __sanitizer_syscall_pre_impl_fsetxattr(                                      \ +      (long long)(fd), (long long)(name), (long long)(value),                  \ +      (long long)(size), (long long)(flags)) +#define __sanitizer_syscall_post_fsetxattr(res, fd, name, value, size, flags)  \ +  __sanitizer_syscall_post_impl_fsetxattr(                                     \ +      res, (long long)(fd), (long long)(name), (long long)(value),             \ +      (long long)(size), (long long)(flags)) +#define __sanitizer_syscall_pre_getxattr(path, name, value, size)              \ +  __sanitizer_syscall_pre_impl_getxattr((long long)(path), (long long)(name),  \ +                                        (long long)(value), (long long)(size)) +#define __sanitizer_syscall_post_getxattr(res, path, name, value, size)        \ +  __sanitizer_syscall_post_impl_getxattr(                                      \ +      res, (long long)(path), (long long)(name), (long long)(value),           \ +      (long long)(size)) +#define __sanitizer_syscall_pre_lgetxattr(path, name, value, size)             \ +  __sanitizer_syscall_pre_impl_lgetxattr((long long)(path), (long long)(name), \ +                                         (long long)(value),                   \ +                                         (long long)(size)) +#define __sanitizer_syscall_post_lgetxattr(res, path, name, value, size)       \ +  __sanitizer_syscall_post_impl_lgetxattr(                                     \ +      res, (long long)(path), (long long)(name), (long long)(value),           \ +      (long long)(size)) +#define __sanitizer_syscall_pre_fgetxattr(fd, name, value, size)               \ +  __sanitizer_syscall_pre_impl_fgetxattr((long long)(fd), (long long)(name),   \ +                                         (long long)(value),                   \ +                                         (long long)(size)) +#define __sanitizer_syscall_post_fgetxattr(res, fd, name, value, size)         \ +  __sanitizer_syscall_post_impl_fgetxattr(                                     \ +      res, (long long)(fd), (long long)(name), (long long)(value),             \ +      (long long)(size)) +#define __sanitizer_syscall_pre_listxattr(path, list, size)                    \ +  __sanitizer_syscall_pre_impl_listxattr((long long)(path), (long long)(list), \ +                                         (long long)(size)) +#define __sanitizer_syscall_post_listxattr(res, path, list, size)              \ +  __sanitizer_syscall_post_impl_listxattr(                                     \ +      res, (long long)(path), (long long)(list), (long long)(size)) +#define __sanitizer_syscall_pre_llistxattr(path, list, size)                   \ +  __sanitizer_syscall_pre_impl_llistxattr(                                     \ +      (long long)(path), (long long)(list), (long long)(size)) +#define __sanitizer_syscall_post_llistxattr(res, path, list, size)             \ +  __sanitizer_syscall_post_impl_llistxattr(                                    \ +      res, (long long)(path), (long long)(list), (long long)(size)) +#define __sanitizer_syscall_pre_flistxattr(fd, list, size)                     \ +  __sanitizer_syscall_pre_impl_flistxattr((long long)(fd), (long long)(list),  \ +                                          (long long)(size)) +#define __sanitizer_syscall_post_flistxattr(res, fd, list, size)               \ +  __sanitizer_syscall_post_impl_flistxattr(                                    \ +      res, (long long)(fd), (long long)(list), (long long)(size)) +#define __sanitizer_syscall_pre_removexattr(path, name)                        \ +  __sanitizer_syscall_pre_impl_removexattr((long long)(path), (long long)(name)) +#define __sanitizer_syscall_post_removexattr(res, path, name)                  \ +  __sanitizer_syscall_post_impl_removexattr(res, (long long)(path),            \ +                                            (long long)(name)) +#define __sanitizer_syscall_pre_lremovexattr(path, name)                       \ +  __sanitizer_syscall_pre_impl_lremovexattr((long long)(path),                 \ +                                            (long long)(name)) +#define __sanitizer_syscall_post_lremovexattr(res, path, name)                 \ +  __sanitizer_syscall_post_impl_lremovexattr(res, (long long)(path),           \ +                                             (long long)(name)) +#define __sanitizer_syscall_pre_fremovexattr(fd, name)                         \ +  __sanitizer_syscall_pre_impl_fremovexattr((long long)(fd), (long long)(name)) +#define __sanitizer_syscall_post_fremovexattr(res, fd, name)                   \ +  __sanitizer_syscall_post_impl_fremovexattr(res, (long long)(fd),             \ +                                             (long long)(name)) +#define __sanitizer_syscall_pre_compat_50___stat30(path, ub)                   \ +  __sanitizer_syscall_pre_impl_compat_50___stat30((long long)(path),           \ +                                                  (long long)(ub)) +#define __sanitizer_syscall_post_compat_50___stat30(res, path, ub)             \ +  __sanitizer_syscall_post_impl_compat_50___stat30(res, (long long)(path),     \ +                                                   (long long)(ub)) +#define __sanitizer_syscall_pre_compat_50___fstat30(fd, sb)                    \ +  __sanitizer_syscall_pre_impl_compat_50___fstat30((long long)(fd),            \ +                                                   (long long)(sb)) +#define __sanitizer_syscall_post_compat_50___fstat30(res, fd, sb)              \ +  __sanitizer_syscall_post_impl_compat_50___fstat30(res, (long long)(fd),      \ +                                                    (long long)(sb)) +#define __sanitizer_syscall_pre_compat_50___lstat30(path, ub)                  \ +  __sanitizer_syscall_pre_impl_compat_50___lstat30((long long)(path),          \ +                                                   (long long)(ub)) +#define __sanitizer_syscall_post_compat_50___lstat30(res, path, ub)            \ +  __sanitizer_syscall_post_impl_compat_50___lstat30(res, (long long)(path),    \ +                                                    (long long)(ub)) +#define __sanitizer_syscall_pre___getdents30(fd, buf, count)                   \ +  __sanitizer_syscall_pre_impl___getdents30((long long)(fd), (long long)(buf), \ +                                            (long long)(count)) +#define __sanitizer_syscall_post___getdents30(res, fd, buf, count)             \ +  __sanitizer_syscall_post_impl___getdents30(                                  \ +      res, (long long)(fd), (long long)(buf), (long long)(count)) +#define __sanitizer_syscall_pre_posix_fadvise()                                \ +  __sanitizer_syscall_pre_impl_posix_fadvise((long long)()) +#define __sanitizer_syscall_post_posix_fadvise(res)                            \ +  __sanitizer_syscall_post_impl_posix_fadvise(res, (long long)()) +#define __sanitizer_syscall_pre_compat_30___fhstat30(fhp, sb)                  \ +  __sanitizer_syscall_pre_impl_compat_30___fhstat30((long long)(fhp),          \ +                                                    (long long)(sb)) +#define __sanitizer_syscall_post_compat_30___fhstat30(res, fhp, sb)            \ +  __sanitizer_syscall_post_impl_compat_30___fhstat30(res, (long long)(fhp),    \ +                                                     (long long)(sb)) +#define __sanitizer_syscall_pre_compat_50___ntp_gettime30(ntvp)                \ +  __sanitizer_syscall_pre_impl_compat_50___ntp_gettime30((long long)(ntvp)) +#define __sanitizer_syscall_post_compat_50___ntp_gettime30(res, ntvp)          \ +  __sanitizer_syscall_post_impl_compat_50___ntp_gettime30(res,                 \ +                                                          (long long)(ntvp)) +#define __sanitizer_syscall_pre___socket30(domain, type, protocol)             \ +  __sanitizer_syscall_pre_impl___socket30(                                     \ +      (long long)(domain), (long long)(type), (long long)(protocol)) +#define __sanitizer_syscall_post___socket30(res, domain, type, protocol)       \ +  __sanitizer_syscall_post_impl___socket30(                                    \ +      res, (long long)(domain), (long long)(type), (long long)(protocol)) +#define __sanitizer_syscall_pre___getfh30(fname, fhp, fh_size)                 \ +  __sanitizer_syscall_pre_impl___getfh30((long long)(fname), (long long)(fhp), \ +                                         (long long)(fh_size)) +#define __sanitizer_syscall_post___getfh30(res, fname, fhp, fh_size)           \ +  __sanitizer_syscall_post_impl___getfh30(                                     \ +      res, (long long)(fname), (long long)(fhp), (long long)(fh_size)) +#define __sanitizer_syscall_pre___fhopen40(fhp, fh_size, flags)                \ +  __sanitizer_syscall_pre_impl___fhopen40(                                     \ +      (long long)(fhp), (long long)(fh_size), (long long)(flags)) +#define __sanitizer_syscall_post___fhopen40(res, fhp, fh_size, flags)          \ +  __sanitizer_syscall_post_impl___fhopen40(                                    \ +      res, (long long)(fhp), (long long)(fh_size), (long long)(flags)) +#define __sanitizer_syscall_pre___fhstatvfs140(fhp, fh_size, buf, flags)       \ +  __sanitizer_syscall_pre_impl___fhstatvfs140(                                 \ +      (long long)(fhp), (long long)(fh_size), (long long)(buf),                \ +      (long long)(flags)) +#define __sanitizer_syscall_post___fhstatvfs140(res, fhp, fh_size, buf, flags) \ +  __sanitizer_syscall_post_impl___fhstatvfs140(                                \ +      res, (long long)(fhp), (long long)(fh_size), (long long)(buf),           \ +      (long long)(flags)) +#define __sanitizer_syscall_pre_compat_50___fhstat40(fhp, fh_size, sb)         \ +  __sanitizer_syscall_pre_impl_compat_50___fhstat40(                           \ +      (long long)(fhp), (long long)(fh_size), (long long)(sb)) +#define __sanitizer_syscall_post_compat_50___fhstat40(res, fhp, fh_size, sb)   \ +  __sanitizer_syscall_post_impl_compat_50___fhstat40(                          \ +      res, (long long)(fhp), (long long)(fh_size), (long long)(sb)) +#define __sanitizer_syscall_pre_aio_cancel(fildes, aiocbp)                     \ +  __sanitizer_syscall_pre_impl_aio_cancel((long long)(fildes),                 \ +                                          (long long)(aiocbp)) +#define __sanitizer_syscall_post_aio_cancel(res, fildes, aiocbp)               \ +  __sanitizer_syscall_post_impl_aio_cancel(res, (long long)(fildes),           \ +                                           (long long)(aiocbp)) +#define __sanitizer_syscall_pre_aio_error(aiocbp)                              \ +  __sanitizer_syscall_pre_impl_aio_error((long long)(aiocbp)) +#define __sanitizer_syscall_post_aio_error(res, aiocbp)                        \ +  __sanitizer_syscall_post_impl_aio_error(res, (long long)(aiocbp)) +#define __sanitizer_syscall_pre_aio_fsync(op, aiocbp)                          \ +  __sanitizer_syscall_pre_impl_aio_fsync((long long)(op), (long long)(aiocbp)) +#define __sanitizer_syscall_post_aio_fsync(res, op, aiocbp)                    \ +  __sanitizer_syscall_post_impl_aio_fsync(res, (long long)(op),                \ +                                          (long long)(aiocbp)) +#define __sanitizer_syscall_pre_aio_read(aiocbp)                               \ +  __sanitizer_syscall_pre_impl_aio_read((long long)(aiocbp)) +#define __sanitizer_syscall_post_aio_read(res, aiocbp)                         \ +  __sanitizer_syscall_post_impl_aio_read(res, (long long)(aiocbp)) +#define __sanitizer_syscall_pre_aio_return(aiocbp)                             \ +  __sanitizer_syscall_pre_impl_aio_return((long long)(aiocbp)) +#define __sanitizer_syscall_post_aio_return(res, aiocbp)                       \ +  __sanitizer_syscall_post_impl_aio_return(res, (long long)(aiocbp)) +#define __sanitizer_syscall_pre_compat_50_aio_suspend(list, nent, timeout)     \ +  __sanitizer_syscall_pre_impl_compat_50_aio_suspend(                          \ +      (long long)(list), (long long)(nent), (long long)(timeout)) +#define __sanitizer_syscall_post_compat_50_aio_suspend(res, list, nent,        \ +                                                       timeout)                \ +  __sanitizer_syscall_post_impl_compat_50_aio_suspend(                         \ +      res, (long long)(list), (long long)(nent), (long long)(timeout)) +#define __sanitizer_syscall_pre_aio_write(aiocbp)                              \ +  __sanitizer_syscall_pre_impl_aio_write((long long)(aiocbp)) +#define __sanitizer_syscall_post_aio_write(res, aiocbp)                        \ +  __sanitizer_syscall_post_impl_aio_write(res, (long long)(aiocbp)) +#define __sanitizer_syscall_pre_lio_listio(mode, list, nent, sig)              \ +  __sanitizer_syscall_pre_impl_lio_listio((long long)(mode),                   \ +                                          (long long)(list),                   \ +                                          (long long)(nent), (long long)(sig)) +#define __sanitizer_syscall_post_lio_listio(res, mode, list, nent, sig)        \ +  __sanitizer_syscall_post_impl_lio_listio(                                    \ +      res, (long long)(mode), (long long)(list), (long long)(nent),            \ +      (long long)(sig)) +/* syscall 407 has been skipped */ +/* syscall 408 has been skipped */ +/* syscall 409 has been skipped */ +#define __sanitizer_syscall_pre___mount50(type, path, flags, data, data_len)   \ +  __sanitizer_syscall_pre_impl___mount50(                                      \ +      (long long)(type), (long long)(path), (long long)(flags),                \ +      (long long)(data), (long long)(data_len)) +#define __sanitizer_syscall_post___mount50(res, type, path, flags, data,       \ +                                           data_len)                           \ +  __sanitizer_syscall_post_impl___mount50(                                     \ +      res, (long long)(type), (long long)(path), (long long)(flags),           \ +      (long long)(data), (long long)(data_len)) +#define __sanitizer_syscall_pre_mremap(old_address, old_size, new_address,     \ +                                       new_size, flags)                        \ +  __sanitizer_syscall_pre_impl_mremap(                                         \ +      (long long)(old_address), (long long)(old_size),                         \ +      (long long)(new_address), (long long)(new_size), (long long)(flags)) +#define __sanitizer_syscall_post_mremap(res, old_address, old_size,            \ +                                        new_address, new_size, flags)          \ +  __sanitizer_syscall_post_impl_mremap(                                        \ +      res, (long long)(old_address), (long long)(old_size),                    \ +      (long long)(new_address), (long long)(new_size), (long long)(flags)) +#define __sanitizer_syscall_pre_pset_create(psid)                              \ +  __sanitizer_syscall_pre_impl_pset_create((long long)(psid)) +#define __sanitizer_syscall_post_pset_create(res, psid)                        \ +  __sanitizer_syscall_post_impl_pset_create(res, (long long)(psid)) +#define __sanitizer_syscall_pre_pset_destroy(psid)                             \ +  __sanitizer_syscall_pre_impl_pset_destroy((long long)(psid)) +#define __sanitizer_syscall_post_pset_destroy(res, psid)                       \ +  __sanitizer_syscall_post_impl_pset_destroy(res, (long long)(psid)) +#define __sanitizer_syscall_pre_pset_assign(psid, cpuid, opsid)                \ +  __sanitizer_syscall_pre_impl_pset_assign(                                    \ +      (long long)(psid), (long long)(cpuid), (long long)(opsid)) +#define __sanitizer_syscall_post_pset_assign(res, psid, cpuid, opsid)          \ +  __sanitizer_syscall_post_impl_pset_assign(                                   \ +      res, (long long)(psid), (long long)(cpuid), (long long)(opsid)) +#define __sanitizer_syscall_pre__pset_bind(idtype, first_id, second_id, psid,  \ +                                           opsid)                              \ +  __sanitizer_syscall_pre_impl__pset_bind(                                     \ +      (long long)(idtype), (long long)(first_id), (long long)(second_id),      \ +      (long long)(psid), (long long)(opsid)) +#define __sanitizer_syscall_post__pset_bind(res, idtype, first_id, second_id,  \ +                                            psid, opsid)                       \ +  __sanitizer_syscall_post_impl__pset_bind(                                    \ +      res, (long long)(idtype), (long long)(first_id), (long long)(second_id), \ +      (long long)(psid), (long long)(opsid)) +#define __sanitizer_syscall_pre___posix_fadvise50(fd, PAD, offset, len,        \ +                                                  advice)                      \ +  __sanitizer_syscall_pre_impl___posix_fadvise50(                              \ +      (long long)(fd), (long long)(PAD), (long long)(offset),                  \ +      (long long)(len), (long long)(advice)) +#define __sanitizer_syscall_post___posix_fadvise50(res, fd, PAD, offset, len,  \ +                                                   advice)                     \ +  __sanitizer_syscall_post_impl___posix_fadvise50(                             \ +      res, (long long)(fd), (long long)(PAD), (long long)(offset),             \ +      (long long)(len), (long long)(advice)) +#define __sanitizer_syscall_pre___select50(nd, in, ou, ex, tv)                 \ +  __sanitizer_syscall_pre_impl___select50((long long)(nd), (long long)(in),    \ +                                          (long long)(ou), (long long)(ex),    \ +                                          (long long)(tv)) +#define __sanitizer_syscall_post___select50(res, nd, in, ou, ex, tv)           \ +  __sanitizer_syscall_post_impl___select50(res, (long long)(nd),               \ +                                           (long long)(in), (long long)(ou),   \ +                                           (long long)(ex), (long long)(tv)) +#define __sanitizer_syscall_pre___gettimeofday50(tp, tzp)                      \ +  __sanitizer_syscall_pre_impl___gettimeofday50((long long)(tp),               \ +                                                (long long)(tzp)) +#define __sanitizer_syscall_post___gettimeofday50(res, tp, tzp)                \ +  __sanitizer_syscall_post_impl___gettimeofday50(res, (long long)(tp),         \ +                                                 (long long)(tzp)) +#define __sanitizer_syscall_pre___settimeofday50(tv, tzp)                      \ +  __sanitizer_syscall_pre_impl___settimeofday50((long long)(tv),               \ +                                                (long long)(tzp)) +#define __sanitizer_syscall_post___settimeofday50(res, tv, tzp)                \ +  __sanitizer_syscall_post_impl___settimeofday50(res, (long long)(tv),         \ +                                                 (long long)(tzp)) +#define __sanitizer_syscall_pre___utimes50(path, tptr)                         \ +  __sanitizer_syscall_pre_impl___utimes50((long long)(path), (long long)(tptr)) +#define __sanitizer_syscall_post___utimes50(res, path, tptr)                   \ +  __sanitizer_syscall_post_impl___utimes50(res, (long long)(path),             \ +                                           (long long)(tptr)) +#define __sanitizer_syscall_pre___adjtime50(delta, olddelta)                   \ +  __sanitizer_syscall_pre_impl___adjtime50((long long)(delta),                 \ +                                           (long long)(olddelta)) +#define __sanitizer_syscall_post___adjtime50(res, delta, olddelta)             \ +  __sanitizer_syscall_post_impl___adjtime50(res, (long long)(delta),           \ +                                            (long long)(olddelta)) +#define __sanitizer_syscall_pre___lfs_segwait50(fsidp, tv)                     \ +  __sanitizer_syscall_pre_impl___lfs_segwait50((long long)(fsidp),             \ +                                               (long long)(tv)) +#define __sanitizer_syscall_post___lfs_segwait50(res, fsidp, tv)               \ +  __sanitizer_syscall_post_impl___lfs_segwait50(res, (long long)(fsidp),       \ +                                                (long long)(tv)) +#define __sanitizer_syscall_pre___futimes50(fd, tptr)                          \ +  __sanitizer_syscall_pre_impl___futimes50((long long)(fd), (long long)(tptr)) +#define __sanitizer_syscall_post___futimes50(res, fd, tptr)                    \ +  __sanitizer_syscall_post_impl___futimes50(res, (long long)(fd),              \ +                                            (long long)(tptr)) +#define __sanitizer_syscall_pre___lutimes50(path, tptr)                        \ +  __sanitizer_syscall_pre_impl___lutimes50((long long)(path), (long long)(tptr)) +#define __sanitizer_syscall_post___lutimes50(res, path, tptr)                  \ +  __sanitizer_syscall_post_impl___lutimes50(res, (long long)(path),            \ +                                            (long long)(tptr)) +#define __sanitizer_syscall_pre___setitimer50(which, itv, oitv)                \ +  __sanitizer_syscall_pre_impl___setitimer50(                                  \ +      (long long)(which), (long long)(itv), (long long)(oitv)) +#define __sanitizer_syscall_post___setitimer50(res, which, itv, oitv)          \ +  __sanitizer_syscall_post_impl___setitimer50(                                 \ +      res, (long long)(which), (long long)(itv), (long long)(oitv)) +#define __sanitizer_syscall_pre___getitimer50(which, itv)                      \ +  __sanitizer_syscall_pre_impl___getitimer50((long long)(which),               \ +                                             (long long)(itv)) +#define __sanitizer_syscall_post___getitimer50(res, which, itv)                \ +  __sanitizer_syscall_post_impl___getitimer50(res, (long long)(which),         \ +                                              (long long)(itv)) +#define __sanitizer_syscall_pre___clock_gettime50(clock_id, tp)                \ +  __sanitizer_syscall_pre_impl___clock_gettime50((long long)(clock_id),        \ +                                                 (long long)(tp)) +#define __sanitizer_syscall_post___clock_gettime50(res, clock_id, tp)          \ +  __sanitizer_syscall_post_impl___clock_gettime50(res, (long long)(clock_id),  \ +                                                  (long long)(tp)) +#define __sanitizer_syscall_pre___clock_settime50(clock_id, tp)                \ +  __sanitizer_syscall_pre_impl___clock_settime50((long long)(clock_id),        \ +                                                 (long long)(tp)) +#define __sanitizer_syscall_post___clock_settime50(res, clock_id, tp)          \ +  __sanitizer_syscall_post_impl___clock_settime50(res, (long long)(clock_id),  \ +                                                  (long long)(tp)) +#define __sanitizer_syscall_pre___clock_getres50(clock_id, tp)                 \ +  __sanitizer_syscall_pre_impl___clock_getres50((long long)(clock_id),         \ +                                                (long long)(tp)) +#define __sanitizer_syscall_post___clock_getres50(res, clock_id, tp)           \ +  __sanitizer_syscall_post_impl___clock_getres50(res, (long long)(clock_id),   \ +                                                 (long long)(tp)) +#define __sanitizer_syscall_pre___nanosleep50(rqtp, rmtp)                      \ +  __sanitizer_syscall_pre_impl___nanosleep50((long long)(rqtp),                \ +                                             (long long)(rmtp)) +#define __sanitizer_syscall_post___nanosleep50(res, rqtp, rmtp)                \ +  __sanitizer_syscall_post_impl___nanosleep50(res, (long long)(rqtp),          \ +                                              (long long)(rmtp)) +#define __sanitizer_syscall_pre_____sigtimedwait50(set, info, timeout)         \ +  __sanitizer_syscall_pre_impl_____sigtimedwait50(                             \ +      (long long)(set), (long long)(info), (long long)(timeout)) +#define __sanitizer_syscall_post_____sigtimedwait50(res, set, info, timeout)   \ +  __sanitizer_syscall_post_impl_____sigtimedwait50(                            \ +      res, (long long)(set), (long long)(info), (long long)(timeout)) +#define __sanitizer_syscall_pre___mq_timedsend50(mqdes, msg_ptr, msg_len,      \ +                                                 msg_prio, abs_timeout)        \ +  __sanitizer_syscall_pre_impl___mq_timedsend50(                               \ +      (long long)(mqdes), (long long)(msg_ptr), (long long)(msg_len),          \ +      (long long)(msg_prio), (long long)(abs_timeout)) +#define __sanitizer_syscall_post___mq_timedsend50(                             \ +    res, mqdes, msg_ptr, msg_len, msg_prio, abs_timeout)                       \ +  __sanitizer_syscall_post_impl___mq_timedsend50(                              \ +      res, (long long)(mqdes), (long long)(msg_ptr), (long long)(msg_len),     \ +      (long long)(msg_prio), (long long)(abs_timeout)) +#define __sanitizer_syscall_pre___mq_timedreceive50(mqdes, msg_ptr, msg_len,   \ +                                                    msg_prio, abs_timeout)     \ +  __sanitizer_syscall_pre_impl___mq_timedreceive50(                            \ +      (long long)(mqdes), (long long)(msg_ptr), (long long)(msg_len),          \ +      (long long)(msg_prio), (long long)(abs_timeout)) +#define __sanitizer_syscall_post___mq_timedreceive50(                          \ +    res, mqdes, msg_ptr, msg_len, msg_prio, abs_timeout)                       \ +  __sanitizer_syscall_post_impl___mq_timedreceive50(                           \ +      res, (long long)(mqdes), (long long)(msg_ptr), (long long)(msg_len),     \ +      (long long)(msg_prio), (long long)(abs_timeout)) +#define __sanitizer_syscall_pre_compat_60__lwp_park(ts, unpark, hint,          \ +                                                    unparkhint)                \ +  __sanitizer_syscall_pre_impl_compat_60__lwp_park(                            \ +      (long long)(ts), (long long)(unpark), (long long)(hint),                 \ +      (long long)(unparkhint)) +#define __sanitizer_syscall_post_compat_60__lwp_park(res, ts, unpark, hint,    \ +                                                     unparkhint)               \ +  __sanitizer_syscall_post_impl_compat_60__lwp_park(                           \ +      res, (long long)(ts), (long long)(unpark), (long long)(hint),            \ +      (long long)(unparkhint)) +#define __sanitizer_syscall_pre___kevent50(fd, changelist, nchanges,           \ +                                           eventlist, nevents, timeout)        \ +  __sanitizer_syscall_pre_impl___kevent50(                                     \ +      (long long)(fd), (long long)(changelist), (long long)(nchanges),         \ +      (long long)(eventlist), (long long)(nevents), (long long)(timeout)) +#define __sanitizer_syscall_post___kevent50(res, fd, changelist, nchanges,     \ +                                            eventlist, nevents, timeout)       \ +  __sanitizer_syscall_post_impl___kevent50(                                    \ +      res, (long long)(fd), (long long)(changelist), (long long)(nchanges),    \ +      (long long)(eventlist), (long long)(nevents), (long long)(timeout)) +#define __sanitizer_syscall_pre___pselect50(nd, in, ou, ex, ts, mask)          \ +  __sanitizer_syscall_pre_impl___pselect50((long long)(nd), (long long)(in),   \ +                                           (long long)(ou), (long long)(ex),   \ +                                           (long long)(ts), (long long)(mask)) +#define __sanitizer_syscall_post___pselect50(res, nd, in, ou, ex, ts, mask)    \ +  __sanitizer_syscall_post_impl___pselect50(                                   \ +      res, (long long)(nd), (long long)(in), (long long)(ou), (long long)(ex), \ +      (long long)(ts), (long long)(mask)) +#define __sanitizer_syscall_pre___pollts50(fds, nfds, ts, mask)                \ +  __sanitizer_syscall_pre_impl___pollts50((long long)(fds), (long long)(nfds), \ +                                          (long long)(ts), (long long)(mask)) +#define __sanitizer_syscall_post___pollts50(res, fds, nfds, ts, mask)          \ +  __sanitizer_syscall_post_impl___pollts50(res, (long long)(fds),              \ +                                           (long long)(nfds), (long long)(ts), \ +                                           (long long)(mask)) +#define __sanitizer_syscall_pre___aio_suspend50(list, nent, timeout)           \ +  __sanitizer_syscall_pre_impl___aio_suspend50(                                \ +      (long long)(list), (long long)(nent), (long long)(timeout)) +#define __sanitizer_syscall_post___aio_suspend50(res, list, nent, timeout)     \ +  __sanitizer_syscall_post_impl___aio_suspend50(                               \ +      res, (long long)(list), (long long)(nent), (long long)(timeout)) +#define __sanitizer_syscall_pre___stat50(path, ub)                             \ +  __sanitizer_syscall_pre_impl___stat50((long long)(path), (long long)(ub)) +#define __sanitizer_syscall_post___stat50(res, path, ub)                       \ +  __sanitizer_syscall_post_impl___stat50(res, (long long)(path),               \ +                                         (long long)(ub)) +#define __sanitizer_syscall_pre___fstat50(fd, sb)                              \ +  __sanitizer_syscall_pre_impl___fstat50((long long)(fd), (long long)(sb)) +#define __sanitizer_syscall_post___fstat50(res, fd, sb)                        \ +  __sanitizer_syscall_post_impl___fstat50(res, (long long)(fd), (long long)(sb)) +#define __sanitizer_syscall_pre___lstat50(path, ub)                            \ +  __sanitizer_syscall_pre_impl___lstat50((long long)(path), (long long)(ub)) +#define __sanitizer_syscall_post___lstat50(res, path, ub)                      \ +  __sanitizer_syscall_post_impl___lstat50(res, (long long)(path),              \ +                                          (long long)(ub)) +#define __sanitizer_syscall_pre_____semctl50(semid, semnum, cmd, arg)          \ +  __sanitizer_syscall_pre_impl_____semctl50(                                   \ +      (long long)(semid), (long long)(semnum), (long long)(cmd),               \ +      (long long)(arg)) +#define __sanitizer_syscall_post_____semctl50(res, semid, semnum, cmd, arg)    \ +  __sanitizer_syscall_post_impl_____semctl50(                                  \ +      res, (long long)(semid), (long long)(semnum), (long long)(cmd),          \ +      (long long)(arg)) +#define __sanitizer_syscall_pre___shmctl50(shmid, cmd, buf)                    \ +  __sanitizer_syscall_pre_impl___shmctl50((long long)(shmid),                  \ +                                          (long long)(cmd), (long long)(buf)) +#define __sanitizer_syscall_post___shmctl50(res, shmid, cmd, buf)              \ +  __sanitizer_syscall_post_impl___shmctl50(res, (long long)(shmid),            \ +                                           (long long)(cmd), (long long)(buf)) +#define __sanitizer_syscall_pre___msgctl50(msqid, cmd, buf)                    \ +  __sanitizer_syscall_pre_impl___msgctl50((long long)(msqid),                  \ +                                          (long long)(cmd), (long long)(buf)) +#define __sanitizer_syscall_post___msgctl50(res, msqid, cmd, buf)              \ +  __sanitizer_syscall_post_impl___msgctl50(res, (long long)(msqid),            \ +                                           (long long)(cmd), (long long)(buf)) +#define __sanitizer_syscall_pre___getrusage50(who, rusage)                     \ +  __sanitizer_syscall_pre_impl___getrusage50((long long)(who),                 \ +                                             (long long)(rusage)) +#define __sanitizer_syscall_post___getrusage50(res, who, rusage)               \ +  __sanitizer_syscall_post_impl___getrusage50(res, (long long)(who),           \ +                                              (long long)(rusage)) +#define __sanitizer_syscall_pre___timer_settime50(timerid, flags, value,       \ +                                                  ovalue)                      \ +  __sanitizer_syscall_pre_impl___timer_settime50(                              \ +      (long long)(timerid), (long long)(flags), (long long)(value),            \ +      (long long)(ovalue)) +#define __sanitizer_syscall_post___timer_settime50(res, timerid, flags, value, \ +                                                   ovalue)                     \ +  __sanitizer_syscall_post_impl___timer_settime50(                             \ +      res, (long long)(timerid), (long long)(flags), (long long)(value),       \ +      (long long)(ovalue)) +#define __sanitizer_syscall_pre___timer_gettime50(timerid, value)              \ +  __sanitizer_syscall_pre_impl___timer_gettime50((long long)(timerid),         \ +                                                 (long long)(value)) +#define __sanitizer_syscall_post___timer_gettime50(res, timerid, value)        \ +  __sanitizer_syscall_post_impl___timer_gettime50(res, (long long)(timerid),   \ +                                                  (long long)(value)) +#if defined(NTP) || !defined(_KERNEL_OPT) +#define __sanitizer_syscall_pre___ntp_gettime50(ntvp)                          \ +  __sanitizer_syscall_pre_impl___ntp_gettime50((long long)(ntvp)) +#define __sanitizer_syscall_post___ntp_gettime50(res, ntvp)                    \ +  __sanitizer_syscall_post_impl___ntp_gettime50(res, (long long)(ntvp)) +#else +/* syscall 448 has been skipped */ +#endif +#define __sanitizer_syscall_pre___wait450(pid, status, options, rusage)        \ +  __sanitizer_syscall_pre_impl___wait450(                                      \ +      (long long)(pid), (long long)(status), (long long)(options),             \ +      (long long)(rusage)) +#define __sanitizer_syscall_post___wait450(res, pid, status, options, rusage)  \ +  __sanitizer_syscall_post_impl___wait450(                                     \ +      res, (long long)(pid), (long long)(status), (long long)(options),        \ +      (long long)(rusage)) +#define __sanitizer_syscall_pre___mknod50(path, mode, dev)                     \ +  __sanitizer_syscall_pre_impl___mknod50((long long)(path), (long long)(mode), \ +                                         (long long)(dev)) +#define __sanitizer_syscall_post___mknod50(res, path, mode, dev)               \ +  __sanitizer_syscall_post_impl___mknod50(res, (long long)(path),              \ +                                          (long long)(mode), (long long)(dev)) +#define __sanitizer_syscall_pre___fhstat50(fhp, fh_size, sb)                   \ +  __sanitizer_syscall_pre_impl___fhstat50(                                     \ +      (long long)(fhp), (long long)(fh_size), (long long)(sb)) +#define __sanitizer_syscall_post___fhstat50(res, fhp, fh_size, sb)             \ +  __sanitizer_syscall_post_impl___fhstat50(                                    \ +      res, (long long)(fhp), (long long)(fh_size), (long long)(sb)) +/* syscall 452 has been skipped */ +#define __sanitizer_syscall_pre_pipe2(fildes, flags)                           \ +  __sanitizer_syscall_pre_impl_pipe2((long long)(fildes), (long long)(flags)) +#define __sanitizer_syscall_post_pipe2(res, fildes, flags)                     \ +  __sanitizer_syscall_post_impl_pipe2(res, (long long)(fildes),                \ +                                      (long long)(flags)) +#define __sanitizer_syscall_pre_dup3(from, to, flags)                          \ +  __sanitizer_syscall_pre_impl_dup3((long long)(from), (long long)(to),        \ +                                    (long long)(flags)) +#define __sanitizer_syscall_post_dup3(res, from, to, flags)                    \ +  __sanitizer_syscall_post_impl_dup3(res, (long long)(from), (long long)(to),  \ +                                     (long long)(flags)) +#define __sanitizer_syscall_pre_kqueue1(flags)                                 \ +  __sanitizer_syscall_pre_impl_kqueue1((long long)(flags)) +#define __sanitizer_syscall_post_kqueue1(res, flags)                           \ +  __sanitizer_syscall_post_impl_kqueue1(res, (long long)(flags)) +#define __sanitizer_syscall_pre_paccept(s, name, anamelen, mask, flags)        \ +  __sanitizer_syscall_pre_impl_paccept((long long)(s), (long long)(name),      \ +                                       (long long)(anamelen),                  \ +                                       (long long)(mask), (long long)(flags)) +#define __sanitizer_syscall_post_paccept(res, s, name, anamelen, mask, flags)  \ +  __sanitizer_syscall_post_impl_paccept(                                       \ +      res, (long long)(s), (long long)(name), (long long)(anamelen),           \ +      (long long)(mask), (long long)(flags)) +#define __sanitizer_syscall_pre_linkat(fd1, name1, fd2, name2, flags)          \ +  __sanitizer_syscall_pre_impl_linkat((long long)(fd1), (long long)(name1),    \ +                                      (long long)(fd2), (long long)(name2),    \ +                                      (long long)(flags)) +#define __sanitizer_syscall_post_linkat(res, fd1, name1, fd2, name2, flags)    \ +  __sanitizer_syscall_post_impl_linkat(res, (long long)(fd1),                  \ +                                       (long long)(name1), (long long)(fd2),   \ +                                       (long long)(name2), (long long)(flags)) +#define __sanitizer_syscall_pre_renameat(fromfd, from, tofd, to)               \ +  __sanitizer_syscall_pre_impl_renameat((long long)(fromfd),                   \ +                                        (long long)(from), (long long)(tofd),  \ +                                        (long long)(to)) +#define __sanitizer_syscall_post_renameat(res, fromfd, from, tofd, to)         \ +  __sanitizer_syscall_post_impl_renameat(res, (long long)(fromfd),             \ +                                         (long long)(from), (long long)(tofd), \ +                                         (long long)(to)) +#define __sanitizer_syscall_pre_mkfifoat(fd, path, mode)                       \ +  __sanitizer_syscall_pre_impl_mkfifoat((long long)(fd), (long long)(path),    \ +                                        (long long)(mode)) +#define __sanitizer_syscall_post_mkfifoat(res, fd, path, mode)                 \ +  __sanitizer_syscall_post_impl_mkfifoat(res, (long long)(fd),                 \ +                                         (long long)(path), (long long)(mode)) +#define __sanitizer_syscall_pre_mknodat(fd, path, mode, PAD, dev)              \ +  __sanitizer_syscall_pre_impl_mknodat((long long)(fd), (long long)(path),     \ +                                       (long long)(mode), (long long)(PAD),    \ +                                       (long long)(dev)) +#define __sanitizer_syscall_post_mknodat(res, fd, path, mode, PAD, dev)        \ +  __sanitizer_syscall_post_impl_mknodat(res, (long long)(fd),                  \ +                                        (long long)(path), (long long)(mode),  \ +                                        (long long)(PAD), (long long)(dev)) +#define __sanitizer_syscall_pre_mkdirat(fd, path, mode)                        \ +  __sanitizer_syscall_pre_impl_mkdirat((long long)(fd), (long long)(path),     \ +                                       (long long)(mode)) +#define __sanitizer_syscall_post_mkdirat(res, fd, path, mode)                  \ +  __sanitizer_syscall_post_impl_mkdirat(res, (long long)(fd),                  \ +                                        (long long)(path), (long long)(mode)) +#define __sanitizer_syscall_pre_faccessat(fd, path, amode, flag)               \ +  __sanitizer_syscall_pre_impl_faccessat((long long)(fd), (long long)(path),   \ +                                         (long long)(amode),                   \ +                                         (long long)(flag)) +#define __sanitizer_syscall_post_faccessat(res, fd, path, amode, flag)         \ +  __sanitizer_syscall_post_impl_faccessat(                                     \ +      res, (long long)(fd), (long long)(path), (long long)(amode),             \ +      (long long)(flag)) +#define __sanitizer_syscall_pre_fchmodat(fd, path, mode, flag)                 \ +  __sanitizer_syscall_pre_impl_fchmodat((long long)(fd), (long long)(path),    \ +                                        (long long)(mode), (long long)(flag)) +#define __sanitizer_syscall_post_fchmodat(res, fd, path, mode, flag)           \ +  __sanitizer_syscall_post_impl_fchmodat(res, (long long)(fd),                 \ +                                         (long long)(path), (long long)(mode), \ +                                         (long long)(flag)) +#define __sanitizer_syscall_pre_fchownat(fd, path, owner, group, flag)         \ +  __sanitizer_syscall_pre_impl_fchownat((long long)(fd), (long long)(path),    \ +                                        (long long)(owner),                    \ +                                        (long long)(group), (long long)(flag)) +#define __sanitizer_syscall_post_fchownat(res, fd, path, owner, group, flag)   \ +  __sanitizer_syscall_post_impl_fchownat(                                      \ +      res, (long long)(fd), (long long)(path), (long long)(owner),             \ +      (long long)(group), (long long)(flag)) +#define __sanitizer_syscall_pre_fexecve(fd, argp, envp)                        \ +  __sanitizer_syscall_pre_impl_fexecve((long long)(fd), (long long)(argp),     \ +                                       (long long)(envp)) +#define __sanitizer_syscall_post_fexecve(res, fd, argp, envp)                  \ +  __sanitizer_syscall_post_impl_fexecve(res, (long long)(fd),                  \ +                                        (long long)(argp), (long long)(envp)) +#define __sanitizer_syscall_pre_fstatat(fd, path, buf, flag)                   \ +  __sanitizer_syscall_pre_impl_fstatat((long long)(fd), (long long)(path),     \ +                                       (long long)(buf), (long long)(flag)) +#define __sanitizer_syscall_post_fstatat(res, fd, path, buf, flag)             \ +  __sanitizer_syscall_post_impl_fstatat(res, (long long)(fd),                  \ +                                        (long long)(path), (long long)(buf),   \ +                                        (long long)(flag)) +#define __sanitizer_syscall_pre_utimensat(fd, path, tptr, flag)                \ +  __sanitizer_syscall_pre_impl_utimensat((long long)(fd), (long long)(path),   \ +                                         (long long)(tptr), (long long)(flag)) +#define __sanitizer_syscall_post_utimensat(res, fd, path, tptr, flag)          \ +  __sanitizer_syscall_post_impl_utimensat(                                     \ +      res, (long long)(fd), (long long)(path), (long long)(tptr),              \ +      (long long)(flag)) +#define __sanitizer_syscall_pre_openat(fd, path, oflags, mode)                 \ +  __sanitizer_syscall_pre_impl_openat((long long)(fd), (long long)(path),      \ +                                      (long long)(oflags), (long long)(mode)) +#define __sanitizer_syscall_post_openat(res, fd, path, oflags, mode)           \ +  __sanitizer_syscall_post_impl_openat(res, (long long)(fd),                   \ +                                       (long long)(path), (long long)(oflags), \ +                                       (long long)(mode)) +#define __sanitizer_syscall_pre_readlinkat(fd, path, buf, bufsize)             \ +  __sanitizer_syscall_pre_impl_readlinkat((long long)(fd), (long long)(path),  \ +                                          (long long)(buf),                    \ +                                          (long long)(bufsize)) +#define __sanitizer_syscall_post_readlinkat(res, fd, path, buf, bufsize)       \ +  __sanitizer_syscall_post_impl_readlinkat(                                    \ +      res, (long long)(fd), (long long)(path), (long long)(buf),               \ +      (long long)(bufsize)) +#define __sanitizer_syscall_pre_symlinkat(path1, fd, path2)                    \ +  __sanitizer_syscall_pre_impl_symlinkat((long long)(path1), (long long)(fd),  \ +                                         (long long)(path2)) +#define __sanitizer_syscall_post_symlinkat(res, path1, fd, path2)              \ +  __sanitizer_syscall_post_impl_symlinkat(res, (long long)(path1),             \ +                                          (long long)(fd), (long long)(path2)) +#define __sanitizer_syscall_pre_unlinkat(fd, path, flag)                       \ +  __sanitizer_syscall_pre_impl_unlinkat((long long)(fd), (long long)(path),    \ +                                        (long long)(flag)) +#define __sanitizer_syscall_post_unlinkat(res, fd, path, flag)                 \ +  __sanitizer_syscall_post_impl_unlinkat(res, (long long)(fd),                 \ +                                         (long long)(path), (long long)(flag)) +#define __sanitizer_syscall_pre_futimens(fd, tptr)                             \ +  __sanitizer_syscall_pre_impl_futimens((long long)(fd), (long long)(tptr)) +#define __sanitizer_syscall_post_futimens(res, fd, tptr)                       \ +  __sanitizer_syscall_post_impl_futimens(res, (long long)(fd),                 \ +                                         (long long)(tptr)) +#define __sanitizer_syscall_pre___quotactl(path, args)                         \ +  __sanitizer_syscall_pre_impl___quotactl((long long)(path), (long long)(args)) +#define __sanitizer_syscall_post___quotactl(res, path, args)                   \ +  __sanitizer_syscall_post_impl___quotactl(res, (long long)(path),             \ +                                           (long long)(args)) +#define __sanitizer_syscall_pre_posix_spawn(pid, path, file_actions, attrp,    \ +                                            argv, envp)                        \ +  __sanitizer_syscall_pre_impl_posix_spawn(                                    \ +      (long long)(pid), (long long)(path), (long long)(file_actions),          \ +      (long long)(attrp), (long long)(argv), (long long)(envp)) +#define __sanitizer_syscall_post_posix_spawn(res, pid, path, file_actions,     \ +                                             attrp, argv, envp)                \ +  __sanitizer_syscall_post_impl_posix_spawn(                                   \ +      res, (long long)(pid), (long long)(path), (long long)(file_actions),     \ +      (long long)(attrp), (long long)(argv), (long long)(envp)) +#define __sanitizer_syscall_pre_recvmmsg(s, mmsg, vlen, flags, timeout)        \ +  __sanitizer_syscall_pre_impl_recvmmsg((long long)(s), (long long)(mmsg),     \ +                                        (long long)(vlen), (long long)(flags), \ +                                        (long long)(timeout)) +#define __sanitizer_syscall_post_recvmmsg(res, s, mmsg, vlen, flags, timeout)  \ +  __sanitizer_syscall_post_impl_recvmmsg(                                      \ +      res, (long long)(s), (long long)(mmsg), (long long)(vlen),               \ +      (long long)(flags), (long long)(timeout)) +#define __sanitizer_syscall_pre_sendmmsg(s, mmsg, vlen, flags)                 \ +  __sanitizer_syscall_pre_impl_sendmmsg((long long)(s), (long long)(mmsg),     \ +                                        (long long)(vlen), (long long)(flags)) +#define __sanitizer_syscall_post_sendmmsg(res, s, mmsg, vlen, flags)           \ +  __sanitizer_syscall_post_impl_sendmmsg(res, (long long)(s),                  \ +                                         (long long)(mmsg), (long long)(vlen), \ +                                         (long long)(flags)) +#define __sanitizer_syscall_pre_clock_nanosleep(clock_id, flags, rqtp, rmtp)   \ +  __sanitizer_syscall_pre_impl_clock_nanosleep(                                \ +      (long long)(clock_id), (long long)(flags), (long long)(rqtp),            \ +      (long long)(rmtp)) +#define __sanitizer_syscall_post_clock_nanosleep(res, clock_id, flags, rqtp,   \ +                                                 rmtp)                         \ +  __sanitizer_syscall_post_impl_clock_nanosleep(                               \ +      res, (long long)(clock_id), (long long)(flags), (long long)(rqtp),       \ +      (long long)(rmtp)) +#define __sanitizer_syscall_pre____lwp_park60(clock_id, flags, ts, unpark,     \ +                                              hint, unparkhint)                \ +  __sanitizer_syscall_pre_impl____lwp_park60(                                  \ +      (long long)(clock_id), (long long)(flags), (long long)(ts),              \ +      (long long)(unpark), (long long)(hint), (long long)(unparkhint)) +#define __sanitizer_syscall_post____lwp_park60(res, clock_id, flags, ts,       \ +                                               unpark, hint, unparkhint)       \ +  __sanitizer_syscall_post_impl____lwp_park60(                                 \ +      res, (long long)(clock_id), (long long)(flags), (long long)(ts),         \ +      (long long)(unpark), (long long)(hint), (long long)(unparkhint)) +#define __sanitizer_syscall_pre_posix_fallocate(fd, PAD, pos, len)             \ +  __sanitizer_syscall_pre_impl_posix_fallocate(                                \ +      (long long)(fd), (long long)(PAD), (long long)(pos), (long long)(len)) +#define __sanitizer_syscall_post_posix_fallocate(res, fd, PAD, pos, len)       \ +  __sanitizer_syscall_post_impl_posix_fallocate(                               \ +      res, (long long)(fd), (long long)(PAD), (long long)(pos),                \ +      (long long)(len)) +#define __sanitizer_syscall_pre_fdiscard(fd, PAD, pos, len)                    \ +  __sanitizer_syscall_pre_impl_fdiscard((long long)(fd), (long long)(PAD),     \ +                                        (long long)(pos), (long long)(len)) +#define __sanitizer_syscall_post_fdiscard(res, fd, PAD, pos, len)              \ +  __sanitizer_syscall_post_impl_fdiscard(res, (long long)(fd),                 \ +                                         (long long)(PAD), (long long)(pos),   \ +                                         (long long)(len)) +#define __sanitizer_syscall_pre_wait6(idtype, id, status, options, wru, info)  \ +  __sanitizer_syscall_pre_impl_wait6(                                          \ +      (long long)(idtype), (long long)(id), (long long)(status),               \ +      (long long)(options), (long long)(wru), (long long)(info)) +#define __sanitizer_syscall_post_wait6(res, idtype, id, status, options, wru,  \ +                                       info)                                   \ +  __sanitizer_syscall_post_impl_wait6(                                         \ +      res, (long long)(idtype), (long long)(id), (long long)(status),          \ +      (long long)(options), (long long)(wru), (long long)(info)) +#define __sanitizer_syscall_pre_clock_getcpuclockid2(idtype, id, clock_id)     \ +  __sanitizer_syscall_pre_impl_clock_getcpuclockid2(                           \ +      (long long)(idtype), (long long)(id), (long long)(clock_id)) +#define __sanitizer_syscall_post_clock_getcpuclockid2(res, idtype, id,         \ +                                                      clock_id)                \ +  __sanitizer_syscall_post_impl_clock_getcpuclockid2(                          \ +      res, (long long)(idtype), (long long)(id), (long long)(clock_id)) + +#ifdef __cplusplus +extern "C" { +#endif + +// Private declarations. Do not call directly from user code. Use macros above. + +// DO NOT EDIT! THIS FILE HAS BEEN GENERATED! + +void __sanitizer_syscall_pre_impl_syscall(long long code, long long arg0, +                                          long long arg1, long long arg2, +                                          long long arg3, long long arg4, +                                          long long arg5, long long arg6, +                                          long long arg7); +void __sanitizer_syscall_post_impl_syscall(long long res, long long code, +                                           long long arg0, long long arg1, +                                           long long arg2, long long arg3, +                                           long long arg4, long long arg5, +                                           long long arg6, long long arg7); +void __sanitizer_syscall_pre_impl_exit(long long rval); +void __sanitizer_syscall_post_impl_exit(long long res, long long rval); +void __sanitizer_syscall_pre_impl_fork(void); +void __sanitizer_syscall_post_impl_fork(long long res); +void __sanitizer_syscall_pre_impl_read(long long fd, long long buf, +                                       long long nbyte); +void __sanitizer_syscall_post_impl_read(long long res, long long fd, +                                        long long buf, long long nbyte); +void __sanitizer_syscall_pre_impl_write(long long fd, long long buf, +                                        long long nbyte); +void __sanitizer_syscall_post_impl_write(long long res, long long fd, +                                         long long buf, long long nbyte); +void __sanitizer_syscall_pre_impl_open(long long path, long long flags, +                                       long long mode); +void __sanitizer_syscall_post_impl_open(long long res, long long path, +                                        long long flags, long long mode); +void __sanitizer_syscall_pre_impl_close(long long fd); +void __sanitizer_syscall_post_impl_close(long long res, long long fd); +void __sanitizer_syscall_pre_impl_compat_50_wait4(long long pid, +                                                  long long status, +                                                  long long options, +                                                  long long rusage); +void __sanitizer_syscall_post_impl_compat_50_wait4(long long res, long long pid, +                                                   long long status, +                                                   long long options, +                                                   long long rusage); +void __sanitizer_syscall_pre_impl_compat_43_ocreat(long long path, +                                                   long long mode); +void __sanitizer_syscall_post_impl_compat_43_ocreat(long long res, +                                                    long long path, +                                                    long long mode); +void __sanitizer_syscall_pre_impl_link(long long path, long long link); +void __sanitizer_syscall_post_impl_link(long long res, long long path, +                                        long long link); +void __sanitizer_syscall_pre_impl_unlink(long long path); +void __sanitizer_syscall_post_impl_unlink(long long res, long long path); +/* syscall 11 has been skipped */ +void __sanitizer_syscall_pre_impl_chdir(long long path); +void __sanitizer_syscall_post_impl_chdir(long long res, long long path); +void __sanitizer_syscall_pre_impl_fchdir(long long fd); +void __sanitizer_syscall_post_impl_fchdir(long long res, long long fd); +void __sanitizer_syscall_pre_impl_compat_50_mknod(long long path, +                                                  long long mode, +                                                  long long dev); +void __sanitizer_syscall_post_impl_compat_50_mknod(long long res, +                                                   long long path, +                                                   long long mode, +                                                   long long dev); +void __sanitizer_syscall_pre_impl_chmod(long long path, long long mode); +void __sanitizer_syscall_post_impl_chmod(long long res, long long path, +                                         long long mode); +void __sanitizer_syscall_pre_impl_chown(long long path, long long uid, +                                        long long gid); +void __sanitizer_syscall_post_impl_chown(long long res, long long path, +                                         long long uid, long long gid); +void __sanitizer_syscall_pre_impl_break(long long nsize); +void __sanitizer_syscall_post_impl_break(long long res, long long nsize); +void __sanitizer_syscall_pre_impl_compat_20_getfsstat(long long buf, +                                                      long long bufsize, +                                                      long long flags); +void __sanitizer_syscall_post_impl_compat_20_getfsstat(long long res, +                                                       long long buf, +                                                       long long bufsize, +                                                       long long flags); +void __sanitizer_syscall_pre_impl_compat_43_olseek(long long fd, +                                                   long long offset, +                                                   long long whence); +void __sanitizer_syscall_post_impl_compat_43_olseek(long long res, long long fd, +                                                    long long offset, +                                                    long long whence); +void __sanitizer_syscall_pre_impl_getpid(void); +void __sanitizer_syscall_post_impl_getpid(long long res); +void __sanitizer_syscall_pre_impl_compat_40_mount(long long type, +                                                  long long path, +                                                  long long flags, +                                                  long long data); +void __sanitizer_syscall_post_impl_compat_40_mount(long long res, +                                                   long long type, +                                                   long long path, +                                                   long long flags, +                                                   long long data); +void __sanitizer_syscall_pre_impl_unmount(long long path, long long flags); +void __sanitizer_syscall_post_impl_unmount(long long res, long long path, +                                           long long flags); +void __sanitizer_syscall_pre_impl_setuid(long long uid); +void __sanitizer_syscall_post_impl_setuid(long long res, long long uid); +void __sanitizer_syscall_pre_impl_getuid(void); +void __sanitizer_syscall_post_impl_getuid(long long res); +void __sanitizer_syscall_pre_impl_geteuid(void); +void __sanitizer_syscall_post_impl_geteuid(long long res); +void __sanitizer_syscall_pre_impl_ptrace(long long req, long long pid, +                                         long long addr, long long data); +void __sanitizer_syscall_post_impl_ptrace(long long res, long long req, +                                          long long pid, long long addr, +                                          long long data); +void __sanitizer_syscall_pre_impl_recvmsg(long long s, long long msg, +                                          long long flags); +void __sanitizer_syscall_post_impl_recvmsg(long long res, long long s, +                                           long long msg, long long flags); +void __sanitizer_syscall_pre_impl_sendmsg(long long s, long long msg, +                                          long long flags); +void __sanitizer_syscall_post_impl_sendmsg(long long res, long long s, +                                           long long msg, long long flags); +void __sanitizer_syscall_pre_impl_recvfrom(long long s, long long buf, +                                           long long len, long long flags, +                                           long long from, +                                           long long fromlenaddr); +void __sanitizer_syscall_post_impl_recvfrom(long long res, long long s, +                                            long long buf, long long len, +                                            long long flags, long long from, +                                            long long fromlenaddr); +void __sanitizer_syscall_pre_impl_accept(long long s, long long name, +                                         long long anamelen); +void __sanitizer_syscall_post_impl_accept(long long res, long long s, +                                          long long name, long long anamelen); +void __sanitizer_syscall_pre_impl_getpeername(long long fdes, long long asa, +                                              long long alen); +void __sanitizer_syscall_post_impl_getpeername(long long res, long long fdes, +                                               long long asa, long long alen); +void __sanitizer_syscall_pre_impl_getsockname(long long fdes, long long asa, +                                              long long alen); +void __sanitizer_syscall_post_impl_getsockname(long long res, long long fdes, +                                               long long asa, long long alen); +void __sanitizer_syscall_pre_impl_access(long long path, long long flags); +void __sanitizer_syscall_post_impl_access(long long res, long long path, +                                          long long flags); +void __sanitizer_syscall_pre_impl_chflags(long long path, long long flags); +void __sanitizer_syscall_post_impl_chflags(long long res, long long path, +                                           long long flags); +void __sanitizer_syscall_pre_impl_fchflags(long long fd, long long flags); +void __sanitizer_syscall_post_impl_fchflags(long long res, long long fd, +                                            long long flags); +void __sanitizer_syscall_pre_impl_sync(void); +void __sanitizer_syscall_post_impl_sync(long long res); +void __sanitizer_syscall_pre_impl_kill(long long pid, long long signum); +void __sanitizer_syscall_post_impl_kill(long long res, long long pid, +                                        long long signum); +void __sanitizer_syscall_pre_impl_compat_43_stat43(long long path, +                                                   long long ub); +void __sanitizer_syscall_post_impl_compat_43_stat43(long long res, +                                                    long long path, +                                                    long long ub); +void __sanitizer_syscall_pre_impl_getppid(void); +void __sanitizer_syscall_post_impl_getppid(long long res); +void __sanitizer_syscall_pre_impl_compat_43_lstat43(long long path, +                                                    long long ub); +void __sanitizer_syscall_post_impl_compat_43_lstat43(long long res, +                                                     long long path, +                                                     long long ub); +void __sanitizer_syscall_pre_impl_dup(long long fd); +void __sanitizer_syscall_post_impl_dup(long long res, long long fd); +void __sanitizer_syscall_pre_impl_pipe(void); +void __sanitizer_syscall_post_impl_pipe(long long res); +void __sanitizer_syscall_pre_impl_getegid(void); +void __sanitizer_syscall_post_impl_getegid(long long res); +void __sanitizer_syscall_pre_impl_profil(long long samples, long long size, +                                         long long offset, long long scale); +void __sanitizer_syscall_post_impl_profil(long long res, long long samples, +                                          long long size, long long offset, +                                          long long scale); +void __sanitizer_syscall_pre_impl_ktrace(long long fname, long long ops, +                                         long long facs, long long pid); +void __sanitizer_syscall_post_impl_ktrace(long long res, long long fname, +                                          long long ops, long long facs, +                                          long long pid); +void __sanitizer_syscall_pre_impl_compat_13_sigaction13(long long signum, +                                                        long long nsa, +                                                        long long osa); +void __sanitizer_syscall_post_impl_compat_13_sigaction13(long long res, +                                                         long long signum, +                                                         long long nsa, +                                                         long long osa); +void __sanitizer_syscall_pre_impl_getgid(void); +void __sanitizer_syscall_post_impl_getgid(long long res); +void __sanitizer_syscall_pre_impl_compat_13_sigprocmask13(long long how, +                                                          long long mask); +void __sanitizer_syscall_post_impl_compat_13_sigprocmask13(long long res, +                                                           long long how, +                                                           long long mask); +void __sanitizer_syscall_pre_impl___getlogin(long long namebuf, +                                             long long namelen); +void __sanitizer_syscall_post_impl___getlogin(long long res, long long namebuf, +                                              long long namelen); +void __sanitizer_syscall_pre_impl___setlogin(long long namebuf); +void __sanitizer_syscall_post_impl___setlogin(long long res, long long namebuf); +void __sanitizer_syscall_pre_impl_acct(long long path); +void __sanitizer_syscall_post_impl_acct(long long res, long long path); +void __sanitizer_syscall_pre_impl_compat_13_sigpending13(void); +void __sanitizer_syscall_post_impl_compat_13_sigpending13(long long res); +void __sanitizer_syscall_pre_impl_compat_13_sigaltstack13(long long nss, +                                                          long long oss); +void __sanitizer_syscall_post_impl_compat_13_sigaltstack13(long long res, +                                                           long long nss, +                                                           long long oss); +void __sanitizer_syscall_pre_impl_ioctl(long long fd, long long com, +                                        long long data); +void __sanitizer_syscall_post_impl_ioctl(long long res, long long fd, +                                         long long com, long long data); +void __sanitizer_syscall_pre_impl_compat_12_oreboot(long long opt); +void __sanitizer_syscall_post_impl_compat_12_oreboot(long long res, +                                                     long long opt); +void __sanitizer_syscall_pre_impl_revoke(long long path); +void __sanitizer_syscall_post_impl_revoke(long long res, long long path); +void __sanitizer_syscall_pre_impl_symlink(long long path, long long link); +void __sanitizer_syscall_post_impl_symlink(long long res, long long path, +                                           long long link); +void __sanitizer_syscall_pre_impl_readlink(long long path, long long buf, +                                           long long count); +void __sanitizer_syscall_post_impl_readlink(long long res, long long path, +                                            long long buf, long long count); +void __sanitizer_syscall_pre_impl_execve(long long path, long long argp, +                                         long long envp); +void __sanitizer_syscall_post_impl_execve(long long res, long long path, +                                          long long argp, long long envp); +void __sanitizer_syscall_pre_impl_umask(long long newmask); +void __sanitizer_syscall_post_impl_umask(long long res, long long newmask); +void __sanitizer_syscall_pre_impl_chroot(long long path); +void __sanitizer_syscall_post_impl_chroot(long long res, long long path); +void __sanitizer_syscall_pre_impl_compat_43_fstat43(long long fd, long long sb); +void __sanitizer_syscall_post_impl_compat_43_fstat43(long long res, +                                                     long long fd, +                                                     long long sb); +void __sanitizer_syscall_pre_impl_compat_43_ogetkerninfo(long long op, +                                                         long long where, +                                                         long long size, +                                                         long long arg); +void __sanitizer_syscall_post_impl_compat_43_ogetkerninfo(long long res, +                                                          long long op, +                                                          long long where, +                                                          long long size, +                                                          long long arg); +void __sanitizer_syscall_pre_impl_compat_43_ogetpagesize(void); +void __sanitizer_syscall_post_impl_compat_43_ogetpagesize(long long res); +void __sanitizer_syscall_pre_impl_compat_12_msync(long long addr, +                                                  long long len); +void __sanitizer_syscall_post_impl_compat_12_msync(long long res, +                                                   long long addr, +                                                   long long len); +void __sanitizer_syscall_pre_impl_vfork(void); +void __sanitizer_syscall_post_impl_vfork(long long res); +/* syscall 67 has been skipped */ +/* syscall 68 has been skipped */ +/* syscall 69 has been skipped */ +/* syscall 70 has been skipped */ +void __sanitizer_syscall_pre_impl_compat_43_ommap(long long addr, long long len, +                                                  long long prot, +                                                  long long flags, long long fd, +                                                  long long pos); +void __sanitizer_syscall_post_impl_compat_43_ommap( +    long long res, long long addr, long long len, long long prot, +    long long flags, long long fd, long long pos); +void __sanitizer_syscall_pre_impl_vadvise(long long anom); +void __sanitizer_syscall_post_impl_vadvise(long long res, long long anom); +void __sanitizer_syscall_pre_impl_munmap(long long addr, long long len); +void __sanitizer_syscall_post_impl_munmap(long long res, long long addr, +                                          long long len); +void __sanitizer_syscall_pre_impl_mprotect(long long addr, long long len, +                                           long long prot); +void __sanitizer_syscall_post_impl_mprotect(long long res, long long addr, +                                            long long len, long long prot); +void __sanitizer_syscall_pre_impl_madvise(long long addr, long long len, +                                          long long behav); +void __sanitizer_syscall_post_impl_madvise(long long res, long long addr, +                                           long long len, long long behav); +/* syscall 76 has been skipped */ +/* syscall 77 has been skipped */ +void __sanitizer_syscall_pre_impl_mincore(long long addr, long long len, +                                          long long vec); +void __sanitizer_syscall_post_impl_mincore(long long res, long long addr, +                                           long long len, long long vec); +void __sanitizer_syscall_pre_impl_getgroups(long long gidsetsize, +                                            long long gidset); +void __sanitizer_syscall_post_impl_getgroups(long long res, +                                             long long gidsetsize, +                                             long long gidset); +void __sanitizer_syscall_pre_impl_setgroups(long long gidsetsize, +                                            long long gidset); +void __sanitizer_syscall_post_impl_setgroups(long long res, +                                             long long gidsetsize, +                                             long long gidset); +void __sanitizer_syscall_pre_impl_getpgrp(void); +void __sanitizer_syscall_post_impl_getpgrp(long long res); +void __sanitizer_syscall_pre_impl_setpgid(long long pid, long long pgid); +void __sanitizer_syscall_post_impl_setpgid(long long res, long long pid, +                                           long long pgid); +void __sanitizer_syscall_pre_impl_compat_50_setitimer(long long which, +                                                      long long itv, +                                                      long long oitv); +void __sanitizer_syscall_post_impl_compat_50_setitimer(long long res, +                                                       long long which, +                                                       long long itv, +                                                       long long oitv); +void __sanitizer_syscall_pre_impl_compat_43_owait(void); +void __sanitizer_syscall_post_impl_compat_43_owait(long long res); +void __sanitizer_syscall_pre_impl_compat_12_oswapon(long long name); +void __sanitizer_syscall_post_impl_compat_12_oswapon(long long res, +                                                     long long name); +void __sanitizer_syscall_pre_impl_compat_50_getitimer(long long which, +                                                      long long itv); +void __sanitizer_syscall_post_impl_compat_50_getitimer(long long res, +                                                       long long which, +                                                       long long itv); +void __sanitizer_syscall_pre_impl_compat_43_ogethostname(long long hostname, +                                                         long long len); +void __sanitizer_syscall_post_impl_compat_43_ogethostname(long long res, +                                                          long long hostname, +                                                          long long len); +void __sanitizer_syscall_pre_impl_compat_43_osethostname(long long hostname, +                                                         long long len); +void __sanitizer_syscall_post_impl_compat_43_osethostname(long long res, +                                                          long long hostname, +                                                          long long len); +void __sanitizer_syscall_pre_impl_compat_43_ogetdtablesize(void); +void __sanitizer_syscall_post_impl_compat_43_ogetdtablesize(long long res); +void __sanitizer_syscall_pre_impl_dup2(long long from, long long to); +void __sanitizer_syscall_post_impl_dup2(long long res, long long from, +                                        long long to); +/* syscall 91 has been skipped */ +void __sanitizer_syscall_pre_impl_fcntl(long long fd, long long cmd, +                                        long long arg); +void __sanitizer_syscall_post_impl_fcntl(long long res, long long fd, +                                         long long cmd, long long arg); +void __sanitizer_syscall_pre_impl_compat_50_select(long long nd, long long in, +                                                   long long ou, long long ex, +                                                   long long tv); +void __sanitizer_syscall_post_impl_compat_50_select(long long res, long long nd, +                                                    long long in, long long ou, +                                                    long long ex, long long tv); +/* syscall 94 has been skipped */ +void __sanitizer_syscall_pre_impl_fsync(long long fd); +void __sanitizer_syscall_post_impl_fsync(long long res, long long fd); +void __sanitizer_syscall_pre_impl_setpriority(long long which, long long who, +                                              long long prio); +void __sanitizer_syscall_post_impl_setpriority(long long res, long long which, +                                               long long who, long long prio); +void __sanitizer_syscall_pre_impl_compat_30_socket(long long domain, +                                                   long long type, +                                                   long long protocol); +void __sanitizer_syscall_post_impl_compat_30_socket(long long res, +                                                    long long domain, +                                                    long long type, +                                                    long long protocol); +void __sanitizer_syscall_pre_impl_connect(long long s, long long name, +                                          long long namelen); +void __sanitizer_syscall_post_impl_connect(long long res, long long s, +                                           long long name, long long namelen); +void __sanitizer_syscall_pre_impl_compat_43_oaccept(long long s, long long name, +                                                    long long anamelen); +void __sanitizer_syscall_post_impl_compat_43_oaccept(long long res, long long s, +                                                     long long name, +                                                     long long anamelen); +void __sanitizer_syscall_pre_impl_getpriority(long long which, long long who); +void __sanitizer_syscall_post_impl_getpriority(long long res, long long which, +                                               long long who); +void __sanitizer_syscall_pre_impl_compat_43_osend(long long s, long long buf, +                                                  long long len, +                                                  long long flags); +void __sanitizer_syscall_post_impl_compat_43_osend(long long res, long long s, +                                                   long long buf, long long len, +                                                   long long flags); +void __sanitizer_syscall_pre_impl_compat_43_orecv(long long s, long long buf, +                                                  long long len, +                                                  long long flags); +void __sanitizer_syscall_post_impl_compat_43_orecv(long long res, long long s, +                                                   long long buf, long long len, +                                                   long long flags); +void __sanitizer_syscall_pre_impl_compat_13_sigreturn13(long long sigcntxp); +void __sanitizer_syscall_post_impl_compat_13_sigreturn13(long long res, +                                                         long long sigcntxp); +void __sanitizer_syscall_pre_impl_bind(long long s, long long name, +                                       long long namelen); +void __sanitizer_syscall_post_impl_bind(long long res, long long s, +                                        long long name, long long namelen); +void __sanitizer_syscall_pre_impl_setsockopt(long long s, long long level, +                                             long long name, long long val, +                                             long long valsize); +void __sanitizer_syscall_post_impl_setsockopt(long long res, long long s, +                                              long long level, long long name, +                                              long long val, long long valsize); +void __sanitizer_syscall_pre_impl_listen(long long s, long long backlog); +void __sanitizer_syscall_post_impl_listen(long long res, long long s, +                                          long long backlog); +/* syscall 107 has been skipped */ +void __sanitizer_syscall_pre_impl_compat_43_osigvec(long long signum, +                                                    long long nsv, +                                                    long long osv); +void __sanitizer_syscall_post_impl_compat_43_osigvec(long long res, +                                                     long long signum, +                                                     long long nsv, +                                                     long long osv); +void __sanitizer_syscall_pre_impl_compat_43_osigblock(long long mask); +void __sanitizer_syscall_post_impl_compat_43_osigblock(long long res, +                                                       long long mask); +void __sanitizer_syscall_pre_impl_compat_43_osigsetmask(long long mask); +void __sanitizer_syscall_post_impl_compat_43_osigsetmask(long long res, +                                                         long long mask); +void __sanitizer_syscall_pre_impl_compat_13_sigsuspend13(long long mask); +void __sanitizer_syscall_post_impl_compat_13_sigsuspend13(long long res, +                                                          long long mask); +void __sanitizer_syscall_pre_impl_compat_43_osigstack(long long nss, +                                                      long long oss); +void __sanitizer_syscall_post_impl_compat_43_osigstack(long long res, +                                                       long long nss, +                                                       long long oss); +void __sanitizer_syscall_pre_impl_compat_43_orecvmsg(long long s, long long msg, +                                                     long long flags); +void __sanitizer_syscall_post_impl_compat_43_orecvmsg(long long res, +                                                      long long s, +                                                      long long msg, +                                                      long long flags); +void __sanitizer_syscall_pre_impl_compat_43_osendmsg(long long s, long long msg, +                                                     long long flags); +void __sanitizer_syscall_post_impl_compat_43_osendmsg(long long res, +                                                      long long s, +                                                      long long msg, +                                                      long long flags); +/* syscall 115 has been skipped */ +void __sanitizer_syscall_pre_impl_compat_50_gettimeofday(long long tp, +                                                         long long tzp); +void __sanitizer_syscall_post_impl_compat_50_gettimeofday(long long res, +                                                          long long tp, +                                                          long long tzp); +void __sanitizer_syscall_pre_impl_compat_50_getrusage(long long who, +                                                      long long rusage); +void __sanitizer_syscall_post_impl_compat_50_getrusage(long long res, +                                                       long long who, +                                                       long long rusage); +void __sanitizer_syscall_pre_impl_getsockopt(long long s, long long level, +                                             long long name, long long val, +                                             long long avalsize); +void __sanitizer_syscall_post_impl_getsockopt(long long res, long long s, +                                              long long level, long long name, +                                              long long val, +                                              long long avalsize); +/* syscall 119 has been skipped */ +void __sanitizer_syscall_pre_impl_readv(long long fd, long long iovp, +                                        long long iovcnt); +void __sanitizer_syscall_post_impl_readv(long long res, long long fd, +                                         long long iovp, long long iovcnt); +void __sanitizer_syscall_pre_impl_writev(long long fd, long long iovp, +                                         long long iovcnt); +void __sanitizer_syscall_post_impl_writev(long long res, long long fd, +                                          long long iovp, long long iovcnt); +void __sanitizer_syscall_pre_impl_compat_50_settimeofday(long long tv, +                                                         long long tzp); +void __sanitizer_syscall_post_impl_compat_50_settimeofday(long long res, +                                                          long long tv, +                                                          long long tzp); +void __sanitizer_syscall_pre_impl_fchown(long long fd, long long uid, +                                         long long gid); +void __sanitizer_syscall_post_impl_fchown(long long res, long long fd, +                                          long long uid, long long gid); +void __sanitizer_syscall_pre_impl_fchmod(long long fd, long long mode); +void __sanitizer_syscall_post_impl_fchmod(long long res, long long fd, +                                          long long mode); +void __sanitizer_syscall_pre_impl_compat_43_orecvfrom( +    long long s, long long buf, long long len, long long flags, long long from, +    long long fromlenaddr); +void __sanitizer_syscall_post_impl_compat_43_orecvfrom( +    long long res, long long s, long long buf, long long len, long long flags, +    long long from, long long fromlenaddr); +void __sanitizer_syscall_pre_impl_setreuid(long long ruid, long long euid); +void __sanitizer_syscall_post_impl_setreuid(long long res, long long ruid, +                                            long long euid); +void __sanitizer_syscall_pre_impl_setregid(long long rgid, long long egid); +void __sanitizer_syscall_post_impl_setregid(long long res, long long rgid, +                                            long long egid); +void __sanitizer_syscall_pre_impl_rename(long long from, long long to); +void __sanitizer_syscall_post_impl_rename(long long res, long long from, +                                          long long to); +void __sanitizer_syscall_pre_impl_compat_43_otruncate(long long path, +                                                      long long length); +void __sanitizer_syscall_post_impl_compat_43_otruncate(long long res, +                                                       long long path, +                                                       long long length); +void __sanitizer_syscall_pre_impl_compat_43_oftruncate(long long fd, +                                                       long long length); +void __sanitizer_syscall_post_impl_compat_43_oftruncate(long long res, +                                                        long long fd, +                                                        long long length); +void __sanitizer_syscall_pre_impl_flock(long long fd, long long how); +void __sanitizer_syscall_post_impl_flock(long long res, long long fd, +                                         long long how); +void __sanitizer_syscall_pre_impl_mkfifo(long long path, long long mode); +void __sanitizer_syscall_post_impl_mkfifo(long long res, long long path, +                                          long long mode); +void __sanitizer_syscall_pre_impl_sendto(long long s, long long buf, +                                         long long len, long long flags, +                                         long long to, long long tolen); +void __sanitizer_syscall_post_impl_sendto(long long res, long long s, +                                          long long buf, long long len, +                                          long long flags, long long to, +                                          long long tolen); +void __sanitizer_syscall_pre_impl_shutdown(long long s, long long how); +void __sanitizer_syscall_post_impl_shutdown(long long res, long long s, +                                            long long how); +void __sanitizer_syscall_pre_impl_socketpair(long long domain, long long type, +                                             long long protocol, long long rsv); +void __sanitizer_syscall_post_impl_socketpair(long long res, long long domain, +                                              long long type, +                                              long long protocol, +                                              long long rsv); +void __sanitizer_syscall_pre_impl_mkdir(long long path, long long mode); +void __sanitizer_syscall_post_impl_mkdir(long long res, long long path, +                                         long long mode); +void __sanitizer_syscall_pre_impl_rmdir(long long path); +void __sanitizer_syscall_post_impl_rmdir(long long res, long long path); +void __sanitizer_syscall_pre_impl_compat_50_utimes(long long path, +                                                   long long tptr); +void __sanitizer_syscall_post_impl_compat_50_utimes(long long res, +                                                    long long path, +                                                    long long tptr); +/* syscall 139 has been skipped */ +void __sanitizer_syscall_pre_impl_compat_50_adjtime(long long delta, +                                                    long long olddelta); +void __sanitizer_syscall_post_impl_compat_50_adjtime(long long res, +                                                     long long delta, +                                                     long long olddelta); +void __sanitizer_syscall_pre_impl_compat_43_ogetpeername(long long fdes, +                                                         long long asa, +                                                         long long alen); +void __sanitizer_syscall_post_impl_compat_43_ogetpeername(long long res, +                                                          long long fdes, +                                                          long long asa, +                                                          long long alen); +void __sanitizer_syscall_pre_impl_compat_43_ogethostid(void); +void __sanitizer_syscall_post_impl_compat_43_ogethostid(long long res); +void __sanitizer_syscall_pre_impl_compat_43_osethostid(long long hostid); +void __sanitizer_syscall_post_impl_compat_43_osethostid(long long res, +                                                        long long hostid); +void __sanitizer_syscall_pre_impl_compat_43_ogetrlimit(long long which, +                                                       long long rlp); +void __sanitizer_syscall_post_impl_compat_43_ogetrlimit(long long res, +                                                        long long which, +                                                        long long rlp); +void __sanitizer_syscall_pre_impl_compat_43_osetrlimit(long long which, +                                                       long long rlp); +void __sanitizer_syscall_post_impl_compat_43_osetrlimit(long long res, +                                                        long long which, +                                                        long long rlp); +void __sanitizer_syscall_pre_impl_compat_43_okillpg(long long pgid, +                                                    long long signum); +void __sanitizer_syscall_post_impl_compat_43_okillpg(long long res, +                                                     long long pgid, +                                                     long long signum); +void __sanitizer_syscall_pre_impl_setsid(void); +void __sanitizer_syscall_post_impl_setsid(long long res); +void __sanitizer_syscall_pre_impl_compat_50_quotactl(long long path, +                                                     long long cmd, +                                                     long long uid, +                                                     long long arg); +void __sanitizer_syscall_post_impl_compat_50_quotactl( +    long long res, long long path, long long cmd, long long uid, long long arg); +void __sanitizer_syscall_pre_impl_compat_43_oquota(void); +void __sanitizer_syscall_post_impl_compat_43_oquota(long long res); +void __sanitizer_syscall_pre_impl_compat_43_ogetsockname(long long fdec, +                                                         long long asa, +                                                         long long alen); +void __sanitizer_syscall_post_impl_compat_43_ogetsockname(long long res, +                                                          long long fdec, +                                                          long long asa, +                                                          long long alen); +/* syscall 151 has been skipped */ +/* syscall 152 has been skipped */ +/* syscall 153 has been skipped */ +/* syscall 154 has been skipped */ +void __sanitizer_syscall_pre_impl_nfssvc(long long flag, long long argp); +void __sanitizer_syscall_post_impl_nfssvc(long long res, long long flag, +                                          long long argp); +void __sanitizer_syscall_pre_impl_compat_43_ogetdirentries(long long fd, +                                                           long long buf, +                                                           long long count, +                                                           long long basep); +void __sanitizer_syscall_post_impl_compat_43_ogetdirentries(long long res, +                                                            long long fd, +                                                            long long buf, +                                                            long long count, +                                                            long long basep); +void __sanitizer_syscall_pre_impl_compat_20_statfs(long long path, +                                                   long long buf); +void __sanitizer_syscall_post_impl_compat_20_statfs(long long res, +                                                    long long path, +                                                    long long buf); +void __sanitizer_syscall_pre_impl_compat_20_fstatfs(long long fd, +                                                    long long buf); +void __sanitizer_syscall_post_impl_compat_20_fstatfs(long long res, +                                                     long long fd, +                                                     long long buf); +/* syscall 159 has been skipped */ +/* syscall 160 has been skipped */ +void __sanitizer_syscall_pre_impl_compat_30_getfh(long long fname, +                                                  long long fhp); +void __sanitizer_syscall_post_impl_compat_30_getfh(long long res, +                                                   long long fname, +                                                   long long fhp); +void __sanitizer_syscall_pre_impl_compat_09_ogetdomainname(long long domainname, +                                                           long long len); +void __sanitizer_syscall_post_impl_compat_09_ogetdomainname( +    long long res, long long domainname, long long len); +void __sanitizer_syscall_pre_impl_compat_09_osetdomainname(long long domainname, +                                                           long long len); +void __sanitizer_syscall_post_impl_compat_09_osetdomainname( +    long long res, long long domainname, long long len); +void __sanitizer_syscall_pre_impl_compat_09_ouname(long long name); +void __sanitizer_syscall_post_impl_compat_09_ouname(long long res, +                                                    long long name); +void __sanitizer_syscall_pre_impl_sysarch(long long op, long long parms); +void __sanitizer_syscall_post_impl_sysarch(long long res, long long op, +                                           long long parms); +/* syscall 166 has been skipped */ +/* syscall 167 has been skipped */ +/* syscall 168 has been skipped */ +#if !defined(_LP64) +void __sanitizer_syscall_pre_impl_compat_10_osemsys(long long which, +                                                    long long a2, long long a3, +                                                    long long a4, long long a5); +void __sanitizer_syscall_post_impl_compat_10_osemsys(long long res, +                                                     long long which, +                                                     long long a2, long long a3, +                                                     long long a4, +                                                     long long a5); +#else +/* syscall 169 has been skipped */ +#endif +#if !defined(_LP64) +void __sanitizer_syscall_pre_impl_compat_10_omsgsys(long long which, +                                                    long long a2, long long a3, +                                                    long long a4, long long a5, +                                                    long long a6); +void __sanitizer_syscall_post_impl_compat_10_omsgsys(long long res, +                                                     long long which, +                                                     long long a2, long long a3, +                                                     long long a4, long long a5, +                                                     long long a6); +#else +/* syscall 170 has been skipped */ +#endif +#if !defined(_LP64) +void __sanitizer_syscall_pre_impl_compat_10_oshmsys(long long which, +                                                    long long a2, long long a3, +                                                    long long a4); +void __sanitizer_syscall_post_impl_compat_10_oshmsys(long long res, +                                                     long long which, +                                                     long long a2, long long a3, +                                                     long long a4); +#else +/* syscall 171 has been skipped */ +#endif +/* syscall 172 has been skipped */ +void __sanitizer_syscall_pre_impl_pread(long long fd, long long buf, +                                        long long nbyte, long long PAD, +                                        long long offset); +void __sanitizer_syscall_post_impl_pread(long long res, long long fd, +                                         long long buf, long long nbyte, +                                         long long PAD, long long offset); +void __sanitizer_syscall_pre_impl_pwrite(long long fd, long long buf, +                                         long long nbyte, long long PAD, +                                         long long offset); +void __sanitizer_syscall_post_impl_pwrite(long long res, long long fd, +                                          long long buf, long long nbyte, +                                          long long PAD, long long offset); +void __sanitizer_syscall_pre_impl_compat_30_ntp_gettime(long long ntvp); +void __sanitizer_syscall_post_impl_compat_30_ntp_gettime(long long res, +                                                         long long ntvp); +#if defined(NTP) || !defined(_KERNEL_OPT) +void __sanitizer_syscall_pre_impl_ntp_adjtime(long long tp); +void __sanitizer_syscall_post_impl_ntp_adjtime(long long res, long long tp); +#else +/* syscall 176 has been skipped */ +#endif +/* syscall 177 has been skipped */ +/* syscall 178 has been skipped */ +/* syscall 179 has been skipped */ +/* syscall 180 has been skipped */ +void __sanitizer_syscall_pre_impl_setgid(long long gid); +void __sanitizer_syscall_post_impl_setgid(long long res, long long gid); +void __sanitizer_syscall_pre_impl_setegid(long long egid); +void __sanitizer_syscall_post_impl_setegid(long long res, long long egid); +void __sanitizer_syscall_pre_impl_seteuid(long long euid); +void __sanitizer_syscall_post_impl_seteuid(long long res, long long euid); +void __sanitizer_syscall_pre_impl_lfs_bmapv(long long fsidp, long long blkiov, +                                            long long blkcnt); +void __sanitizer_syscall_post_impl_lfs_bmapv(long long res, long long fsidp, +                                             long long blkiov, +                                             long long blkcnt); +void __sanitizer_syscall_pre_impl_lfs_markv(long long fsidp, long long blkiov, +                                            long long blkcnt); +void __sanitizer_syscall_post_impl_lfs_markv(long long res, long long fsidp, +                                             long long blkiov, +                                             long long blkcnt); +void __sanitizer_syscall_pre_impl_lfs_segclean(long long fsidp, +                                               long long segment); +void __sanitizer_syscall_post_impl_lfs_segclean(long long res, long long fsidp, +                                                long long segment); +void __sanitizer_syscall_pre_impl_compat_50_lfs_segwait(long long fsidp, +                                                        long long tv); +void __sanitizer_syscall_post_impl_compat_50_lfs_segwait(long long res, +                                                         long long fsidp, +                                                         long long tv); +void __sanitizer_syscall_pre_impl_compat_12_stat12(long long path, +                                                   long long ub); +void __sanitizer_syscall_post_impl_compat_12_stat12(long long res, +                                                    long long path, +                                                    long long ub); +void __sanitizer_syscall_pre_impl_compat_12_fstat12(long long fd, long long sb); +void __sanitizer_syscall_post_impl_compat_12_fstat12(long long res, +                                                     long long fd, +                                                     long long sb); +void __sanitizer_syscall_pre_impl_compat_12_lstat12(long long path, +                                                    long long ub); +void __sanitizer_syscall_post_impl_compat_12_lstat12(long long res, +                                                     long long path, +                                                     long long ub); +void __sanitizer_syscall_pre_impl_pathconf(long long path, long long name); +void __sanitizer_syscall_post_impl_pathconf(long long res, long long path, +                                            long long name); +void __sanitizer_syscall_pre_impl_fpathconf(long long fd, long long name); +void __sanitizer_syscall_post_impl_fpathconf(long long res, long long fd, +                                             long long name); +/* syscall 193 has been skipped */ +void __sanitizer_syscall_pre_impl_getrlimit(long long which, long long rlp); +void __sanitizer_syscall_post_impl_getrlimit(long long res, long long which, +                                             long long rlp); +void __sanitizer_syscall_pre_impl_setrlimit(long long which, long long rlp); +void __sanitizer_syscall_post_impl_setrlimit(long long res, long long which, +                                             long long rlp); +void __sanitizer_syscall_pre_impl_compat_12_getdirentries(long long fd, +                                                          long long buf, +                                                          long long count, +                                                          long long basep); +void __sanitizer_syscall_post_impl_compat_12_getdirentries(long long res, +                                                           long long fd, +                                                           long long buf, +                                                           long long count, +                                                           long long basep); +void __sanitizer_syscall_pre_impl_mmap(long long addr, long long len, +                                       long long prot, long long flags, +                                       long long fd, long long PAD, +                                       long long pos); +void __sanitizer_syscall_post_impl_mmap(long long res, long long addr, +                                        long long len, long long prot, +                                        long long flags, long long fd, +                                        long long PAD, long long pos); +void __sanitizer_syscall_pre_impl___syscall(long long code, long long arg0, +                                            long long arg1, long long arg2, +                                            long long arg3, long long arg4, +                                            long long arg5, long long arg6, +                                            long long arg7); +void __sanitizer_syscall_post_impl___syscall(long long res, long long code, +                                             long long arg0, long long arg1, +                                             long long arg2, long long arg3, +                                             long long arg4, long long arg5, +                                             long long arg6, long long arg7); +void __sanitizer_syscall_pre_impl_lseek(long long fd, long long PAD, +                                        long long offset, long long whence); +void __sanitizer_syscall_post_impl_lseek(long long res, long long fd, +                                         long long PAD, long long offset, +                                         long long whence); +void __sanitizer_syscall_pre_impl_truncate(long long path, long long PAD, +                                           long long length); +void __sanitizer_syscall_post_impl_truncate(long long res, long long path, +                                            long long PAD, long long length); +void __sanitizer_syscall_pre_impl_ftruncate(long long fd, long long PAD, +                                            long long length); +void __sanitizer_syscall_post_impl_ftruncate(long long res, long long fd, +                                             long long PAD, long long length); +void __sanitizer_syscall_pre_impl___sysctl(long long name, long long namelen, +                                           long long oldv, long long oldlenp, +                                           long long newv, long long newlen); +void __sanitizer_syscall_post_impl___sysctl(long long res, long long name, +                                            long long namelen, long long oldv, +                                            long long oldlenp, long long newv, +                                            long long newlen); +void __sanitizer_syscall_pre_impl_mlock(long long addr, long long len); +void __sanitizer_syscall_post_impl_mlock(long long res, long long addr, +                                         long long len); +void __sanitizer_syscall_pre_impl_munlock(long long addr, long long len); +void __sanitizer_syscall_post_impl_munlock(long long res, long long addr, +                                           long long len); +void __sanitizer_syscall_pre_impl_undelete(long long path); +void __sanitizer_syscall_post_impl_undelete(long long res, long long path); +void __sanitizer_syscall_pre_impl_compat_50_futimes(long long fd, +                                                    long long tptr); +void __sanitizer_syscall_post_impl_compat_50_futimes(long long res, +                                                     long long fd, +                                                     long long tptr); +void __sanitizer_syscall_pre_impl_getpgid(long long pid); +void __sanitizer_syscall_post_impl_getpgid(long long res, long long pid); +void __sanitizer_syscall_pre_impl_reboot(long long opt, long long bootstr); +void __sanitizer_syscall_post_impl_reboot(long long res, long long opt, +                                          long long bootstr); +void __sanitizer_syscall_pre_impl_poll(long long fds, long long nfds, +                                       long long timeout); +void __sanitizer_syscall_post_impl_poll(long long res, long long fds, +                                        long long nfds, long long timeout); +void __sanitizer_syscall_pre_impl_afssys(long long id, long long a1, +                                         long long a2, long long a3, +                                         long long a4, long long a5, +                                         long long a6); +void __sanitizer_syscall_post_impl_afssys(long long res, long long id, +                                          long long a1, long long a2, +                                          long long a3, long long a4, +                                          long long a5, long long a6); +/* syscall 211 has been skipped */ +/* syscall 212 has been skipped */ +/* syscall 213 has been skipped */ +/* syscall 214 has been skipped */ +/* syscall 215 has been skipped */ +/* syscall 216 has been skipped */ +/* syscall 217 has been skipped */ +/* syscall 218 has been skipped */ +/* syscall 219 has been skipped */ +void __sanitizer_syscall_pre_impl_compat_14___semctl(long long semid, +                                                     long long semnum, +                                                     long long cmd, +                                                     long long arg); +void __sanitizer_syscall_post_impl_compat_14___semctl(long long res, +                                                      long long semid, +                                                      long long semnum, +                                                      long long cmd, +                                                      long long arg); +void __sanitizer_syscall_pre_impl_semget(long long key, long long nsems, +                                         long long semflg); +void __sanitizer_syscall_post_impl_semget(long long res, long long key, +                                          long long nsems, long long semflg); +void __sanitizer_syscall_pre_impl_semop(long long semid, long long sops, +                                        long long nsops); +void __sanitizer_syscall_post_impl_semop(long long res, long long semid, +                                         long long sops, long long nsops); +void __sanitizer_syscall_pre_impl_semconfig(long long flag); +void __sanitizer_syscall_post_impl_semconfig(long long res, long long flag); +void __sanitizer_syscall_pre_impl_compat_14_msgctl(long long msqid, +                                                   long long cmd, +                                                   long long buf); +void __sanitizer_syscall_post_impl_compat_14_msgctl(long long res, +                                                    long long msqid, +                                                    long long cmd, +                                                    long long buf); +void __sanitizer_syscall_pre_impl_msgget(long long key, long long msgflg); +void __sanitizer_syscall_post_impl_msgget(long long res, long long key, +                                          long long msgflg); +void __sanitizer_syscall_pre_impl_msgsnd(long long msqid, long long msgp, +                                         long long msgsz, long long msgflg); +void __sanitizer_syscall_post_impl_msgsnd(long long res, long long msqid, +                                          long long msgp, long long msgsz, +                                          long long msgflg); +void __sanitizer_syscall_pre_impl_msgrcv(long long msqid, long long msgp, +                                         long long msgsz, long long msgtyp, +                                         long long msgflg); +void __sanitizer_syscall_post_impl_msgrcv(long long res, long long msqid, +                                          long long msgp, long long msgsz, +                                          long long msgtyp, long long msgflg); +void __sanitizer_syscall_pre_impl_shmat(long long shmid, long long shmaddr, +                                        long long shmflg); +void __sanitizer_syscall_post_impl_shmat(long long res, long long shmid, +                                         long long shmaddr, long long shmflg); +void __sanitizer_syscall_pre_impl_compat_14_shmctl(long long shmid, +                                                   long long cmd, +                                                   long long buf); +void __sanitizer_syscall_post_impl_compat_14_shmctl(long long res, +                                                    long long shmid, +                                                    long long cmd, +                                                    long long buf); +void __sanitizer_syscall_pre_impl_shmdt(long long shmaddr); +void __sanitizer_syscall_post_impl_shmdt(long long res, long long shmaddr); +void __sanitizer_syscall_pre_impl_shmget(long long key, long long size, +                                         long long shmflg); +void __sanitizer_syscall_post_impl_shmget(long long res, long long key, +                                          long long size, long long shmflg); +void __sanitizer_syscall_pre_impl_compat_50_clock_gettime(long long clock_id, +                                                          long long tp); +void __sanitizer_syscall_post_impl_compat_50_clock_gettime(long long res, +                                                           long long clock_id, +                                                           long long tp); +void __sanitizer_syscall_pre_impl_compat_50_clock_settime(long long clock_id, +                                                          long long tp); +void __sanitizer_syscall_post_impl_compat_50_clock_settime(long long res, +                                                           long long clock_id, +                                                           long long tp); +void __sanitizer_syscall_pre_impl_compat_50_clock_getres(long long clock_id, +                                                         long long tp); +void __sanitizer_syscall_post_impl_compat_50_clock_getres(long long res, +                                                          long long clock_id, +                                                          long long tp); +void __sanitizer_syscall_pre_impl_timer_create(long long clock_id, +                                               long long evp, +                                               long long timerid); +void __sanitizer_syscall_post_impl_timer_create(long long res, +                                                long long clock_id, +                                                long long evp, +                                                long long timerid); +void __sanitizer_syscall_pre_impl_timer_delete(long long timerid); +void __sanitizer_syscall_post_impl_timer_delete(long long res, +                                                long long timerid); +void __sanitizer_syscall_pre_impl_compat_50_timer_settime(long long timerid, +                                                          long long flags, +                                                          long long value, +                                                          long long ovalue); +void __sanitizer_syscall_post_impl_compat_50_timer_settime(long long res, +                                                           long long timerid, +                                                           long long flags, +                                                           long long value, +                                                           long long ovalue); +void __sanitizer_syscall_pre_impl_compat_50_timer_gettime(long long timerid, +                                                          long long value); +void __sanitizer_syscall_post_impl_compat_50_timer_gettime(long long res, +                                                           long long timerid, +                                                           long long value); +void __sanitizer_syscall_pre_impl_timer_getoverrun(long long timerid); +void __sanitizer_syscall_post_impl_timer_getoverrun(long long res, +                                                    long long timerid); +void __sanitizer_syscall_pre_impl_compat_50_nanosleep(long long rqtp, +                                                      long long rmtp); +void __sanitizer_syscall_post_impl_compat_50_nanosleep(long long res, +                                                       long long rqtp, +                                                       long long rmtp); +void __sanitizer_syscall_pre_impl_fdatasync(long long fd); +void __sanitizer_syscall_post_impl_fdatasync(long long res, long long fd); +void __sanitizer_syscall_pre_impl_mlockall(long long flags); +void __sanitizer_syscall_post_impl_mlockall(long long res, long long flags); +void __sanitizer_syscall_pre_impl_munlockall(void); +void __sanitizer_syscall_post_impl_munlockall(long long res); +void __sanitizer_syscall_pre_impl_compat_50___sigtimedwait(long long set, +                                                           long long info, +                                                           long long timeout); +void __sanitizer_syscall_post_impl_compat_50___sigtimedwait(long long res, +                                                            long long set, +                                                            long long info, +                                                            long long timeout); +void __sanitizer_syscall_pre_impl_sigqueueinfo(long long pid, long long info); +void __sanitizer_syscall_post_impl_sigqueueinfo(long long res, long long pid, +                                                long long info); +void __sanitizer_syscall_pre_impl_modctl(long long cmd, long long arg); +void __sanitizer_syscall_post_impl_modctl(long long res, long long cmd, +                                          long long arg); +void __sanitizer_syscall_pre_impl__ksem_init(long long value, long long idp); +void __sanitizer_syscall_post_impl__ksem_init(long long res, long long value, +                                              long long idp); +void __sanitizer_syscall_pre_impl__ksem_open(long long name, long long oflag, +                                             long long mode, long long value, +                                             long long idp); +void __sanitizer_syscall_post_impl__ksem_open(long long res, long long name, +                                              long long oflag, long long mode, +                                              long long value, long long idp); +void __sanitizer_syscall_pre_impl__ksem_unlink(long long name); +void __sanitizer_syscall_post_impl__ksem_unlink(long long res, long long name); +void __sanitizer_syscall_pre_impl__ksem_close(long long id); +void __sanitizer_syscall_post_impl__ksem_close(long long res, long long id); +void __sanitizer_syscall_pre_impl__ksem_post(long long id); +void __sanitizer_syscall_post_impl__ksem_post(long long res, long long id); +void __sanitizer_syscall_pre_impl__ksem_wait(long long id); +void __sanitizer_syscall_post_impl__ksem_wait(long long res, long long id); +void __sanitizer_syscall_pre_impl__ksem_trywait(long long id); +void __sanitizer_syscall_post_impl__ksem_trywait(long long res, long long id); +void __sanitizer_syscall_pre_impl__ksem_getvalue(long long id, long long value); +void __sanitizer_syscall_post_impl__ksem_getvalue(long long res, long long id, +                                                  long long value); +void __sanitizer_syscall_pre_impl__ksem_destroy(long long id); +void __sanitizer_syscall_post_impl__ksem_destroy(long long res, long long id); +void __sanitizer_syscall_pre_impl__ksem_timedwait(long long id, +                                                  long long abstime); +void __sanitizer_syscall_post_impl__ksem_timedwait(long long res, long long id, +                                                   long long abstime); +void __sanitizer_syscall_pre_impl_mq_open(long long name, long long oflag, +                                          long long mode, long long attr); +void __sanitizer_syscall_post_impl_mq_open(long long res, long long name, +                                           long long oflag, long long mode, +                                           long long attr); +void __sanitizer_syscall_pre_impl_mq_close(long long mqdes); +void __sanitizer_syscall_post_impl_mq_close(long long res, long long mqdes); +void __sanitizer_syscall_pre_impl_mq_unlink(long long name); +void __sanitizer_syscall_post_impl_mq_unlink(long long res, long long name); +void __sanitizer_syscall_pre_impl_mq_getattr(long long mqdes, long long mqstat); +void __sanitizer_syscall_post_impl_mq_getattr(long long res, long long mqdes, +                                              long long mqstat); +void __sanitizer_syscall_pre_impl_mq_setattr(long long mqdes, long long mqstat, +                                             long long omqstat); +void __sanitizer_syscall_post_impl_mq_setattr(long long res, long long mqdes, +                                              long long mqstat, +                                              long long omqstat); +void __sanitizer_syscall_pre_impl_mq_notify(long long mqdes, +                                            long long notification); +void __sanitizer_syscall_post_impl_mq_notify(long long res, long long mqdes, +                                             long long notification); +void __sanitizer_syscall_pre_impl_mq_send(long long mqdes, long long msg_ptr, +                                          long long msg_len, +                                          long long msg_prio); +void __sanitizer_syscall_post_impl_mq_send(long long res, long long mqdes, +                                           long long msg_ptr, long long msg_len, +                                           long long msg_prio); +void __sanitizer_syscall_pre_impl_mq_receive(long long mqdes, long long msg_ptr, +                                             long long msg_len, +                                             long long msg_prio); +void __sanitizer_syscall_post_impl_mq_receive(long long res, long long mqdes, +                                              long long msg_ptr, +                                              long long msg_len, +                                              long long msg_prio); +void __sanitizer_syscall_pre_impl_compat_50_mq_timedsend(long long mqdes, +                                                         long long msg_ptr, +                                                         long long msg_len, +                                                         long long msg_prio, +                                                         long long abs_timeout); +void __sanitizer_syscall_post_impl_compat_50_mq_timedsend( +    long long res, long long mqdes, long long msg_ptr, long long msg_len, +    long long msg_prio, long long abs_timeout); +void __sanitizer_syscall_pre_impl_compat_50_mq_timedreceive( +    long long mqdes, long long msg_ptr, long long msg_len, long long msg_prio, +    long long abs_timeout); +void __sanitizer_syscall_post_impl_compat_50_mq_timedreceive( +    long long res, long long mqdes, long long msg_ptr, long long msg_len, +    long long msg_prio, long long abs_timeout); +/* syscall 267 has been skipped */ +/* syscall 268 has been skipped */ +/* syscall 269 has been skipped */ +void __sanitizer_syscall_pre_impl___posix_rename(long long from, long long to); +void __sanitizer_syscall_post_impl___posix_rename(long long res, long long from, +                                                  long long to); +void __sanitizer_syscall_pre_impl_swapctl(long long cmd, long long arg, +                                          long long misc); +void __sanitizer_syscall_post_impl_swapctl(long long res, long long cmd, +                                           long long arg, long long misc); +void __sanitizer_syscall_pre_impl_compat_30_getdents(long long fd, +                                                     long long buf, +                                                     long long count); +void __sanitizer_syscall_post_impl_compat_30_getdents(long long res, +                                                      long long fd, +                                                      long long buf, +                                                      long long count); +void __sanitizer_syscall_pre_impl_minherit(long long addr, long long len, +                                           long long inherit); +void __sanitizer_syscall_post_impl_minherit(long long res, long long addr, +                                            long long len, long long inherit); +void __sanitizer_syscall_pre_impl_lchmod(long long path, long long mode); +void __sanitizer_syscall_post_impl_lchmod(long long res, long long path, +                                          long long mode); +void __sanitizer_syscall_pre_impl_lchown(long long path, long long uid, +                                         long long gid); +void __sanitizer_syscall_post_impl_lchown(long long res, long long path, +                                          long long uid, long long gid); +void __sanitizer_syscall_pre_impl_compat_50_lutimes(long long path, +                                                    long long tptr); +void __sanitizer_syscall_post_impl_compat_50_lutimes(long long res, +                                                     long long path, +                                                     long long tptr); +void __sanitizer_syscall_pre_impl___msync13(long long addr, long long len, +                                            long long flags); +void __sanitizer_syscall_post_impl___msync13(long long res, long long addr, +                                             long long len, long long flags); +void __sanitizer_syscall_pre_impl_compat_30___stat13(long long path, +                                                     long long ub); +void __sanitizer_syscall_post_impl_compat_30___stat13(long long res, +                                                      long long path, +                                                      long long ub); +void __sanitizer_syscall_pre_impl_compat_30___fstat13(long long fd, +                                                      long long sb); +void __sanitizer_syscall_post_impl_compat_30___fstat13(long long res, +                                                       long long fd, +                                                       long long sb); +void __sanitizer_syscall_pre_impl_compat_30___lstat13(long long path, +                                                      long long ub); +void __sanitizer_syscall_post_impl_compat_30___lstat13(long long res, +                                                       long long path, +                                                       long long ub); +void __sanitizer_syscall_pre_impl___sigaltstack14(long long nss, long long oss); +void __sanitizer_syscall_post_impl___sigaltstack14(long long res, long long nss, +                                                   long long oss); +void __sanitizer_syscall_pre_impl___vfork14(void); +void __sanitizer_syscall_post_impl___vfork14(long long res); +void __sanitizer_syscall_pre_impl___posix_chown(long long path, long long uid, +                                                long long gid); +void __sanitizer_syscall_post_impl___posix_chown(long long res, long long path, +                                                 long long uid, long long gid); +void __sanitizer_syscall_pre_impl___posix_fchown(long long fd, long long uid, +                                                 long long gid); +void __sanitizer_syscall_post_impl___posix_fchown(long long res, long long fd, +                                                  long long uid, long long gid); +void __sanitizer_syscall_pre_impl___posix_lchown(long long path, long long uid, +                                                 long long gid); +void __sanitizer_syscall_post_impl___posix_lchown(long long res, long long path, +                                                  long long uid, long long gid); +void __sanitizer_syscall_pre_impl_getsid(long long pid); +void __sanitizer_syscall_post_impl_getsid(long long res, long long pid); +void __sanitizer_syscall_pre_impl___clone(long long flags, long long stack); +void __sanitizer_syscall_post_impl___clone(long long res, long long flags, +                                           long long stack); +void __sanitizer_syscall_pre_impl_fktrace(long long fd, long long ops, +                                          long long facs, long long pid); +void __sanitizer_syscall_post_impl_fktrace(long long res, long long fd, +                                           long long ops, long long facs, +                                           long long pid); +void __sanitizer_syscall_pre_impl_preadv(long long fd, long long iovp, +                                         long long iovcnt, long long PAD, +                                         long long offset); +void __sanitizer_syscall_post_impl_preadv(long long res, long long fd, +                                          long long iovp, long long iovcnt, +                                          long long PAD, long long offset); +void __sanitizer_syscall_pre_impl_pwritev(long long fd, long long iovp, +                                          long long iovcnt, long long PAD, +                                          long long offset); +void __sanitizer_syscall_post_impl_pwritev(long long res, long long fd, +                                           long long iovp, long long iovcnt, +                                           long long PAD, long long offset); +void __sanitizer_syscall_pre_impl_compat_16___sigaction14(long long signum, +                                                          long long nsa, +                                                          long long osa); +void __sanitizer_syscall_post_impl_compat_16___sigaction14(long long res, +                                                           long long signum, +                                                           long long nsa, +                                                           long long osa); +void __sanitizer_syscall_pre_impl___sigpending14(long long set); +void __sanitizer_syscall_post_impl___sigpending14(long long res, long long set); +void __sanitizer_syscall_pre_impl___sigprocmask14(long long how, long long set, +                                                  long long oset); +void __sanitizer_syscall_post_impl___sigprocmask14(long long res, long long how, +                                                   long long set, +                                                   long long oset); +void __sanitizer_syscall_pre_impl___sigsuspend14(long long set); +void __sanitizer_syscall_post_impl___sigsuspend14(long long res, long long set); +void __sanitizer_syscall_pre_impl_compat_16___sigreturn14(long long sigcntxp); +void __sanitizer_syscall_post_impl_compat_16___sigreturn14(long long res, +                                                           long long sigcntxp); +void __sanitizer_syscall_pre_impl___getcwd(long long bufp, long long length); +void __sanitizer_syscall_post_impl___getcwd(long long res, long long bufp, +                                            long long length); +void __sanitizer_syscall_pre_impl_fchroot(long long fd); +void __sanitizer_syscall_post_impl_fchroot(long long res, long long fd); +void __sanitizer_syscall_pre_impl_compat_30_fhopen(long long fhp, +                                                   long long flags); +void __sanitizer_syscall_post_impl_compat_30_fhopen(long long res, +                                                    long long fhp, +                                                    long long flags); +void __sanitizer_syscall_pre_impl_compat_30_fhstat(long long fhp, long long sb); +void __sanitizer_syscall_post_impl_compat_30_fhstat(long long res, +                                                    long long fhp, +                                                    long long sb); +void __sanitizer_syscall_pre_impl_compat_20_fhstatfs(long long fhp, +                                                     long long buf); +void __sanitizer_syscall_post_impl_compat_20_fhstatfs(long long res, +                                                      long long fhp, +                                                      long long buf); +void __sanitizer_syscall_pre_impl_compat_50_____semctl13(long long semid, +                                                         long long semnum, +                                                         long long cmd, +                                                         long long arg); +void __sanitizer_syscall_post_impl_compat_50_____semctl13(long long res, +                                                          long long semid, +                                                          long long semnum, +                                                          long long cmd, +                                                          long long arg); +void __sanitizer_syscall_pre_impl_compat_50___msgctl13(long long msqid, +                                                       long long cmd, +                                                       long long buf); +void __sanitizer_syscall_post_impl_compat_50___msgctl13(long long res, +                                                        long long msqid, +                                                        long long cmd, +                                                        long long buf); +void __sanitizer_syscall_pre_impl_compat_50___shmctl13(long long shmid, +                                                       long long cmd, +                                                       long long buf); +void __sanitizer_syscall_post_impl_compat_50___shmctl13(long long res, +                                                        long long shmid, +                                                        long long cmd, +                                                        long long buf); +void __sanitizer_syscall_pre_impl_lchflags(long long path, long long flags); +void __sanitizer_syscall_post_impl_lchflags(long long res, long long path, +                                            long long flags); +void __sanitizer_syscall_pre_impl_issetugid(void); +void __sanitizer_syscall_post_impl_issetugid(long long res); +void __sanitizer_syscall_pre_impl_utrace(long long label, long long addr, +                                         long long len); +void __sanitizer_syscall_post_impl_utrace(long long res, long long label, +                                          long long addr, long long len); +void __sanitizer_syscall_pre_impl_getcontext(long long ucp); +void __sanitizer_syscall_post_impl_getcontext(long long res, long long ucp); +void __sanitizer_syscall_pre_impl_setcontext(long long ucp); +void __sanitizer_syscall_post_impl_setcontext(long long res, long long ucp); +void __sanitizer_syscall_pre_impl__lwp_create(long long ucp, long long flags, +                                              long long new_lwp); +void __sanitizer_syscall_post_impl__lwp_create(long long res, long long ucp, +                                               long long flags, +                                               long long new_lwp); +void __sanitizer_syscall_pre_impl__lwp_exit(void); +void __sanitizer_syscall_post_impl__lwp_exit(long long res); +void __sanitizer_syscall_pre_impl__lwp_self(void); +void __sanitizer_syscall_post_impl__lwp_self(long long res); +void __sanitizer_syscall_pre_impl__lwp_wait(long long wait_for, +                                            long long departed); +void __sanitizer_syscall_post_impl__lwp_wait(long long res, long long wait_for, +                                             long long departed); +void __sanitizer_syscall_pre_impl__lwp_suspend(long long target); +void __sanitizer_syscall_post_impl__lwp_suspend(long long res, +                                                long long target); +void __sanitizer_syscall_pre_impl__lwp_continue(long long target); +void __sanitizer_syscall_post_impl__lwp_continue(long long res, +                                                 long long target); +void __sanitizer_syscall_pre_impl__lwp_wakeup(long long target); +void __sanitizer_syscall_post_impl__lwp_wakeup(long long res, long long target); +void __sanitizer_syscall_pre_impl__lwp_getprivate(void); +void __sanitizer_syscall_post_impl__lwp_getprivate(long long res); +void __sanitizer_syscall_pre_impl__lwp_setprivate(long long ptr); +void __sanitizer_syscall_post_impl__lwp_setprivate(long long res, +                                                   long long ptr); +void __sanitizer_syscall_pre_impl__lwp_kill(long long target, long long signo); +void __sanitizer_syscall_post_impl__lwp_kill(long long res, long long target, +                                             long long signo); +void __sanitizer_syscall_pre_impl__lwp_detach(long long target); +void __sanitizer_syscall_post_impl__lwp_detach(long long res, long long target); +void __sanitizer_syscall_pre_impl_compat_50__lwp_park(long long ts, +                                                      long long unpark, +                                                      long long hint, +                                                      long long unparkhint); +void __sanitizer_syscall_post_impl_compat_50__lwp_park(long long res, +                                                       long long ts, +                                                       long long unpark, +                                                       long long hint, +                                                       long long unparkhint); +void __sanitizer_syscall_pre_impl__lwp_unpark(long long target, long long hint); +void __sanitizer_syscall_post_impl__lwp_unpark(long long res, long long target, +                                               long long hint); +void __sanitizer_syscall_pre_impl__lwp_unpark_all(long long targets, +                                                  long long ntargets, +                                                  long long hint); +void __sanitizer_syscall_post_impl__lwp_unpark_all(long long res, +                                                   long long targets, +                                                   long long ntargets, +                                                   long long hint); +void __sanitizer_syscall_pre_impl__lwp_setname(long long target, +                                               long long name); +void __sanitizer_syscall_post_impl__lwp_setname(long long res, long long target, +                                                long long name); +void __sanitizer_syscall_pre_impl__lwp_getname(long long target, long long name, +                                               long long len); +void __sanitizer_syscall_post_impl__lwp_getname(long long res, long long target, +                                                long long name, long long len); +void __sanitizer_syscall_pre_impl__lwp_ctl(long long features, +                                           long long address); +void __sanitizer_syscall_post_impl__lwp_ctl(long long res, long long features, +                                            long long address); +/* syscall 326 has been skipped */ +/* syscall 327 has been skipped */ +/* syscall 328 has been skipped */ +/* syscall 329 has been skipped */ +void __sanitizer_syscall_pre_impl_compat_60_sa_register( +    long long newv, long long oldv, long long flags, +    long long stackinfo_offset); +void __sanitizer_syscall_post_impl_compat_60_sa_register( +    long long res, long long newv, long long oldv, long long flags, +    long long stackinfo_offset); +void __sanitizer_syscall_pre_impl_compat_60_sa_stacks(long long num, +                                                      long long stacks); +void __sanitizer_syscall_post_impl_compat_60_sa_stacks(long long res, +                                                       long long num, +                                                       long long stacks); +void __sanitizer_syscall_pre_impl_compat_60_sa_enable(void); +void __sanitizer_syscall_post_impl_compat_60_sa_enable(long long res); +void __sanitizer_syscall_pre_impl_compat_60_sa_setconcurrency( +    long long concurrency); +void __sanitizer_syscall_post_impl_compat_60_sa_setconcurrency( +    long long res, long long concurrency); +void __sanitizer_syscall_pre_impl_compat_60_sa_yield(void); +void __sanitizer_syscall_post_impl_compat_60_sa_yield(long long res); +void __sanitizer_syscall_pre_impl_compat_60_sa_preempt(long long sa_id); +void __sanitizer_syscall_post_impl_compat_60_sa_preempt(long long res, +                                                        long long sa_id); +/* syscall 336 has been skipped */ +/* syscall 337 has been skipped */ +/* syscall 338 has been skipped */ +/* syscall 339 has been skipped */ +void __sanitizer_syscall_pre_impl___sigaction_sigtramp(long long signum, +                                                       long long nsa, +                                                       long long osa, +                                                       long long tramp, +                                                       long long vers); +void __sanitizer_syscall_post_impl___sigaction_sigtramp( +    long long res, long long signum, long long nsa, long long osa, +    long long tramp, long long vers); +void __sanitizer_syscall_pre_impl_pmc_get_info(long long ctr, long long op, +                                               long long args); +void __sanitizer_syscall_post_impl_pmc_get_info(long long res, long long ctr, +                                                long long op, long long args); +void __sanitizer_syscall_pre_impl_pmc_control(long long ctr, long long op, +                                              long long args); +void __sanitizer_syscall_post_impl_pmc_control(long long res, long long ctr, +                                               long long op, long long args); +void __sanitizer_syscall_pre_impl_rasctl(long long addr, long long len, +                                         long long op); +void __sanitizer_syscall_post_impl_rasctl(long long res, long long addr, +                                          long long len, long long op); +void __sanitizer_syscall_pre_impl_kqueue(void); +void __sanitizer_syscall_post_impl_kqueue(long long res); +void __sanitizer_syscall_pre_impl_compat_50_kevent( +    long long fd, long long changelist, long long nchanges, long long eventlist, +    long long nevents, long long timeout); +void __sanitizer_syscall_post_impl_compat_50_kevent( +    long long res, long long fd, long long changelist, long long nchanges, +    long long eventlist, long long nevents, long long timeout); +void __sanitizer_syscall_pre_impl__sched_setparam(long long pid, long long lid, +                                                  long long policy, +                                                  long long params); +void __sanitizer_syscall_post_impl__sched_setparam(long long res, long long pid, +                                                   long long lid, +                                                   long long policy, +                                                   long long params); +void __sanitizer_syscall_pre_impl__sched_getparam(long long pid, long long lid, +                                                  long long policy, +                                                  long long params); +void __sanitizer_syscall_post_impl__sched_getparam(long long res, long long pid, +                                                   long long lid, +                                                   long long policy, +                                                   long long params); +void __sanitizer_syscall_pre_impl__sched_setaffinity(long long pid, +                                                     long long lid, +                                                     long long size, +                                                     long long cpuset); +void __sanitizer_syscall_post_impl__sched_setaffinity(long long res, +                                                      long long pid, +                                                      long long lid, +                                                      long long size, +                                                      long long cpuset); +void __sanitizer_syscall_pre_impl__sched_getaffinity(long long pid, +                                                     long long lid, +                                                     long long size, +                                                     long long cpuset); +void __sanitizer_syscall_post_impl__sched_getaffinity(long long res, +                                                      long long pid, +                                                      long long lid, +                                                      long long size, +                                                      long long cpuset); +void __sanitizer_syscall_pre_impl_sched_yield(void); +void __sanitizer_syscall_post_impl_sched_yield(long long res); +void __sanitizer_syscall_pre_impl__sched_protect(long long priority); +void __sanitizer_syscall_post_impl__sched_protect(long long res, +                                                  long long priority); +/* syscall 352 has been skipped */ +/* syscall 353 has been skipped */ +void __sanitizer_syscall_pre_impl_fsync_range(long long fd, long long flags, +                                              long long start, +                                              long long length); +void __sanitizer_syscall_post_impl_fsync_range(long long res, long long fd, +                                               long long flags, long long start, +                                               long long length); +void __sanitizer_syscall_pre_impl_uuidgen(long long store, long long count); +void __sanitizer_syscall_post_impl_uuidgen(long long res, long long store, +                                           long long count); +void __sanitizer_syscall_pre_impl_getvfsstat(long long buf, long long bufsize, +                                             long long flags); +void __sanitizer_syscall_post_impl_getvfsstat(long long res, long long buf, +                                              long long bufsize, +                                              long long flags); +void __sanitizer_syscall_pre_impl_statvfs1(long long path, long long buf, +                                           long long flags); +void __sanitizer_syscall_post_impl_statvfs1(long long res, long long path, +                                            long long buf, long long flags); +void __sanitizer_syscall_pre_impl_fstatvfs1(long long fd, long long buf, +                                            long long flags); +void __sanitizer_syscall_post_impl_fstatvfs1(long long res, long long fd, +                                             long long buf, long long flags); +void __sanitizer_syscall_pre_impl_compat_30_fhstatvfs1(long long fhp, +                                                       long long buf, +                                                       long long flags); +void __sanitizer_syscall_post_impl_compat_30_fhstatvfs1(long long res, +                                                        long long fhp, +                                                        long long buf, +                                                        long long flags); +void __sanitizer_syscall_pre_impl_extattrctl(long long path, long long cmd, +                                             long long filename, +                                             long long attrnamespace, +                                             long long attrname); +void __sanitizer_syscall_post_impl_extattrctl(long long res, long long path, +                                              long long cmd, long long filename, +                                              long long attrnamespace, +                                              long long attrname); +void __sanitizer_syscall_pre_impl_extattr_set_file(long long path, +                                                   long long attrnamespace, +                                                   long long attrname, +                                                   long long data, +                                                   long long nbytes); +void __sanitizer_syscall_post_impl_extattr_set_file( +    long long res, long long path, long long attrnamespace, long long attrname, +    long long data, long long nbytes); +void __sanitizer_syscall_pre_impl_extattr_get_file(long long path, +                                                   long long attrnamespace, +                                                   long long attrname, +                                                   long long data, +                                                   long long nbytes); +void __sanitizer_syscall_post_impl_extattr_get_file( +    long long res, long long path, long long attrnamespace, long long attrname, +    long long data, long long nbytes); +void __sanitizer_syscall_pre_impl_extattr_delete_file(long long path, +                                                      long long attrnamespace, +                                                      long long attrname); +void __sanitizer_syscall_post_impl_extattr_delete_file(long long res, +                                                       long long path, +                                                       long long attrnamespace, +                                                       long long attrname); +void __sanitizer_syscall_pre_impl_extattr_set_fd(long long fd, +                                                 long long attrnamespace, +                                                 long long attrname, +                                                 long long data, +                                                 long long nbytes); +void __sanitizer_syscall_post_impl_extattr_set_fd(long long res, long long fd, +                                                  long long attrnamespace, +                                                  long long attrname, +                                                  long long data, +                                                  long long nbytes); +void __sanitizer_syscall_pre_impl_extattr_get_fd(long long fd, +                                                 long long attrnamespace, +                                                 long long attrname, +                                                 long long data, +                                                 long long nbytes); +void __sanitizer_syscall_post_impl_extattr_get_fd(long long res, long long fd, +                                                  long long attrnamespace, +                                                  long long attrname, +                                                  long long data, +                                                  long long nbytes); +void __sanitizer_syscall_pre_impl_extattr_delete_fd(long long fd, +                                                    long long attrnamespace, +                                                    long long attrname); +void __sanitizer_syscall_post_impl_extattr_delete_fd(long long res, +                                                     long long fd, +                                                     long long attrnamespace, +                                                     long long attrname); +void __sanitizer_syscall_pre_impl_extattr_set_link(long long path, +                                                   long long attrnamespace, +                                                   long long attrname, +                                                   long long data, +                                                   long long nbytes); +void __sanitizer_syscall_post_impl_extattr_set_link( +    long long res, long long path, long long attrnamespace, long long attrname, +    long long data, long long nbytes); +void __sanitizer_syscall_pre_impl_extattr_get_link(long long path, +                                                   long long attrnamespace, +                                                   long long attrname, +                                                   long long data, +                                                   long long nbytes); +void __sanitizer_syscall_post_impl_extattr_get_link( +    long long res, long long path, long long attrnamespace, long long attrname, +    long long data, long long nbytes); +void __sanitizer_syscall_pre_impl_extattr_delete_link(long long path, +                                                      long long attrnamespace, +                                                      long long attrname); +void __sanitizer_syscall_post_impl_extattr_delete_link(long long res, +                                                       long long path, +                                                       long long attrnamespace, +                                                       long long attrname); +void __sanitizer_syscall_pre_impl_extattr_list_fd(long long fd, +                                                  long long attrnamespace, +                                                  long long data, +                                                  long long nbytes); +void __sanitizer_syscall_post_impl_extattr_list_fd(long long res, long long fd, +                                                   long long attrnamespace, +                                                   long long data, +                                                   long long nbytes); +void __sanitizer_syscall_pre_impl_extattr_list_file(long long path, +                                                    long long attrnamespace, +                                                    long long data, +                                                    long long nbytes); +void __sanitizer_syscall_post_impl_extattr_list_file(long long res, +                                                     long long path, +                                                     long long attrnamespace, +                                                     long long data, +                                                     long long nbytes); +void __sanitizer_syscall_pre_impl_extattr_list_link(long long path, +                                                    long long attrnamespace, +                                                    long long data, +                                                    long long nbytes); +void __sanitizer_syscall_post_impl_extattr_list_link(long long res, +                                                     long long path, +                                                     long long attrnamespace, +                                                     long long data, +                                                     long long nbytes); +void __sanitizer_syscall_pre_impl_compat_50_pselect(long long nd, long long in, +                                                    long long ou, long long ex, +                                                    long long ts, +                                                    long long mask); +void __sanitizer_syscall_post_impl_compat_50_pselect(long long res, +                                                     long long nd, long long in, +                                                     long long ou, long long ex, +                                                     long long ts, +                                                     long long mask); +void __sanitizer_syscall_pre_impl_compat_50_pollts(long long fds, +                                                   long long nfds, long long ts, +                                                   long long mask); +void __sanitizer_syscall_post_impl_compat_50_pollts( +    long long res, long long fds, long long nfds, long long ts, long long mask); +void __sanitizer_syscall_pre_impl_setxattr(long long path, long long name, +                                           long long value, long long size, +                                           long long flags); +void __sanitizer_syscall_post_impl_setxattr(long long res, long long path, +                                            long long name, long long value, +                                            long long size, long long flags); +void __sanitizer_syscall_pre_impl_lsetxattr(long long path, long long name, +                                            long long value, long long size, +                                            long long flags); +void __sanitizer_syscall_post_impl_lsetxattr(long long res, long long path, +                                             long long name, long long value, +                                             long long size, long long flags); +void __sanitizer_syscall_pre_impl_fsetxattr(long long fd, long long name, +                                            long long value, long long size, +                                            long long flags); +void __sanitizer_syscall_post_impl_fsetxattr(long long res, long long fd, +                                             long long name, long long value, +                                             long long size, long long flags); +void __sanitizer_syscall_pre_impl_getxattr(long long path, long long name, +                                           long long value, long long size); +void __sanitizer_syscall_post_impl_getxattr(long long res, long long path, +                                            long long name, long long value, +                                            long long size); +void __sanitizer_syscall_pre_impl_lgetxattr(long long path, long long name, +                                            long long value, long long size); +void __sanitizer_syscall_post_impl_lgetxattr(long long res, long long path, +                                             long long name, long long value, +                                             long long size); +void __sanitizer_syscall_pre_impl_fgetxattr(long long fd, long long name, +                                            long long value, long long size); +void __sanitizer_syscall_post_impl_fgetxattr(long long res, long long fd, +                                             long long name, long long value, +                                             long long size); +void __sanitizer_syscall_pre_impl_listxattr(long long path, long long list, +                                            long long size); +void __sanitizer_syscall_post_impl_listxattr(long long res, long long path, +                                             long long list, long long size); +void __sanitizer_syscall_pre_impl_llistxattr(long long path, long long list, +                                             long long size); +void __sanitizer_syscall_post_impl_llistxattr(long long res, long long path, +                                              long long list, long long size); +void __sanitizer_syscall_pre_impl_flistxattr(long long fd, long long list, +                                             long long size); +void __sanitizer_syscall_post_impl_flistxattr(long long res, long long fd, +                                              long long list, long long size); +void __sanitizer_syscall_pre_impl_removexattr(long long path, long long name); +void __sanitizer_syscall_post_impl_removexattr(long long res, long long path, +                                               long long name); +void __sanitizer_syscall_pre_impl_lremovexattr(long long path, long long name); +void __sanitizer_syscall_post_impl_lremovexattr(long long res, long long path, +                                                long long name); +void __sanitizer_syscall_pre_impl_fremovexattr(long long fd, long long name); +void __sanitizer_syscall_post_impl_fremovexattr(long long res, long long fd, +                                                long long name); +void __sanitizer_syscall_pre_impl_compat_50___stat30(long long path, +                                                     long long ub); +void __sanitizer_syscall_post_impl_compat_50___stat30(long long res, +                                                      long long path, +                                                      long long ub); +void __sanitizer_syscall_pre_impl_compat_50___fstat30(long long fd, +                                                      long long sb); +void __sanitizer_syscall_post_impl_compat_50___fstat30(long long res, +                                                       long long fd, +                                                       long long sb); +void __sanitizer_syscall_pre_impl_compat_50___lstat30(long long path, +                                                      long long ub); +void __sanitizer_syscall_post_impl_compat_50___lstat30(long long res, +                                                       long long path, +                                                       long long ub); +void __sanitizer_syscall_pre_impl___getdents30(long long fd, long long buf, +                                               long long count); +void __sanitizer_syscall_post_impl___getdents30(long long res, long long fd, +                                                long long buf, long long count); +void __sanitizer_syscall_pre_impl_posix_fadvise(long long); +void __sanitizer_syscall_post_impl_posix_fadvise(long long res, long long); +void __sanitizer_syscall_pre_impl_compat_30___fhstat30(long long fhp, +                                                       long long sb); +void __sanitizer_syscall_post_impl_compat_30___fhstat30(long long res, +                                                        long long fhp, +                                                        long long sb); +void __sanitizer_syscall_pre_impl_compat_50___ntp_gettime30(long long ntvp); +void __sanitizer_syscall_post_impl_compat_50___ntp_gettime30(long long res, +                                                             long long ntvp); +void __sanitizer_syscall_pre_impl___socket30(long long domain, long long type, +                                             long long protocol); +void __sanitizer_syscall_post_impl___socket30(long long res, long long domain, +                                              long long type, +                                              long long protocol); +void __sanitizer_syscall_pre_impl___getfh30(long long fname, long long fhp, +                                            long long fh_size); +void __sanitizer_syscall_post_impl___getfh30(long long res, long long fname, +                                             long long fhp, long long fh_size); +void __sanitizer_syscall_pre_impl___fhopen40(long long fhp, long long fh_size, +                                             long long flags); +void __sanitizer_syscall_post_impl___fhopen40(long long res, long long fhp, +                                              long long fh_size, +                                              long long flags); +void __sanitizer_syscall_pre_impl___fhstatvfs140(long long fhp, +                                                 long long fh_size, +                                                 long long buf, +                                                 long long flags); +void __sanitizer_syscall_post_impl___fhstatvfs140(long long res, long long fhp, +                                                  long long fh_size, +                                                  long long buf, +                                                  long long flags); +void __sanitizer_syscall_pre_impl_compat_50___fhstat40(long long fhp, +                                                       long long fh_size, +                                                       long long sb); +void __sanitizer_syscall_post_impl_compat_50___fhstat40(long long res, +                                                        long long fhp, +                                                        long long fh_size, +                                                        long long sb); +void __sanitizer_syscall_pre_impl_aio_cancel(long long fildes, +                                             long long aiocbp); +void __sanitizer_syscall_post_impl_aio_cancel(long long res, long long fildes, +                                              long long aiocbp); +void __sanitizer_syscall_pre_impl_aio_error(long long aiocbp); +void __sanitizer_syscall_post_impl_aio_error(long long res, long long aiocbp); +void __sanitizer_syscall_pre_impl_aio_fsync(long long op, long long aiocbp); +void __sanitizer_syscall_post_impl_aio_fsync(long long res, long long op, +                                             long long aiocbp); +void __sanitizer_syscall_pre_impl_aio_read(long long aiocbp); +void __sanitizer_syscall_post_impl_aio_read(long long res, long long aiocbp); +void __sanitizer_syscall_pre_impl_aio_return(long long aiocbp); +void __sanitizer_syscall_post_impl_aio_return(long long res, long long aiocbp); +void __sanitizer_syscall_pre_impl_compat_50_aio_suspend(long long list, +                                                        long long nent, +                                                        long long timeout); +void __sanitizer_syscall_post_impl_compat_50_aio_suspend(long long res, +                                                         long long list, +                                                         long long nent, +                                                         long long timeout); +void __sanitizer_syscall_pre_impl_aio_write(long long aiocbp); +void __sanitizer_syscall_post_impl_aio_write(long long res, long long aiocbp); +void __sanitizer_syscall_pre_impl_lio_listio(long long mode, long long list, +                                             long long nent, long long sig); +void __sanitizer_syscall_post_impl_lio_listio(long long res, long long mode, +                                              long long list, long long nent, +                                              long long sig); +/* syscall 407 has been skipped */ +/* syscall 408 has been skipped */ +/* syscall 409 has been skipped */ +void __sanitizer_syscall_pre_impl___mount50(long long type, long long path, +                                            long long flags, long long data, +                                            long long data_len); +void __sanitizer_syscall_post_impl___mount50(long long res, long long type, +                                             long long path, long long flags, +                                             long long data, +                                             long long data_len); +void __sanitizer_syscall_pre_impl_mremap(long long old_address, +                                         long long old_size, +                                         long long new_address, +                                         long long new_size, long long flags); +void __sanitizer_syscall_post_impl_mremap(long long res, long long old_address, +                                          long long old_size, +                                          long long new_address, +                                          long long new_size, long long flags); +void __sanitizer_syscall_pre_impl_pset_create(long long psid); +void __sanitizer_syscall_post_impl_pset_create(long long res, long long psid); +void __sanitizer_syscall_pre_impl_pset_destroy(long long psid); +void __sanitizer_syscall_post_impl_pset_destroy(long long res, long long psid); +void __sanitizer_syscall_pre_impl_pset_assign(long long psid, long long cpuid, +                                              long long opsid); +void __sanitizer_syscall_post_impl_pset_assign(long long res, long long psid, +                                               long long cpuid, +                                               long long opsid); +void __sanitizer_syscall_pre_impl__pset_bind(long long idtype, +                                             long long first_id, +                                             long long second_id, +                                             long long psid, long long opsid); +void __sanitizer_syscall_post_impl__pset_bind(long long res, long long idtype, +                                              long long first_id, +                                              long long second_id, +                                              long long psid, long long opsid); +void __sanitizer_syscall_pre_impl___posix_fadvise50(long long fd, long long PAD, +                                                    long long offset, +                                                    long long len, +                                                    long long advice); +void __sanitizer_syscall_post_impl___posix_fadvise50( +    long long res, long long fd, long long PAD, long long offset, long long len, +    long long advice); +void __sanitizer_syscall_pre_impl___select50(long long nd, long long in, +                                             long long ou, long long ex, +                                             long long tv); +void __sanitizer_syscall_post_impl___select50(long long res, long long nd, +                                              long long in, long long ou, +                                              long long ex, long long tv); +void __sanitizer_syscall_pre_impl___gettimeofday50(long long tp, long long tzp); +void __sanitizer_syscall_post_impl___gettimeofday50(long long res, long long tp, +                                                    long long tzp); +void __sanitizer_syscall_pre_impl___settimeofday50(long long tv, long long tzp); +void __sanitizer_syscall_post_impl___settimeofday50(long long res, long long tv, +                                                    long long tzp); +void __sanitizer_syscall_pre_impl___utimes50(long long path, long long tptr); +void __sanitizer_syscall_post_impl___utimes50(long long res, long long path, +                                              long long tptr); +void __sanitizer_syscall_pre_impl___adjtime50(long long delta, +                                              long long olddelta); +void __sanitizer_syscall_post_impl___adjtime50(long long res, long long delta, +                                               long long olddelta); +void __sanitizer_syscall_pre_impl___lfs_segwait50(long long fsidp, +                                                  long long tv); +void __sanitizer_syscall_post_impl___lfs_segwait50(long long res, +                                                   long long fsidp, +                                                   long long tv); +void __sanitizer_syscall_pre_impl___futimes50(long long fd, long long tptr); +void __sanitizer_syscall_post_impl___futimes50(long long res, long long fd, +                                               long long tptr); +void __sanitizer_syscall_pre_impl___lutimes50(long long path, long long tptr); +void __sanitizer_syscall_post_impl___lutimes50(long long res, long long path, +                                               long long tptr); +void __sanitizer_syscall_pre_impl___setitimer50(long long which, long long itv, +                                                long long oitv); +void __sanitizer_syscall_post_impl___setitimer50(long long res, long long which, +                                                 long long itv, long long oitv); +void __sanitizer_syscall_pre_impl___getitimer50(long long which, long long itv); +void __sanitizer_syscall_post_impl___getitimer50(long long res, long long which, +                                                 long long itv); +void __sanitizer_syscall_pre_impl___clock_gettime50(long long clock_id, +                                                    long long tp); +void __sanitizer_syscall_post_impl___clock_gettime50(long long res, +                                                     long long clock_id, +                                                     long long tp); +void __sanitizer_syscall_pre_impl___clock_settime50(long long clock_id, +                                                    long long tp); +void __sanitizer_syscall_post_impl___clock_settime50(long long res, +                                                     long long clock_id, +                                                     long long tp); +void __sanitizer_syscall_pre_impl___clock_getres50(long long clock_id, +                                                   long long tp); +void __sanitizer_syscall_post_impl___clock_getres50(long long res, +                                                    long long clock_id, +                                                    long long tp); +void __sanitizer_syscall_pre_impl___nanosleep50(long long rqtp, long long rmtp); +void __sanitizer_syscall_post_impl___nanosleep50(long long res, long long rqtp, +                                                 long long rmtp); +void __sanitizer_syscall_pre_impl_____sigtimedwait50(long long set, +                                                     long long info, +                                                     long long timeout); +void __sanitizer_syscall_post_impl_____sigtimedwait50(long long res, +                                                      long long set, +                                                      long long info, +                                                      long long timeout); +void __sanitizer_syscall_pre_impl___mq_timedsend50(long long mqdes, +                                                   long long msg_ptr, +                                                   long long msg_len, +                                                   long long msg_prio, +                                                   long long abs_timeout); +void __sanitizer_syscall_post_impl___mq_timedsend50( +    long long res, long long mqdes, long long msg_ptr, long long msg_len, +    long long msg_prio, long long abs_timeout); +void __sanitizer_syscall_pre_impl___mq_timedreceive50(long long mqdes, +                                                      long long msg_ptr, +                                                      long long msg_len, +                                                      long long msg_prio, +                                                      long long abs_timeout); +void __sanitizer_syscall_post_impl___mq_timedreceive50( +    long long res, long long mqdes, long long msg_ptr, long long msg_len, +    long long msg_prio, long long abs_timeout); +void __sanitizer_syscall_pre_impl_compat_60__lwp_park(long long ts, +                                                      long long unpark, +                                                      long long hint, +                                                      long long unparkhint); +void __sanitizer_syscall_post_impl_compat_60__lwp_park(long long res, +                                                       long long ts, +                                                       long long unpark, +                                                       long long hint, +                                                       long long unparkhint); +void __sanitizer_syscall_pre_impl___kevent50(long long fd, long long changelist, +                                             long long nchanges, +                                             long long eventlist, +                                             long long nevents, +                                             long long timeout); +void __sanitizer_syscall_post_impl___kevent50( +    long long res, long long fd, long long changelist, long long nchanges, +    long long eventlist, long long nevents, long long timeout); +void __sanitizer_syscall_pre_impl___pselect50(long long nd, long long in, +                                              long long ou, long long ex, +                                              long long ts, long long mask); +void __sanitizer_syscall_post_impl___pselect50(long long res, long long nd, +                                               long long in, long long ou, +                                               long long ex, long long ts, +                                               long long mask); +void __sanitizer_syscall_pre_impl___pollts50(long long fds, long long nfds, +                                             long long ts, long long mask); +void __sanitizer_syscall_post_impl___pollts50(long long res, long long fds, +                                              long long nfds, long long ts, +                                              long long mask); +void __sanitizer_syscall_pre_impl___aio_suspend50(long long list, +                                                  long long nent, +                                                  long long timeout); +void __sanitizer_syscall_post_impl___aio_suspend50(long long res, +                                                   long long list, +                                                   long long nent, +                                                   long long timeout); +void __sanitizer_syscall_pre_impl___stat50(long long path, long long ub); +void __sanitizer_syscall_post_impl___stat50(long long res, long long path, +                                            long long ub); +void __sanitizer_syscall_pre_impl___fstat50(long long fd, long long sb); +void __sanitizer_syscall_post_impl___fstat50(long long res, long long fd, +                                             long long sb); +void __sanitizer_syscall_pre_impl___lstat50(long long path, long long ub); +void __sanitizer_syscall_post_impl___lstat50(long long res, long long path, +                                             long long ub); +void __sanitizer_syscall_pre_impl_____semctl50(long long semid, +                                               long long semnum, long long cmd, +                                               long long arg); +void __sanitizer_syscall_post_impl_____semctl50(long long res, long long semid, +                                                long long semnum, long long cmd, +                                                long long arg); +void __sanitizer_syscall_pre_impl___shmctl50(long long shmid, long long cmd, +                                             long long buf); +void __sanitizer_syscall_post_impl___shmctl50(long long res, long long shmid, +                                              long long cmd, long long buf); +void __sanitizer_syscall_pre_impl___msgctl50(long long msqid, long long cmd, +                                             long long buf); +void __sanitizer_syscall_post_impl___msgctl50(long long res, long long msqid, +                                              long long cmd, long long buf); +void __sanitizer_syscall_pre_impl___getrusage50(long long who, +                                                long long rusage); +void __sanitizer_syscall_post_impl___getrusage50(long long res, long long who, +                                                 long long rusage); +void __sanitizer_syscall_pre_impl___timer_settime50(long long timerid, +                                                    long long flags, +                                                    long long value, +                                                    long long ovalue); +void __sanitizer_syscall_post_impl___timer_settime50(long long res, +                                                     long long timerid, +                                                     long long flags, +                                                     long long value, +                                                     long long ovalue); +void __sanitizer_syscall_pre_impl___timer_gettime50(long long timerid, +                                                    long long value); +void __sanitizer_syscall_post_impl___timer_gettime50(long long res, +                                                     long long timerid, +                                                     long long value); +#if defined(NTP) || !defined(_KERNEL_OPT) +void __sanitizer_syscall_pre_impl___ntp_gettime50(long long ntvp); +void __sanitizer_syscall_post_impl___ntp_gettime50(long long res, +                                                   long long ntvp); +#else +/* syscall 448 has been skipped */ +#endif +void __sanitizer_syscall_pre_impl___wait450(long long pid, long long status, +                                            long long options, +                                            long long rusage); +void __sanitizer_syscall_post_impl___wait450(long long res, long long pid, +                                             long long status, +                                             long long options, +                                             long long rusage); +void __sanitizer_syscall_pre_impl___mknod50(long long path, long long mode, +                                            long long dev); +void __sanitizer_syscall_post_impl___mknod50(long long res, long long path, +                                             long long mode, long long dev); +void __sanitizer_syscall_pre_impl___fhstat50(long long fhp, long long fh_size, +                                             long long sb); +void __sanitizer_syscall_post_impl___fhstat50(long long res, long long fhp, +                                              long long fh_size, long long sb); +/* syscall 452 has been skipped */ +void __sanitizer_syscall_pre_impl_pipe2(long long fildes, long long flags); +void __sanitizer_syscall_post_impl_pipe2(long long res, long long fildes, +                                         long long flags); +void __sanitizer_syscall_pre_impl_dup3(long long from, long long to, +                                       long long flags); +void __sanitizer_syscall_post_impl_dup3(long long res, long long from, +                                        long long to, long long flags); +void __sanitizer_syscall_pre_impl_kqueue1(long long flags); +void __sanitizer_syscall_post_impl_kqueue1(long long res, long long flags); +void __sanitizer_syscall_pre_impl_paccept(long long s, long long name, +                                          long long anamelen, long long mask, +                                          long long flags); +void __sanitizer_syscall_post_impl_paccept(long long res, long long s, +                                           long long name, long long anamelen, +                                           long long mask, long long flags); +void __sanitizer_syscall_pre_impl_linkat(long long fd1, long long name1, +                                         long long fd2, long long name2, +                                         long long flags); +void __sanitizer_syscall_post_impl_linkat(long long res, long long fd1, +                                          long long name1, long long fd2, +                                          long long name2, long long flags); +void __sanitizer_syscall_pre_impl_renameat(long long fromfd, long long from, +                                           long long tofd, long long to); +void __sanitizer_syscall_post_impl_renameat(long long res, long long fromfd, +                                            long long from, long long tofd, +                                            long long to); +void __sanitizer_syscall_pre_impl_mkfifoat(long long fd, long long path, +                                           long long mode); +void __sanitizer_syscall_post_impl_mkfifoat(long long res, long long fd, +                                            long long path, long long mode); +void __sanitizer_syscall_pre_impl_mknodat(long long fd, long long path, +                                          long long mode, long long PAD, +                                          long long dev); +void __sanitizer_syscall_post_impl_mknodat(long long res, long long fd, +                                           long long path, long long mode, +                                           long long PAD, long long dev); +void __sanitizer_syscall_pre_impl_mkdirat(long long fd, long long path, +                                          long long mode); +void __sanitizer_syscall_post_impl_mkdirat(long long res, long long fd, +                                           long long path, long long mode); +void __sanitizer_syscall_pre_impl_faccessat(long long fd, long long path, +                                            long long amode, long long flag); +void __sanitizer_syscall_post_impl_faccessat(long long res, long long fd, +                                             long long path, long long amode, +                                             long long flag); +void __sanitizer_syscall_pre_impl_fchmodat(long long fd, long long path, +                                           long long mode, long long flag); +void __sanitizer_syscall_post_impl_fchmodat(long long res, long long fd, +                                            long long path, long long mode, +                                            long long flag); +void __sanitizer_syscall_pre_impl_fchownat(long long fd, long long path, +                                           long long owner, long long group, +                                           long long flag); +void __sanitizer_syscall_post_impl_fchownat(long long res, long long fd, +                                            long long path, long long owner, +                                            long long group, long long flag); +void __sanitizer_syscall_pre_impl_fexecve(long long fd, long long argp, +                                          long long envp); +void __sanitizer_syscall_post_impl_fexecve(long long res, long long fd, +                                           long long argp, long long envp); +void __sanitizer_syscall_pre_impl_fstatat(long long fd, long long path, +                                          long long buf, long long flag); +void __sanitizer_syscall_post_impl_fstatat(long long res, long long fd, +                                           long long path, long long buf, +                                           long long flag); +void __sanitizer_syscall_pre_impl_utimensat(long long fd, long long path, +                                            long long tptr, long long flag); +void __sanitizer_syscall_post_impl_utimensat(long long res, long long fd, +                                             long long path, long long tptr, +                                             long long flag); +void __sanitizer_syscall_pre_impl_openat(long long fd, long long path, +                                         long long oflags, long long mode); +void __sanitizer_syscall_post_impl_openat(long long res, long long fd, +                                          long long path, long long oflags, +                                          long long mode); +void __sanitizer_syscall_pre_impl_readlinkat(long long fd, long long path, +                                             long long buf, long long bufsize); +void __sanitizer_syscall_post_impl_readlinkat(long long res, long long fd, +                                              long long path, long long buf, +                                              long long bufsize); +void __sanitizer_syscall_pre_impl_symlinkat(long long path1, long long fd, +                                            long long path2); +void __sanitizer_syscall_post_impl_symlinkat(long long res, long long path1, +                                             long long fd, long long path2); +void __sanitizer_syscall_pre_impl_unlinkat(long long fd, long long path, +                                           long long flag); +void __sanitizer_syscall_post_impl_unlinkat(long long res, long long fd, +                                            long long path, long long flag); +void __sanitizer_syscall_pre_impl_futimens(long long fd, long long tptr); +void __sanitizer_syscall_post_impl_futimens(long long res, long long fd, +                                            long long tptr); +void __sanitizer_syscall_pre_impl___quotactl(long long path, long long args); +void __sanitizer_syscall_post_impl___quotactl(long long res, long long path, +                                              long long args); +void __sanitizer_syscall_pre_impl_posix_spawn(long long pid, long long path, +                                              long long file_actions, +                                              long long attrp, long long argv, +                                              long long envp); +void __sanitizer_syscall_post_impl_posix_spawn(long long res, long long pid, +                                               long long path, +                                               long long file_actions, +                                               long long attrp, long long argv, +                                               long long envp); +void __sanitizer_syscall_pre_impl_recvmmsg(long long s, long long mmsg, +                                           long long vlen, long long flags, +                                           long long timeout); +void __sanitizer_syscall_post_impl_recvmmsg(long long res, long long s, +                                            long long mmsg, long long vlen, +                                            long long flags, long long timeout); +void __sanitizer_syscall_pre_impl_sendmmsg(long long s, long long mmsg, +                                           long long vlen, long long flags); +void __sanitizer_syscall_post_impl_sendmmsg(long long res, long long s, +                                            long long mmsg, long long vlen, +                                            long long flags); +void __sanitizer_syscall_pre_impl_clock_nanosleep(long long clock_id, +                                                  long long flags, +                                                  long long rqtp, +                                                  long long rmtp); +void __sanitizer_syscall_post_impl_clock_nanosleep(long long res, +                                                   long long clock_id, +                                                   long long flags, +                                                   long long rqtp, +                                                   long long rmtp); +void __sanitizer_syscall_pre_impl____lwp_park60(long long clock_id, +                                                long long flags, long long ts, +                                                long long unpark, +                                                long long hint, +                                                long long unparkhint); +void __sanitizer_syscall_post_impl____lwp_park60( +    long long res, long long clock_id, long long flags, long long ts, +    long long unpark, long long hint, long long unparkhint); +void __sanitizer_syscall_pre_impl_posix_fallocate(long long fd, long long PAD, +                                                  long long pos, long long len); +void __sanitizer_syscall_post_impl_posix_fallocate(long long res, long long fd, +                                                   long long PAD, long long pos, +                                                   long long len); +void __sanitizer_syscall_pre_impl_fdiscard(long long fd, long long PAD, +                                           long long pos, long long len); +void __sanitizer_syscall_post_impl_fdiscard(long long res, long long fd, +                                            long long PAD, long long pos, +                                            long long len); +void __sanitizer_syscall_pre_impl_wait6(long long idtype, long long id, +                                        long long status, long long options, +                                        long long wru, long long info); +void __sanitizer_syscall_post_impl_wait6(long long res, long long idtype, +                                         long long id, long long status, +                                         long long options, long long wru, +                                         long long info); +void __sanitizer_syscall_pre_impl_clock_getcpuclockid2(long long idtype, +                                                       long long id, +                                                       long long clock_id); +void __sanitizer_syscall_post_impl_clock_getcpuclockid2(long long res, +                                                        long long idtype, +                                                        long long id, +                                                        long long clock_id); + +#ifdef __cplusplus +} // extern "C" +#endif + +// DO NOT EDIT! THIS FILE HAS BEEN GENERATED! + +#endif // SANITIZER_NETBSD_SYSCALL_HOOKS_H diff --git a/include/sanitizer/scudo_interface.h b/include/sanitizer/scudo_interface.h index ec7a9e4e150c4..be605f1d7fd93 100644 --- a/include/sanitizer/scudo_interface.h +++ b/include/sanitizer/scudo_interface.h @@ -26,7 +26,12 @@ extern "C" {    // the hard limit (HardLimit=1) or the soft limit (HardLimit=0). The limit    // can be removed by setting LimitMb to 0. This function's parameters should    // be fully trusted to avoid security mishaps. -  void __scudo_set_rss_limit(unsigned long LimitMb, int HardLimit); +  void __scudo_set_rss_limit(size_t LimitMb, int HardLimit); + +  // This function outputs various allocator statistics for both the Primary +  // and Secondary allocators, including memory usage, number of allocations +  // and deallocations. +  void __scudo_print_stats(void);  #ifdef __cplusplus  }  // extern "C"  #endif diff --git a/include/xray/xray_interface.h b/include/xray/xray_interface.h index d08039a67fa20..ba4c0e81269dd 100644 --- a/include/xray/xray_interface.h +++ b/include/xray/xray_interface.h @@ -27,6 +27,7 @@ enum XRayEntryType {    TAIL = 2,    LOG_ARGS_ENTRY = 3,    CUSTOM_EVENT = 4, +  TYPED_EVENT = 5,  };  /// Provide a function to invoke for when instrumentation points are hit. This @@ -68,12 +69,23 @@ extern int __xray_set_handler_arg1(void (*entry)(int32_t, XRayEntryType,  extern int __xray_remove_handler_arg1();  /// Provide a function to invoke when XRay encounters a custom event. -extern int __xray_set_customevent_handler(void (*entry)(void*, std::size_t)); +extern int __xray_set_customevent_handler(void (*entry)(void *, std::size_t));  /// This removes whatever the currently provided custom event handler is.  /// Returns 1 on success, 0 on error.  extern int __xray_remove_customevent_handler(); +/// Set a handler for xray typed event logging. The first parameter is a type +/// identifier, the second is a payload, and the third is the payload size. +extern int __xray_set_typedevent_handler(void (*entry)(uint16_t, const void *, +                                                       std::size_t)); + +/// Removes the currently set typed event handler. +/// Returns 1 on success, 0 on error. +extern int __xray_remove_typedevent_handler(); + +extern uint16_t __xray_register_event_type(const char *event_type); +  enum XRayPatchingStatus {    NOT_INITIALIZED = 0,    SUCCESS = 1, diff --git a/include/xray/xray_log_interface.h b/include/xray/xray_log_interface.h index 6c53cdaebfe22..5f8b3a4a06a4a 100644 --- a/include/xray/xray_log_interface.h +++ b/include/xray/xray_log_interface.h @@ -21,27 +21,29 @@  ///  /// The high-level usage pattern for these APIs look like the following:  /// -///   // Before we try initializing the log implementation, we must set it as -///   // the log implementation. We provide the function pointers that define -///   // the various initialization, finalization, and other pluggable hooks -///   // that we need. -///   __xray_set_log_impl({...}); -/// -///   // Once that's done, we can now initialize the implementation. Each -///   // implementation has a chance to let users customize the implementation -///   // with a struct that their implementation supports. Roughly this might -///   // look like: -///   MyImplementationOptions opts; -///   opts.enable_feature = true; -///   ... -///   auto init_status = __xray_log_init( -///       BufferSize, MaxBuffers, &opts, sizeof opts); -///   if (init_status != XRayLogInitStatus::XRAY_LOG_INITIALIZED) { +///   // We choose the mode which we'd like to install, and check whether this +///   // has succeeded. Each mode will have their own set of flags they will +///   // support, outside of the global XRay configuration options that are +///   // defined in the XRAY_OPTIONS environment variable. +///   auto select_status = __xray_log_select_mode("xray-fdr"); +///   if (select_status != XRayLogRegisterStatus::XRAY_REGISTRATION_OK) { +///     // This failed, we should not proceed with attempting to initialise +///     // the currently selected mode. +///     return; +///   } +/// +///   // Once that's done, we can now attempt to configure the implementation. +///   // To do this, we provide the string flags configuration for the mode. +///   auto config_status = __xray_log_init_mode( +///       "xray-fdr", "verbosity=1 some_flag=1 another_flag=2"); +///   if (config_status != XRayLogInitStatus::XRAY_LOG_INITIALIZED) {  ///     // deal with the error here, if there is one.  ///   }  ///  ///   // When the log implementation has had the chance to initialize, we can -///   // now patch the sleds. +///   // now patch the instrumentation points. Note that we could have patched +///   // the instrumentation points first, but there's no strict ordering to +///   // these operations.  ///   auto patch_status = __xray_patch();  ///   if (patch_status != XRayPatchingStatus::SUCCESS) {  ///     // deal with the error here, if it is an error. @@ -56,12 +58,12 @@  ///  ///   // We can optionally wait before flushing the log to give other threads a  ///   // chance to see that the implementation is already finalized. Also, at -///   // this point we can optionally unpatch the sleds to reduce overheads at -///   // runtime. +///   // this point we can optionally unpatch the instrumentation points to +///   // reduce overheads at runtime.  ///   auto unpatch_status = __xray_unpatch();  ///   if (unpatch_status != XRayPatchingStatus::SUCCESS) { -//      // deal with the error here, if it is an error. -//    } +///     // deal with the error here, if it is an error. +///   }  ///  ///   // If there are logs or data to be flushed somewhere, we can do so only  ///   // after we've finalized the log. Some implementations may not actually @@ -72,6 +74,17 @@  ///     // deal with the error here, if it is an error.  ///   }  /// +///   // Alternatively, we can go through the buffers ourselves without +///   // relying on the implementations' flushing semantics (if the +///   // implementation supports exporting this data directly). +///   auto MyBufferProcessor = +[](const char* mode, XRayBuffer buffer) { +///     // Check the "mode" to see if it's something we know how to handle... +///     // and/or do something with an XRayBuffer instance. +///   }; +///   auto process_status = __xray_log_process_buffers(MyBufferProcessor); +///   if (process_status != XRayLogFlushStatus::XRAY_LOG_FLUSHED) { +///     // deal with the error here, if it is an error. +///   }  ///  /// NOTE: Before calling __xray_patch() again, consider re-initializing the  /// implementation first. Some implementations might stay in an "off" state when @@ -182,9 +195,13 @@ struct XRayLogImpl {    XRayLogFlushStatus (*flush_log)();  }; +/// DEPRECATED: Use the mode registration workflow instead with +/// __xray_log_register_mode(...) and __xray_log_select_mode(...). See the +/// documentation for those function. +///  /// This function installs a new logging implementation that XRay will use. In  /// case there are any nullptr members in Impl, XRay will *uninstall any -/// existing implementations*. It does NOT patch the instrumentation sleds. +/// existing implementations*. It does NOT patch the instrumentation points.  ///  /// NOTE: This function does NOT attempt to finalize the currently installed  /// implementation. Use with caution. @@ -227,9 +244,14 @@ XRayLogRegisterStatus __xray_log_register_mode(const char *Mode,  ///     does not update the currently installed implementation.  XRayLogRegisterStatus __xray_log_select_mode(const char *Mode); +/// Returns an identifier for the currently selected XRay mode chosen through +/// the __xray_log_select_mode(...) function call. Returns nullptr if there is +/// no currently installed mode. +const char *__xray_log_get_current_mode(); +  /// This function removes the currently installed implementation. It will also  /// uninstall any handlers that have been previously installed. It does NOT -/// unpatch the instrumentation sleds. +/// unpatch the instrumentation points.  ///  /// NOTE: This function does NOT attempt to finalize the currently installed  /// implementation. Use with caution. @@ -244,11 +266,37 @@ XRayLogRegisterStatus __xray_log_select_mode(const char *Mode);  /// called while in any other states.  void __xray_remove_log_impl(); +/// DEPRECATED: Use __xray_log_init_mode() instead, and provide all the options +/// in string form.  /// Invokes the installed implementation initialization routine. See  /// XRayLogInitStatus for what the return values mean.  XRayLogInitStatus __xray_log_init(size_t BufferSize, size_t MaxBuffers,                                    void *Args, size_t ArgsSize); +/// Invokes the installed initialization routine, which *must* support the +/// string based form. +/// +/// NOTE: When this API is used, we still invoke the installed initialization +/// routine, but we will call it with the following convention to signal that we +/// are using the string form: +/// +/// - BufferSize = 0 +/// - MaxBuffers = 0 +/// - ArgsSize = 0 +/// - Args will be the pointer to the character buffer representing the +///   configuration. +/// +/// FIXME: Updating the XRayLogImpl struct is an ABI breaking change. When we +/// are ready to make a breaking change, we should clean this up appropriately. +XRayLogInitStatus __xray_log_init_mode(const char *Mode, const char *Config); + +/// Like __xray_log_init_mode(...) this version allows for providing +/// configurations that might have non-null-terminated strings. This will +/// operate similarly to __xray_log_init_mode, with the exception that +/// |ArgsSize| will be what |ConfigSize| is. +XRayLogInitStatus __xray_log_init_mode_bin(const char *Mode, const char *Config, +                                           size_t ConfigSize); +  /// Invokes the installed implementation finalization routine. See  /// XRayLogInitStatus for what the return values mean.  XRayLogInitStatus __xray_log_finalize(); @@ -257,16 +305,68 @@ XRayLogInitStatus __xray_log_finalize();  /// XRayLogFlushStatus for what the return values mean.  XRayLogFlushStatus __xray_log_flushLog(); +/// An XRayBuffer represents a section of memory which can be treated by log +/// processing functions as bytes stored in the logging implementation's +/// buffers. +struct XRayBuffer { +  const void *Data; +  size_t Size; +}; + +/// Registers an iterator function which takes an XRayBuffer argument, then +/// returns another XRayBuffer function representing the next buffer. When the +/// Iterator function returns an empty XRayBuffer (Data = nullptr, Size = 0), +/// this signifies the end of the buffers. +/// +/// The first invocation of this Iterator function will always take an empty +/// XRayBuffer (Data = nullptr, Size = 0). +void __xray_log_set_buffer_iterator(XRayBuffer (*Iterator)(XRayBuffer)); + +/// Removes the currently registered buffer iterator function. +void __xray_log_remove_buffer_iterator(); + +/// Invokes the provided handler to process data maintained by the logging +/// handler. This API will be provided raw access to the data available in +/// memory from the logging implementation. The callback function must: +/// +/// 1) Not modify the data, to avoid running into undefined behaviour. +/// +/// 2) Either know the data layout, or treat the data as raw bytes for later +///    interpretation. +/// +/// This API is best used in place of the `__xray_log_flushLog()` implementation +/// above to enable the caller to provide an alternative means of extracting the +/// data from the XRay implementation. +/// +/// Implementations MUST then provide: +/// +/// 1) A function that will return an XRayBuffer. Functions that return an +///    "empty" XRayBuffer signifies that there are no more buffers to be +///    processed. This function should be registered through the +///    `__xray_log_set_buffer_iterator(...)` function. +/// +/// 2) Its own means of converting data it holds in memory into an XRayBuffer +///    structure. +/// +/// See XRayLogFlushStatus for what the return values mean. +/// +XRayLogFlushStatus __xray_log_process_buffers(void (*Processor)(const char *, +                                                                XRayBuffer)); +  } // extern "C"  namespace __xray { +/// DEPRECATED: Use __xray_log_init_mode(...) instead, and provide flag +/// configuration strings to set the options instead.  /// Options used by the LLVM XRay FDR logging implementation.  struct FDRLoggingOptions {    bool ReportErrors = false;    int Fd = -1;  }; +/// DEPRECATED: Use __xray_log_init_mode(...) instead, and provide flag +/// configuration strings to set the options instead.  /// Options used by the LLVM XRay Basic (Naive) logging implementation.  struct BasicLoggingOptions {    int DurationFilterMicros = 0; diff --git a/include/xray/xray_records.h b/include/xray/xray_records.h index d4b7b4c31a9a2..8cfdeee8cf2bb 100644 --- a/include/xray/xray_records.h +++ b/include/xray/xray_records.h @@ -54,7 +54,7 @@ struct alignas(32) XRayFileHeader {    union {      char FreeForm[16]; -    // The current civiltime timestamp, as retrived from 'clock_gettime'. This +    // The current civiltime timestamp, as retrieved from 'clock_gettime'. This      // allows readers of the file to determine when the file was created or      // written down.      struct timespec TS; @@ -95,8 +95,11 @@ struct alignas(32) XRayRecord {    // The thread ID for the currently running thread.    uint32_t TId = 0; +  // The ID of process that is currently running +  uint32_t PId = 0; +      // Use some bytes in the end of the record for buffers. -  char Buffer[4] = {}; +  char Buffer[8] = {};  } __attribute__((packed));  static_assert(sizeof(XRayRecord) == 32, "XRayRecord != 32 bytes"); @@ -115,8 +118,8 @@ struct alignas(32) XRayArgPayload {    // The thread ID for the currently running thread.    uint32_t TId = 0; -  // Add more padding. -  uint8_t Padding2[4] = {}; +  // The ID of process that is currently running +  uint32_t PId = 0;    // The argument payload.    uint64_t Arg = 0; diff --git a/lib/asan/.clang-format b/lib/asan/.clang-format index f6cb8ad931f54..560308c91deec 100644 --- a/lib/asan/.clang-format +++ b/lib/asan/.clang-format @@ -1 +1,2 @@  BasedOnStyle: Google +AllowShortIfStatementsOnASingleLine: false diff --git a/lib/asan/CMakeLists.txt b/lib/asan/CMakeLists.txt index fbd72f69298f6..2ae5c85ecefba 100644 --- a/lib/asan/CMakeLists.txt +++ b/lib/asan/CMakeLists.txt @@ -23,6 +23,7 @@ set(ASAN_SOURCES    asan_posix.cc    asan_premap_shadow.cc    asan_report.cc +  asan_rtems.cc    asan_rtl.cc    asan_shadow_setup.cc    asan_stack.cc @@ -37,6 +38,34 @@ set(ASAN_CXX_SOURCES  set(ASAN_PREINIT_SOURCES    asan_preinit.cc) +SET(ASAN_HEADERS +  asan_activation.h +  asan_activation_flags.inc +  asan_allocator.h +  asan_descriptions.h +  asan_errors.h +  asan_fake_stack.h +  asan_flags.h +  asan_flags.inc +  asan_init_version.h +  asan_interceptors.h +  asan_interceptors_memintrinsics.h +  asan_interface.inc +  asan_interface_internal.h +  asan_internal.h +  asan_lock.h +  asan_malloc_local.h +  asan_mapping.h +  asan_mapping_myriad.h +  asan_poisoning.h +  asan_premap_shadow.h +  asan_report.h +  asan_scariness_score.h +  asan_stack.h +  asan_stats.h +  asan_suppressions.h +  asan_thread.h) +  include_directories(..)  set(ASAN_CFLAGS ${SANITIZER_COMMON_CFLAGS}) @@ -46,20 +75,6 @@ append_rtti_flag(OFF ASAN_CFLAGS)  set(ASAN_DYNAMIC_LINK_FLAGS ${SANITIZER_COMMON_LINK_FLAGS}) -if(ANDROID) -# On Android, -z global does not do what it is documented to do. -# On Android, -z global moves the library ahead in the lookup order, -# placing it right after the LD_PRELOADs. This is used to compensate for the fact -# that Android linker does not look at the dependencies of the main executable -# that aren't dependencies of the current DSO when resolving symbols from said DSO. -# As a net result, this allows running ASan executables without LD_PRELOAD-ing the -# ASan runtime library. -# The above is applicable to L MR1 or newer. -  if (COMPILER_RT_HAS_Z_GLOBAL) -    list(APPEND ASAN_DYNAMIC_LINK_FLAGS -Wl,-z,global) -  endif() -endif() -  set(ASAN_DYNAMIC_DEFINITIONS    ${ASAN_COMMON_DEFINITIONS} ASAN_DYNAMIC=1)  append_list_if(WIN32 INTERCEPTION_DYNAMIC_CRT ASAN_DYNAMIC_DEFINITIONS) @@ -83,21 +98,28 @@ add_compiler_rt_object_libraries(RTAsan_dynamic    OS ${SANITIZER_COMMON_SUPPORTED_OS}    ARCHS ${ASAN_SUPPORTED_ARCH}    SOURCES ${ASAN_SOURCES} ${ASAN_CXX_SOURCES} +  ADDITIONAL_HEADERS ${ASAN_HEADERS}    CFLAGS ${ASAN_DYNAMIC_CFLAGS}    DEFS ${ASAN_DYNAMIC_DEFINITIONS})  if(NOT APPLE)    add_compiler_rt_object_libraries(RTAsan      ARCHS ${ASAN_SUPPORTED_ARCH} -    SOURCES ${ASAN_SOURCES} CFLAGS ${ASAN_CFLAGS} +    SOURCES ${ASAN_SOURCES} +    ADDITIONAL_HEADERS ${ASAN_HEADERS} +    CFLAGS ${ASAN_CFLAGS}      DEFS ${ASAN_COMMON_DEFINITIONS})    add_compiler_rt_object_libraries(RTAsan_cxx      ARCHS ${ASAN_SUPPORTED_ARCH} -    SOURCES ${ASAN_CXX_SOURCES} CFLAGS ${ASAN_CFLAGS} +    SOURCES ${ASAN_CXX_SOURCES} +    ADDITIONAL_HEADERS ${ASAN_HEADERS} +    CFLAGS ${ASAN_CFLAGS}      DEFS ${ASAN_COMMON_DEFINITIONS})    add_compiler_rt_object_libraries(RTAsan_preinit      ARCHS ${ASAN_SUPPORTED_ARCH} -    SOURCES ${ASAN_PREINIT_SOURCES} CFLAGS ${ASAN_CFLAGS} +    SOURCES ${ASAN_PREINIT_SOURCES} +    ADDITIONAL_HEADERS ${ASAN_HEADERS} +    CFLAGS ${ASAN_CFLAGS}      DEFS ${ASAN_COMMON_DEFINITIONS})    file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/dummy.cc "") @@ -125,6 +147,8 @@ if(APPLE)                  RTInterception                  RTSanitizerCommon                  RTSanitizerCommonLibc +                RTSanitizerCommonCoverage +                RTSanitizerCommonSymbolizer                  RTLSanCommon                  RTUbsan      CFLAGS ${ASAN_DYNAMIC_CFLAGS} @@ -138,6 +162,8 @@ else()      RTInterception      RTSanitizerCommon      RTSanitizerCommonLibc +    RTSanitizerCommonCoverage +    RTSanitizerCommonSymbolizer      RTLSanCommon      RTUbsan) @@ -223,7 +249,7 @@ else()        DEFS ${ASAN_DYNAMIC_DEFINITIONS}        PARENT_TARGET asan) -    if (UNIX AND NOT ${arch} STREQUAL "i386") +    if (SANITIZER_USE_SYMBOLS AND NOT ${arch} STREQUAL "i386")        add_sanitizer_rt_symbols(clang_rt.asan_cxx          ARCHS ${arch})        add_dependencies(asan clang_rt.asan_cxx-${arch}-symbols) diff --git a/lib/asan/asan_allocator.cc b/lib/asan/asan_allocator.cc index a437ae1cd3b1f..c0fad4fa042b8 100644 --- a/lib/asan/asan_allocator.cc +++ b/lib/asan/asan_allocator.cc @@ -134,8 +134,9 @@ struct AsanChunk: ChunkBase {  };  struct QuarantineCallback { -  explicit QuarantineCallback(AllocatorCache *cache) -      : cache_(cache) { +  QuarantineCallback(AllocatorCache *cache, BufferedStackTrace *stack) +      : cache_(cache), +        stack_(stack) {    }    void Recycle(AsanChunk *m) { @@ -168,7 +169,7 @@ struct QuarantineCallback {      void *res = get_allocator().Allocate(cache_, size, 1);      // TODO(alekseys): Consider making quarantine OOM-friendly.      if (UNLIKELY(!res)) -      return DieOnFailure::OnOOM(); +      ReportOutOfMemory(size, stack_);      return res;    } @@ -176,7 +177,9 @@ struct QuarantineCallback {      get_allocator().Deallocate(cache_, p);    } -  AllocatorCache *cache_; + private: +  AllocatorCache* const cache_; +  BufferedStackTrace* const stack_;  };  typedef Quarantine<QuarantineCallback, AsanChunk> AsanQuarantine; @@ -397,8 +400,11 @@ struct Allocator {                   AllocType alloc_type, bool can_fill) {      if (UNLIKELY(!asan_inited))        AsanInitFromRtl(); -    if (RssLimitExceeded()) -      return AsanAllocator::FailureHandler::OnOOM(); +    if (RssLimitExceeded()) { +      if (AllocatorMayReturnNull()) +        return nullptr; +      ReportRssLimitExceeded(stack); +    }      Flags &fl = *flags();      CHECK(stack);      const uptr min_alignment = SHADOW_GRANULARITY; @@ -431,9 +437,13 @@ struct Allocator {      }      CHECK(IsAligned(needed_size, min_alignment));      if (size > kMaxAllowedMallocSize || needed_size > kMaxAllowedMallocSize) { -      Report("WARNING: AddressSanitizer failed to allocate 0x%zx bytes\n", -             (void*)size); -      return AsanAllocator::FailureHandler::OnBadRequest(); +      if (AllocatorMayReturnNull()) { +        Report("WARNING: AddressSanitizer failed to allocate 0x%zx bytes\n", +               (void*)size); +        return nullptr; +      } +      ReportAllocationSizeTooBig(size, needed_size, kMaxAllowedMallocSize, +                                 stack);      }      AsanThread *t = GetCurrentThread(); @@ -446,8 +456,12 @@ struct Allocator {        AllocatorCache *cache = &fallback_allocator_cache;        allocated = allocator.Allocate(cache, needed_size, 8);      } -    if (!allocated) -      return nullptr; +    if (UNLIKELY(!allocated)) { +      SetAllocatorOutOfMemory(); +      if (AllocatorMayReturnNull()) +        return nullptr; +      ReportOutOfMemory(size, stack); +    }      if (*(u8 *)MEM_TO_SHADOW((uptr)allocated) == 0 && CanPoisonMemory()) {        // Heap poisoning is enabled, but the allocator provides an unpoisoned @@ -583,13 +597,13 @@ struct Allocator {      if (t) {        AsanThreadLocalMallocStorage *ms = &t->malloc_storage();        AllocatorCache *ac = GetAllocatorCache(ms); -      quarantine.Put(GetQuarantineCache(ms), QuarantineCallback(ac), m, -                           m->UsedSize()); +      quarantine.Put(GetQuarantineCache(ms), QuarantineCallback(ac, stack), m, +                     m->UsedSize());      } else {        SpinMutexLock l(&fallback_mutex);        AllocatorCache *ac = &fallback_allocator_cache; -      quarantine.Put(&fallback_quarantine_cache, QuarantineCallback(ac), m, -                           m->UsedSize()); +      quarantine.Put(&fallback_quarantine_cache, QuarantineCallback(ac, stack), +                     m, m->UsedSize());      }    } @@ -660,8 +674,11 @@ struct Allocator {    }    void *Calloc(uptr nmemb, uptr size, BufferedStackTrace *stack) { -    if (CheckForCallocOverflow(size, nmemb)) -      return AsanAllocator::FailureHandler::OnBadRequest(); +    if (UNLIKELY(CheckForCallocOverflow(size, nmemb))) { +      if (AllocatorMayReturnNull()) +        return nullptr; +      ReportCallocOverflow(nmemb, size, stack); +    }      void *ptr = Allocate(nmemb * size, 8, stack, FROM_MALLOC, false);      // If the memory comes from the secondary allocator no need to clear it      // as it comes directly from mmap. @@ -677,9 +694,9 @@ struct Allocator {        ReportFreeNotMalloced((uptr)ptr, stack);    } -  void CommitBack(AsanThreadLocalMallocStorage *ms) { +  void CommitBack(AsanThreadLocalMallocStorage *ms, BufferedStackTrace *stack) {      AllocatorCache *ac = GetAllocatorCache(ms); -    quarantine.Drain(GetQuarantineCache(ms), QuarantineCallback(ac)); +    quarantine.Drain(GetQuarantineCache(ms), QuarantineCallback(ac, stack));      allocator.SwallowCache(ac);    } @@ -739,17 +756,19 @@ struct Allocator {      return AsanChunkView(m1);    } -  void Purge() { +  void Purge(BufferedStackTrace *stack) {      AsanThread *t = GetCurrentThread();      if (t) {        AsanThreadLocalMallocStorage *ms = &t->malloc_storage();        quarantine.DrainAndRecycle(GetQuarantineCache(ms), -                                 QuarantineCallback(GetAllocatorCache(ms))); +                                 QuarantineCallback(GetAllocatorCache(ms), +                                                    stack));      }      {        SpinMutexLock l(&fallback_mutex);        quarantine.DrainAndRecycle(&fallback_quarantine_cache, -                                 QuarantineCallback(&fallback_allocator_cache)); +                                 QuarantineCallback(&fallback_allocator_cache, +                                                    stack));      }      allocator.ForceReleaseToOS(); @@ -836,7 +855,8 @@ AsanChunkView FindHeapChunkByAllocBeg(uptr addr) {  }  void AsanThreadLocalMallocStorage::CommitBack() { -  instance.CommitBack(this); +  GET_STACK_TRACE_MALLOC; +  instance.CommitBack(this, &stack);  }  void PrintInternalAllocatorStats() { @@ -883,7 +903,9 @@ void *asan_pvalloc(uptr size, BufferedStackTrace *stack) {    uptr PageSize = GetPageSizeCached();    if (UNLIKELY(CheckForPvallocOverflow(size, PageSize))) {      errno = errno_ENOMEM; -    return AsanAllocator::FailureHandler::OnBadRequest(); +    if (AllocatorMayReturnNull()) +      return nullptr; +    ReportPvallocOverflow(size, stack);    }    // pvalloc(0) should allocate one page.    size = size ? RoundUpTo(size, PageSize) : PageSize; @@ -895,20 +917,35 @@ void *asan_memalign(uptr alignment, uptr size, BufferedStackTrace *stack,                      AllocType alloc_type) {    if (UNLIKELY(!IsPowerOfTwo(alignment))) {      errno = errno_EINVAL; -    return AsanAllocator::FailureHandler::OnBadRequest(); +    if (AllocatorMayReturnNull()) +      return nullptr; +    ReportInvalidAllocationAlignment(alignment, stack);    }    return SetErrnoOnNull(        instance.Allocate(size, alignment, stack, alloc_type, true));  } +void *asan_aligned_alloc(uptr alignment, uptr size, BufferedStackTrace *stack) { +  if (UNLIKELY(!CheckAlignedAllocAlignmentAndSize(alignment, size))) { +    errno = errno_EINVAL; +    if (AllocatorMayReturnNull()) +      return nullptr; +    ReportInvalidAlignedAllocAlignment(size, alignment, stack); +  } +  return SetErrnoOnNull( +      instance.Allocate(size, alignment, stack, FROM_MALLOC, true)); +} +  int asan_posix_memalign(void **memptr, uptr alignment, uptr size,                          BufferedStackTrace *stack) {    if (UNLIKELY(!CheckPosixMemalignAlignment(alignment))) { -    AsanAllocator::FailureHandler::OnBadRequest(); -    return errno_EINVAL; +    if (AllocatorMayReturnNull()) +      return errno_EINVAL; +    ReportInvalidPosixMemalignAlignment(alignment, stack);    }    void *ptr = instance.Allocate(size, alignment, stack, FROM_MALLOC, true);    if (UNLIKELY(!ptr)) +    // OOM error is already taken care of by Allocate.      return errno_ENOMEM;    CHECK(IsAligned((uptr)ptr, alignment));    *memptr = ptr; @@ -1054,7 +1091,8 @@ uptr __sanitizer_get_allocated_size(const void *p) {  }  void __sanitizer_purge_allocator() { -  instance.Purge(); +  GET_STACK_TRACE_MALLOC; +  instance.Purge(&stack);  }  #if !SANITIZER_SUPPORTS_WEAK_HOOKS diff --git a/lib/asan/asan_allocator.h b/lib/asan/asan_allocator.h index 26483db4c60ec..93d6f29c5bf55 100644 --- a/lib/asan/asan_allocator.h +++ b/lib/asan/asan_allocator.h @@ -125,11 +125,12 @@ const uptr kAllocatorSpace = ~(uptr)0;  const uptr kAllocatorSize  =  0x40000000000ULL;  // 4T.  typedef DefaultSizeClassMap SizeClassMap;  # elif defined(__powerpc64__) -const uptr kAllocatorSpace =  0xa0000000000ULL; +const uptr kAllocatorSpace = ~(uptr)0;  const uptr kAllocatorSize  =  0x20000000000ULL;  // 2T.  typedef DefaultSizeClassMap SizeClassMap;  # elif defined(__aarch64__) && SANITIZER_ANDROID -const uptr kAllocatorSpace =  0x3000000000ULL; +// Android needs to support 39, 42 and 48 bit VMA. +const uptr kAllocatorSpace =  ~(uptr)0;  const uptr kAllocatorSize  =  0x2000000000ULL;  // 128G.  typedef VeryCompactSizeClassMap SizeClassMap;  # elif defined(__aarch64__) @@ -207,6 +208,7 @@ void *asan_realloc(void *p, uptr size, BufferedStackTrace *stack);  void *asan_valloc(uptr size, BufferedStackTrace *stack);  void *asan_pvalloc(uptr size, BufferedStackTrace *stack); +void *asan_aligned_alloc(uptr alignment, uptr size, BufferedStackTrace *stack);  int asan_posix_memalign(void **memptr, uptr alignment, uptr size,                          BufferedStackTrace *stack);  uptr asan_malloc_usable_size(const void *ptr, uptr pc, uptr bp); diff --git a/lib/asan/asan_debugging.cc b/lib/asan/asan_debugging.cc index 37c5922dc0fcd..7c877ded30cf4 100644 --- a/lib/asan/asan_debugging.cc +++ b/lib/asan/asan_debugging.cc @@ -27,7 +27,8 @@ using namespace __asan;  static void FindInfoForStackVar(uptr addr, const char *frame_descr, uptr offset,                                  char *name, uptr name_size,                                  uptr ®ion_address, uptr ®ion_size) { -  InternalMmapVector<StackVarDescr> vars(16); +  InternalMmapVector<StackVarDescr> vars; +  vars.reserve(16);    if (!ParseFrameDescription(frame_descr, &vars)) {      return;    } diff --git a/lib/asan/asan_descriptions.cc b/lib/asan/asan_descriptions.cc index 86c6af7d9f75f..cdb562d975ff2 100644 --- a/lib/asan/asan_descriptions.cc +++ b/lib/asan/asan_descriptions.cc @@ -20,23 +20,25 @@  namespace __asan { -// Return " (thread_name) " or an empty string if the name is empty. -const char *ThreadNameWithParenthesis(AsanThreadContext *t, char buff[], -                                      uptr buff_len) { -  const char *name = t->name; -  if (name[0] == '\0') return ""; -  buff[0] = 0; -  internal_strncat(buff, " (", 3); -  internal_strncat(buff, name, buff_len - 4); -  internal_strncat(buff, ")", 2); -  return buff; +AsanThreadIdAndName::AsanThreadIdAndName(AsanThreadContext *t) { +  Init(t->tid, t->name);  } -const char *ThreadNameWithParenthesis(u32 tid, char buff[], uptr buff_len) { -  if (tid == kInvalidTid) return ""; -  asanThreadRegistry().CheckLocked(); -  AsanThreadContext *t = GetThreadContextByTidLocked(tid); -  return ThreadNameWithParenthesis(t, buff, buff_len); +AsanThreadIdAndName::AsanThreadIdAndName(u32 tid) { +  if (tid == kInvalidTid) { +    Init(tid, ""); +  } else { +    asanThreadRegistry().CheckLocked(); +    AsanThreadContext *t = GetThreadContextByTidLocked(tid); +    Init(tid, t->name); +  } +} + +void AsanThreadIdAndName::Init(u32 tid, const char *tname) { +  int len = internal_snprintf(name, sizeof(name), "T%d", tid); +  CHECK(((unsigned int)len) < sizeof(name)); +  if (tname[0] != '\0') +    internal_snprintf(&name[len], sizeof(name) - len, " (%s)", tname);  }  void DescribeThread(AsanThreadContext *context) { @@ -47,18 +49,15 @@ void DescribeThread(AsanThreadContext *context) {      return;    }    context->announced = true; -  char tname[128];    InternalScopedString str(1024); -  str.append("Thread T%d%s", context->tid, -             ThreadNameWithParenthesis(context->tid, tname, sizeof(tname))); +  str.append("Thread %s", AsanThreadIdAndName(context).c_str());    if (context->parent_tid == kInvalidTid) {      str.append(" created by unknown thread\n");      Printf("%s", str.data());      return;    } -  str.append( -      " created by T%d%s here:\n", context->parent_tid, -      ThreadNameWithParenthesis(context->parent_tid, tname, sizeof(tname))); +  str.append(" created by %s here:\n", +             AsanThreadIdAndName(context->parent_tid).c_str());    Printf("%s", str.data());    StackDepotGet(context->stack_id).Print();    // Recursively described parent thread if needed. @@ -358,10 +357,9 @@ bool GlobalAddressDescription::PointsInsideTheSameVariable(  void StackAddressDescription::Print() const {    Decorator d; -  char tname[128];    Printf("%s", d.Location()); -  Printf("Address %p is located in stack of thread T%d%s", addr, tid, -         ThreadNameWithParenthesis(tid, tname, sizeof(tname))); +  Printf("Address %p is located in stack of thread %s", addr, +         AsanThreadIdAndName(tid).c_str());    if (!frame_descr) {      Printf("%s\n", d.Default()); @@ -380,7 +378,8 @@ void StackAddressDescription::Print() const {    StackTrace alloca_stack(&frame_pc, 1);    alloca_stack.Print(); -  InternalMmapVector<StackVarDescr> vars(16); +  InternalMmapVector<StackVarDescr> vars; +  vars.reserve(16);    if (!ParseFrameDescription(frame_descr, &vars)) {      Printf(          "AddressSanitizer can't parse the stack frame " @@ -402,7 +401,7 @@ void StackAddressDescription::Print() const {    }    Printf(        "HINT: this may be a false positive if your program uses " -      "some custom stack unwind mechanism or swapcontext\n"); +      "some custom stack unwind mechanism, swapcontext or vfork\n");    if (SANITIZER_WINDOWS)      Printf("      (longjmp, SEH and C++ exceptions *are* supported)\n");    else @@ -418,26 +417,19 @@ void HeapAddressDescription::Print() const {    AsanThreadContext *alloc_thread = GetThreadContextByTidLocked(alloc_tid);    StackTrace alloc_stack = GetStackTraceFromId(alloc_stack_id); -  char tname[128];    Decorator d;    AsanThreadContext *free_thread = nullptr;    if (free_tid != kInvalidTid) {      free_thread = GetThreadContextByTidLocked(free_tid); -    Printf("%sfreed by thread T%d%s here:%s\n", d.Allocation(), -           free_thread->tid, -           ThreadNameWithParenthesis(free_thread, tname, sizeof(tname)), -           d.Default()); +    Printf("%sfreed by thread %s here:%s\n", d.Allocation(), +           AsanThreadIdAndName(free_thread).c_str(), d.Default());      StackTrace free_stack = GetStackTraceFromId(free_stack_id);      free_stack.Print(); -    Printf("%spreviously allocated by thread T%d%s here:%s\n", d.Allocation(), -           alloc_thread->tid, -           ThreadNameWithParenthesis(alloc_thread, tname, sizeof(tname)), -           d.Default()); +    Printf("%spreviously allocated by thread %s here:%s\n", d.Allocation(), +           AsanThreadIdAndName(alloc_thread).c_str(), d.Default());    } else { -    Printf("%sallocated by thread T%d%s here:%s\n", d.Allocation(), -           alloc_thread->tid, -           ThreadNameWithParenthesis(alloc_thread, tname, sizeof(tname)), -           d.Default()); +    Printf("%sallocated by thread %s here:%s\n", d.Allocation(), +           AsanThreadIdAndName(alloc_thread).c_str(), d.Default());    }    alloc_stack.Print();    DescribeThread(GetCurrentThread()); diff --git a/lib/asan/asan_descriptions.h b/lib/asan/asan_descriptions.h index 1a1b01cf20cda..5c2d7662a35aa 100644 --- a/lib/asan/asan_descriptions.h +++ b/lib/asan/asan_descriptions.h @@ -26,9 +26,20 @@ void DescribeThread(AsanThreadContext *context);  static inline void DescribeThread(AsanThread *t) {    if (t) DescribeThread(t->context());  } -const char *ThreadNameWithParenthesis(AsanThreadContext *t, char buff[], -                                      uptr buff_len); -const char *ThreadNameWithParenthesis(u32 tid, char buff[], uptr buff_len); + +class AsanThreadIdAndName { + public: +  explicit AsanThreadIdAndName(AsanThreadContext *t); +  explicit AsanThreadIdAndName(u32 tid); + +  // Contains "T%tid (%name)" or "T%tid" if the name is empty. +  const char *c_str() const { return &name[0]; } + + private: +  void Init(u32 tid, const char *tname); + +  char name[128]; +};  class Decorator : public __sanitizer::SanitizerCommonDecorator {   public: diff --git a/lib/asan/asan_errors.cc b/lib/asan/asan_errors.cc index 0f4a3abff9a74..33d0613f79f47 100644 --- a/lib/asan/asan_errors.cc +++ b/lib/asan/asan_errors.cc @@ -45,13 +45,11 @@ void ErrorDeadlySignal::Print() {  void ErrorDoubleFree::Print() {    Decorator d; -  Printf("%s", d.Warning()); -  char tname[128]; +  Printf("%s", d.Error());    Report( -      "ERROR: AddressSanitizer: attempting %s on %p in " -      "thread T%d%s:\n", -      scariness.GetDescription(), addr_description.addr, tid, -      ThreadNameWithParenthesis(tid, tname, sizeof(tname))); +      "ERROR: AddressSanitizer: attempting %s on %p in thread %s:\n", +      scariness.GetDescription(), addr_description.addr, +      AsanThreadIdAndName(tid).c_str());    Printf("%s", d.Default());    scariness.Print();    GET_STACK_TRACE_FATAL(second_free_stack->trace[0], @@ -63,13 +61,11 @@ void ErrorDoubleFree::Print() {  void ErrorNewDeleteTypeMismatch::Print() {    Decorator d; -  Printf("%s", d.Warning()); -  char tname[128]; +  Printf("%s", d.Error());    Report( -      "ERROR: AddressSanitizer: %s on %p in thread " -      "T%d%s:\n", -      scariness.GetDescription(), addr_description.addr, tid, -      ThreadNameWithParenthesis(tid, tname, sizeof(tname))); +      "ERROR: AddressSanitizer: %s on %p in thread %s:\n", +      scariness.GetDescription(), addr_description.addr, +      AsanThreadIdAndName(tid).c_str());    Printf("%s  object passed to delete has wrong type:\n", d.Default());    if (delete_size != 0) {      Printf( @@ -106,13 +102,11 @@ void ErrorNewDeleteTypeMismatch::Print() {  void ErrorFreeNotMalloced::Print() {    Decorator d; -  Printf("%s", d.Warning()); -  char tname[128]; +  Printf("%s", d.Error());    Report(        "ERROR: AddressSanitizer: attempting free on address " -      "which was not malloc()-ed: %p in thread T%d%s\n", -      addr_description.Address(), tid, -      ThreadNameWithParenthesis(tid, tname, sizeof(tname))); +      "which was not malloc()-ed: %p in thread %s\n", +      addr_description.Address(), AsanThreadIdAndName(tid).c_str());    Printf("%s", d.Default());    CHECK_GT(free_stack->size, 0);    scariness.Print(); @@ -129,7 +123,7 @@ void ErrorAllocTypeMismatch::Print() {                                          "operator delete []"};    CHECK_NE(alloc_type, dealloc_type);    Decorator d; -  Printf("%s", d.Warning()); +  Printf("%s", d.Error());    Report("ERROR: AddressSanitizer: %s (%s vs %s) on %p\n",           scariness.GetDescription(),           alloc_names[alloc_type], dealloc_names[dealloc_type], @@ -148,7 +142,7 @@ void ErrorAllocTypeMismatch::Print() {  void ErrorMallocUsableSizeNotOwned::Print() {    Decorator d; -  Printf("%s", d.Warning()); +  Printf("%s", d.Error());    Report(        "ERROR: AddressSanitizer: attempting to call malloc_usable_size() for "        "pointer which is not owned: %p\n", @@ -161,7 +155,7 @@ void ErrorMallocUsableSizeNotOwned::Print() {  void ErrorSanitizerGetAllocatedSizeNotOwned::Print() {    Decorator d; -  Printf("%s", d.Warning()); +  Printf("%s", d.Error());    Report(        "ERROR: AddressSanitizer: attempting to call "        "__sanitizer_get_allocated_size() for pointer which is not owned: %p\n", @@ -172,11 +166,123 @@ void ErrorSanitizerGetAllocatedSizeNotOwned::Print() {    ReportErrorSummary(scariness.GetDescription(), stack);  } +void ErrorCallocOverflow::Print() { +  Decorator d; +  Printf("%s", d.Error()); +  Report( +      "ERROR: AddressSanitizer: calloc parameters overflow: count * size " +      "(%zd * %zd) cannot be represented in type size_t (thread %s)\n", +      count, size, AsanThreadIdAndName(tid).c_str()); +  Printf("%s", d.Default()); +  stack->Print(); +  PrintHintAllocatorCannotReturnNull(); +  ReportErrorSummary(scariness.GetDescription(), stack); +} + +void ErrorPvallocOverflow::Print() { +  Decorator d; +  Printf("%s", d.Error()); +  Report( +      "ERROR: AddressSanitizer: pvalloc parameters overflow: size 0x%zx " +      "rounded up to system page size 0x%zx cannot be represented in type " +      "size_t (thread %s)\n", +      size, GetPageSizeCached(), AsanThreadIdAndName(tid).c_str()); +  Printf("%s", d.Default()); +  stack->Print(); +  PrintHintAllocatorCannotReturnNull(); +  ReportErrorSummary(scariness.GetDescription(), stack); +} + +void ErrorInvalidAllocationAlignment::Print() { +  Decorator d; +  Printf("%s", d.Error()); +  Report( +      "ERROR: AddressSanitizer: invalid allocation alignment: %zd, " +      "alignment must be a power of two (thread %s)\n", +      alignment, AsanThreadIdAndName(tid).c_str()); +  Printf("%s", d.Default()); +  stack->Print(); +  PrintHintAllocatorCannotReturnNull(); +  ReportErrorSummary(scariness.GetDescription(), stack); +} + +void ErrorInvalidAlignedAllocAlignment::Print() { +  Decorator d; +  Printf("%s", d.Error()); +#if SANITIZER_POSIX +  Report("ERROR: AddressSanitizer: invalid alignment requested in " +         "aligned_alloc: %zd, alignment must be a power of two and the " +         "requested size 0x%zx must be a multiple of alignment " +         "(thread %s)\n", alignment, size, AsanThreadIdAndName(tid).c_str()); +#else +  Report("ERROR: AddressSanitizer: invalid alignment requested in " +         "aligned_alloc: %zd, the requested size 0x%zx must be a multiple of " +         "alignment (thread %s)\n", alignment, size, +         AsanThreadIdAndName(tid).c_str()); +#endif +  Printf("%s", d.Default()); +  stack->Print(); +  PrintHintAllocatorCannotReturnNull(); +  ReportErrorSummary(scariness.GetDescription(), stack); +} + +void ErrorInvalidPosixMemalignAlignment::Print() { +  Decorator d; +  Printf("%s", d.Error()); +  Report( +      "ERROR: AddressSanitizer: invalid alignment requested in posix_memalign: " +      "%zd, alignment must be a power of two and a multiple of sizeof(void*) " +      "== %zd (thread %s)\n", +      alignment, sizeof(void*), AsanThreadIdAndName(tid).c_str());  // NOLINT +  Printf("%s", d.Default()); +  stack->Print(); +  PrintHintAllocatorCannotReturnNull(); +  ReportErrorSummary(scariness.GetDescription(), stack); +} + +void ErrorAllocationSizeTooBig::Print() { +  Decorator d; +  Printf("%s", d.Error()); +  Report( +      "ERROR: AddressSanitizer: requested allocation size 0x%zx (0x%zx after " +      "adjustments for alignment, red zones etc.) exceeds maximum supported " +      "size of 0x%zx (thread %s)\n", +      user_size, total_size, max_size, AsanThreadIdAndName(tid).c_str()); +  Printf("%s", d.Default()); +  stack->Print(); +  PrintHintAllocatorCannotReturnNull(); +  ReportErrorSummary(scariness.GetDescription(), stack); +} + +void ErrorRssLimitExceeded::Print() { +  Decorator d; +  Printf("%s", d.Error()); +  Report( +      "ERROR: AddressSanitizer: specified RSS limit exceeded, currently set to " +      "soft_rss_limit_mb=%zd\n", common_flags()->soft_rss_limit_mb); +  Printf("%s", d.Default()); +  stack->Print(); +  PrintHintAllocatorCannotReturnNull(); +  ReportErrorSummary(scariness.GetDescription(), stack); +} + +void ErrorOutOfMemory::Print() { +  Decorator d; +  Printf("%s", d.Error()); +  Report( +      "ERROR: AddressSanitizer: allocator is out of memory trying to allocate " +      "0x%zx bytes\n", requested_size); +  Printf("%s", d.Default()); +  stack->Print(); +  PrintHintAllocatorCannotReturnNull(); +  ReportErrorSummary(scariness.GetDescription(), stack); +} +  void ErrorStringFunctionMemoryRangesOverlap::Print() {    Decorator d;    char bug_type[100];    internal_snprintf(bug_type, sizeof(bug_type), "%s-param-overlap", function); -  Printf("%s", d.Warning()); +  Printf("%s", d.Error());    Report(        "ERROR: AddressSanitizer: %s: memory ranges [%p,%p) and [%p, %p) "        "overlap\n", @@ -193,7 +299,7 @@ void ErrorStringFunctionMemoryRangesOverlap::Print() {  void ErrorStringFunctionSizeOverflow::Print() {    Decorator d; -  Printf("%s", d.Warning()); +  Printf("%s", d.Error());    Report("ERROR: AddressSanitizer: %s: (size=%zd)\n",           scariness.GetDescription(), size);    Printf("%s", d.Default()); @@ -221,7 +327,7 @@ void ErrorBadParamsToAnnotateContiguousContainer::Print() {  void ErrorODRViolation::Print() {    Decorator d; -  Printf("%s", d.Warning()); +  Printf("%s", d.Error());    Report("ERROR: AddressSanitizer: %s (%p):\n", scariness.GetDescription(),           global1.beg);    Printf("%s", d.Default()); @@ -250,7 +356,7 @@ void ErrorODRViolation::Print() {  void ErrorInvalidPointerPair::Print() {    Decorator d; -  Printf("%s", d.Warning()); +  Printf("%s", d.Error());    Report("ERROR: AddressSanitizer: %s: %p %p\n", scariness.GetDescription(),           addr1_description.Address(), addr2_description.Address());    Printf("%s", d.Default()); @@ -414,6 +520,7 @@ static void PrintLegend(InternalScopedString *str) {    PrintShadowByte(str, "  ASan internal:           ", kAsanInternalHeapMagic);    PrintShadowByte(str, "  Left alloca redzone:     ", kAsanAllocaLeftMagic);    PrintShadowByte(str, "  Right alloca redzone:    ", kAsanAllocaRightMagic); +  PrintShadowByte(str, "  Shadow gap:              ", kAsanShadowGap);  }  static void PrintShadowBytes(InternalScopedString *str, const char *before, @@ -453,17 +560,15 @@ static void PrintShadowMemoryForAddress(uptr addr) {  void ErrorGeneric::Print() {    Decorator d; -  Printf("%s", d.Warning()); +  Printf("%s", d.Error());    uptr addr = addr_description.Address();    Report("ERROR: AddressSanitizer: %s on address %p at pc %p bp %p sp %p\n",           bug_descr, (void *)addr, pc, bp, sp);    Printf("%s", d.Default()); -  char tname[128]; -  Printf("%s%s of size %zu at %p thread T%d%s%s\n", d.Access(), +  Printf("%s%s of size %zu at %p thread %s%s\n", d.Access(),           access_size ? (is_write ? "WRITE" : "READ") : "ACCESS", access_size, -         (void *)addr, tid, -         ThreadNameWithParenthesis(tid, tname, sizeof(tname)), d.Default()); +         (void *)addr, AsanThreadIdAndName(tid).c_str(), d.Default());    scariness.Print();    GET_STACK_TRACE_FATAL(pc, bp); diff --git a/lib/asan/asan_errors.h b/lib/asan/asan_errors.h index 518ba0c6945ef..574197ebff868 100644 --- a/lib/asan/asan_errors.h +++ b/lib/asan/asan_errors.h @@ -20,20 +20,30 @@  namespace __asan { +// (*) VS2013 does not implement unrestricted unions, so we need a trivial +// default constructor explicitly defined for each particular error. + +// None of the error classes own the stack traces mentioned in them. +  struct ErrorBase { -  ErrorBase() = default; -  explicit ErrorBase(u32 tid_) : tid(tid_) {}    ScarinessScoreBase scariness;    u32 tid; + +  ErrorBase() = default;  // (*) +  explicit ErrorBase(u32 tid_) : tid(tid_) {} +  ErrorBase(u32 tid_, int initial_score, const char *reason) : tid(tid_) { +    scariness.Clear(); +    scariness.Scare(initial_score, reason); +  }  };  struct ErrorDeadlySignal : ErrorBase {    SignalContext signal; -  // VS2013 doesn't implement unrestricted unions, so we need a trivial default -  // constructor -  ErrorDeadlySignal() = default; + +  ErrorDeadlySignal() = default;  // (*)    ErrorDeadlySignal(u32 tid, const SignalContext &sig) -      : ErrorBase(tid), signal(sig) { +      : ErrorBase(tid), +        signal(sig) {      scariness.Clear();      if (signal.IsStackOverflow()) {        scariness.Scare(10, "stack-overflow"); @@ -55,125 +65,206 @@ struct ErrorDeadlySignal : ErrorBase {  };  struct ErrorDoubleFree : ErrorBase { -  // ErrorDoubleFree doesn't own the stack trace.    const BufferedStackTrace *second_free_stack;    HeapAddressDescription addr_description; -  // VS2013 doesn't implement unrestricted unions, so we need a trivial default -  // constructor -  ErrorDoubleFree() = default; + +  ErrorDoubleFree() = default;  // (*)    ErrorDoubleFree(u32 tid, BufferedStackTrace *stack, uptr addr) -      : ErrorBase(tid), second_free_stack(stack) { +      : ErrorBase(tid, 42, "double-free"), +        second_free_stack(stack) {      CHECK_GT(second_free_stack->size, 0);      GetHeapAddressInformation(addr, 1, &addr_description); -    scariness.Clear(); -    scariness.Scare(42, "double-free");    }    void Print();  };  struct ErrorNewDeleteTypeMismatch : ErrorBase { -  // ErrorNewDeleteTypeMismatch doesn't own the stack trace.    const BufferedStackTrace *free_stack;    HeapAddressDescription addr_description;    uptr delete_size;    uptr delete_alignment; -  // VS2013 doesn't implement unrestricted unions, so we need a trivial default -  // constructor -  ErrorNewDeleteTypeMismatch() = default; + +  ErrorNewDeleteTypeMismatch() = default;  // (*)    ErrorNewDeleteTypeMismatch(u32 tid, BufferedStackTrace *stack, uptr addr,                               uptr delete_size_, uptr delete_alignment_) -      : ErrorBase(tid), free_stack(stack), delete_size(delete_size_), +      : ErrorBase(tid, 10, "new-delete-type-mismatch"), +        free_stack(stack), +        delete_size(delete_size_),          delete_alignment(delete_alignment_) {      GetHeapAddressInformation(addr, 1, &addr_description); -    scariness.Clear(); -    scariness.Scare(10, "new-delete-type-mismatch");    }    void Print();  };  struct ErrorFreeNotMalloced : ErrorBase { -  // ErrorFreeNotMalloced doesn't own the stack trace.    const BufferedStackTrace *free_stack;    AddressDescription addr_description; -  // VS2013 doesn't implement unrestricted unions, so we need a trivial default -  // constructor -  ErrorFreeNotMalloced() = default; + +  ErrorFreeNotMalloced() = default;  // (*)    ErrorFreeNotMalloced(u32 tid, BufferedStackTrace *stack, uptr addr) -      : ErrorBase(tid), +      : ErrorBase(tid, 40, "bad-free"),          free_stack(stack), -        addr_description(addr, /*shouldLockThreadRegistry=*/false) { -    scariness.Clear(); -    scariness.Scare(40, "bad-free"); -  } +        addr_description(addr, /*shouldLockThreadRegistry=*/false) {}    void Print();  };  struct ErrorAllocTypeMismatch : ErrorBase { -  // ErrorAllocTypeMismatch doesn't own the stack trace.    const BufferedStackTrace *dealloc_stack;    HeapAddressDescription addr_description;    AllocType alloc_type, dealloc_type; -  // VS2013 doesn't implement unrestricted unions, so we need a trivial default -  // constructor -  ErrorAllocTypeMismatch() = default; + +  ErrorAllocTypeMismatch() = default;  // (*)    ErrorAllocTypeMismatch(u32 tid, BufferedStackTrace *stack, uptr addr,                           AllocType alloc_type_, AllocType dealloc_type_) -      : ErrorBase(tid), +      : ErrorBase(tid, 10, "alloc-dealloc-mismatch"),          dealloc_stack(stack),          alloc_type(alloc_type_),          dealloc_type(dealloc_type_) {      GetHeapAddressInformation(addr, 1, &addr_description); -    scariness.Clear(); -    scariness.Scare(10, "alloc-dealloc-mismatch");    };    void Print();  };  struct ErrorMallocUsableSizeNotOwned : ErrorBase { -  // ErrorMallocUsableSizeNotOwned doesn't own the stack trace.    const BufferedStackTrace *stack;    AddressDescription addr_description; -  // VS2013 doesn't implement unrestricted unions, so we need a trivial default -  // constructor -  ErrorMallocUsableSizeNotOwned() = default; + +  ErrorMallocUsableSizeNotOwned() = default;  // (*)    ErrorMallocUsableSizeNotOwned(u32 tid, BufferedStackTrace *stack_, uptr addr) -      : ErrorBase(tid), +      : ErrorBase(tid, 10, "bad-malloc_usable_size"),          stack(stack_), -        addr_description(addr, /*shouldLockThreadRegistry=*/false) { -    scariness.Clear(); -    scariness.Scare(10, "bad-malloc_usable_size"); -  } +        addr_description(addr, /*shouldLockThreadRegistry=*/false) {}    void Print();  };  struct ErrorSanitizerGetAllocatedSizeNotOwned : ErrorBase { -  // ErrorSanitizerGetAllocatedSizeNotOwned doesn't own the stack trace.    const BufferedStackTrace *stack;    AddressDescription addr_description; -  // VS2013 doesn't implement unrestricted unions, so we need a trivial default -  // constructor -  ErrorSanitizerGetAllocatedSizeNotOwned() = default; + +  ErrorSanitizerGetAllocatedSizeNotOwned() = default;  // (*)    ErrorSanitizerGetAllocatedSizeNotOwned(u32 tid, BufferedStackTrace *stack_,                                           uptr addr) -      : ErrorBase(tid), +      : ErrorBase(tid, 10, "bad-__sanitizer_get_allocated_size"),          stack(stack_), -        addr_description(addr, /*shouldLockThreadRegistry=*/false) { -    scariness.Clear(); -    scariness.Scare(10, "bad-__sanitizer_get_allocated_size"); -  } +        addr_description(addr, /*shouldLockThreadRegistry=*/false) {} +  void Print(); +}; + +struct ErrorCallocOverflow : ErrorBase { +  const BufferedStackTrace *stack; +  uptr count; +  uptr size; + +  ErrorCallocOverflow() = default;  // (*) +  ErrorCallocOverflow(u32 tid, BufferedStackTrace *stack_, uptr count_, +                      uptr size_) +      : ErrorBase(tid, 10, "calloc-overflow"), +        stack(stack_), +        count(count_), +        size(size_) {} +  void Print(); +}; + +struct ErrorPvallocOverflow : ErrorBase { +  const BufferedStackTrace *stack; +  uptr size; + +  ErrorPvallocOverflow() = default;  // (*) +  ErrorPvallocOverflow(u32 tid, BufferedStackTrace *stack_, uptr size_) +      : ErrorBase(tid, 10, "pvalloc-overflow"), +        stack(stack_), +        size(size_) {} +  void Print(); +}; + +struct ErrorInvalidAllocationAlignment : ErrorBase { +  const BufferedStackTrace *stack; +  uptr alignment; + +  ErrorInvalidAllocationAlignment() = default;  // (*) +  ErrorInvalidAllocationAlignment(u32 tid, BufferedStackTrace *stack_, +                                  uptr alignment_) +      : ErrorBase(tid, 10, "invalid-allocation-alignment"), +        stack(stack_), +        alignment(alignment_) {} +  void Print(); +}; + +struct ErrorInvalidAlignedAllocAlignment : ErrorBase { +  const BufferedStackTrace *stack; +  uptr size; +  uptr alignment; + +  ErrorInvalidAlignedAllocAlignment() = default;  // (*) +  ErrorInvalidAlignedAllocAlignment(u32 tid, BufferedStackTrace *stack_, +                                    uptr size_, uptr alignment_) +      : ErrorBase(tid, 10, "invalid-aligned-alloc-alignment"), +        stack(stack_), +        size(size_), +        alignment(alignment_) {} +  void Print(); +}; + +struct ErrorInvalidPosixMemalignAlignment : ErrorBase { +  const BufferedStackTrace *stack; +  uptr alignment; + +  ErrorInvalidPosixMemalignAlignment() = default;  // (*) +  ErrorInvalidPosixMemalignAlignment(u32 tid, BufferedStackTrace *stack_, +                                     uptr alignment_) +      : ErrorBase(tid, 10, "invalid-posix-memalign-alignment"), +        stack(stack_), +        alignment(alignment_) {} +  void Print(); +}; + +struct ErrorAllocationSizeTooBig : ErrorBase { +  const BufferedStackTrace *stack; +  uptr user_size; +  uptr total_size; +  uptr max_size; + +  ErrorAllocationSizeTooBig() = default;  // (*) +  ErrorAllocationSizeTooBig(u32 tid, BufferedStackTrace *stack_, +                            uptr user_size_, uptr total_size_, uptr max_size_) +      : ErrorBase(tid, 10, "allocation-size-too-big"), +        stack(stack_), +        user_size(user_size_), +        total_size(total_size_), +        max_size(max_size_) {} +  void Print(); +}; + +struct ErrorRssLimitExceeded : ErrorBase { +  const BufferedStackTrace *stack; + +  ErrorRssLimitExceeded() = default;  // (*) +  ErrorRssLimitExceeded(u32 tid, BufferedStackTrace *stack_) +      : ErrorBase(tid, 10, "rss-limit-exceeded"), +        stack(stack_) {} +  void Print(); +}; + +struct ErrorOutOfMemory : ErrorBase { +  const BufferedStackTrace *stack; +  uptr requested_size; + +  ErrorOutOfMemory() = default;  // (*) +  ErrorOutOfMemory(u32 tid, BufferedStackTrace *stack_, uptr requested_size_) +      : ErrorBase(tid, 10, "out-of-memory"), +        stack(stack_), +        requested_size(requested_size_) {}    void Print();  };  struct ErrorStringFunctionMemoryRangesOverlap : ErrorBase { -  // ErrorStringFunctionMemoryRangesOverlap doesn't own the stack trace.    const BufferedStackTrace *stack;    uptr length1, length2;    AddressDescription addr1_description;    AddressDescription addr2_description;    const char *function; -  // VS2013 doesn't implement unrestricted unions, so we need a trivial default -  // constructor -  ErrorStringFunctionMemoryRangesOverlap() = default; + +  ErrorStringFunctionMemoryRangesOverlap() = default;  // (*)    ErrorStringFunctionMemoryRangesOverlap(u32 tid, BufferedStackTrace *stack_,                                           uptr addr1, uptr length1_, uptr addr2,                                           uptr length2_, const char *function_) @@ -193,65 +284,51 @@ struct ErrorStringFunctionMemoryRangesOverlap : ErrorBase {  };  struct ErrorStringFunctionSizeOverflow : ErrorBase { -  // ErrorStringFunctionSizeOverflow doesn't own the stack trace.    const BufferedStackTrace *stack;    AddressDescription addr_description;    uptr size; -  // VS2013 doesn't implement unrestricted unions, so we need a trivial default -  // constructor -  ErrorStringFunctionSizeOverflow() = default; + +  ErrorStringFunctionSizeOverflow() = default;  // (*)    ErrorStringFunctionSizeOverflow(u32 tid, BufferedStackTrace *stack_,                                    uptr addr, uptr size_) -      : ErrorBase(tid), +      : ErrorBase(tid, 10, "negative-size-param"),          stack(stack_),          addr_description(addr, /*shouldLockThreadRegistry=*/false), -        size(size_) { -    scariness.Clear(); -    scariness.Scare(10, "negative-size-param"); -  } +        size(size_) {}    void Print();  };  struct ErrorBadParamsToAnnotateContiguousContainer : ErrorBase { -  // ErrorBadParamsToAnnotateContiguousContainer doesn't own the stack trace.    const BufferedStackTrace *stack;    uptr beg, end, old_mid, new_mid; -  // VS2013 doesn't implement unrestricted unions, so we need a trivial default -  // constructor -  ErrorBadParamsToAnnotateContiguousContainer() = default; + +  ErrorBadParamsToAnnotateContiguousContainer() = default;  // (*)    // PS4: Do we want an AddressDescription for beg?    ErrorBadParamsToAnnotateContiguousContainer(u32 tid,                                                BufferedStackTrace *stack_,                                                uptr beg_, uptr end_,                                                uptr old_mid_, uptr new_mid_) -      : ErrorBase(tid), +      : ErrorBase(tid, 10, "bad-__sanitizer_annotate_contiguous_container"),          stack(stack_),          beg(beg_),          end(end_),          old_mid(old_mid_), -        new_mid(new_mid_) { -    scariness.Clear(); -    scariness.Scare(10, "bad-__sanitizer_annotate_contiguous_container"); -  } +        new_mid(new_mid_) {}    void Print();  };  struct ErrorODRViolation : ErrorBase {    __asan_global global1, global2;    u32 stack_id1, stack_id2; -  // VS2013 doesn't implement unrestricted unions, so we need a trivial default -  // constructor -  ErrorODRViolation() = default; + +  ErrorODRViolation() = default;  // (*)    ErrorODRViolation(u32 tid, const __asan_global *g1, u32 stack_id1_,                      const __asan_global *g2, u32 stack_id2_) -      : ErrorBase(tid), +      : ErrorBase(tid, 10, "odr-violation"),          global1(*g1),          global2(*g2),          stack_id1(stack_id1_), -        stack_id2(stack_id2_) { -    scariness.Clear(); -    scariness.Scare(10, "odr-violation"); -  } +        stack_id2(stack_id2_) {}    void Print();  }; @@ -259,20 +336,16 @@ struct ErrorInvalidPointerPair : ErrorBase {    uptr pc, bp, sp;    AddressDescription addr1_description;    AddressDescription addr2_description; -  // VS2013 doesn't implement unrestricted unions, so we need a trivial default -  // constructor -  ErrorInvalidPointerPair() = default; + +  ErrorInvalidPointerPair() = default;  // (*)    ErrorInvalidPointerPair(u32 tid, uptr pc_, uptr bp_, uptr sp_, uptr p1,                            uptr p2) -      : ErrorBase(tid), +      : ErrorBase(tid, 10, "invalid-pointer-pair"),          pc(pc_),          bp(bp_),          sp(sp_),          addr1_description(p1, 1, /*shouldLockThreadRegistry=*/false), -        addr2_description(p2, 1, /*shouldLockThreadRegistry=*/false)  { -    scariness.Clear(); -    scariness.Scare(10, "invalid-pointer-pair"); -  } +        addr2_description(p2, 1, /*shouldLockThreadRegistry=*/false) {}    void Print();  }; @@ -283,9 +356,8 @@ struct ErrorGeneric : ErrorBase {    const char *bug_descr;    bool is_write;    u8 shadow_val; -  // VS2013 doesn't implement unrestricted unions, so we need a trivial default -  // constructor -  ErrorGeneric() = default; + +  ErrorGeneric() = default;  // (*)    ErrorGeneric(u32 tid, uptr addr, uptr pc_, uptr bp_, uptr sp_, bool is_write_,                 uptr access_size_);    void Print(); @@ -300,6 +372,14 @@ struct ErrorGeneric : ErrorBase {    macro(AllocTypeMismatch)                      \    macro(MallocUsableSizeNotOwned)               \    macro(SanitizerGetAllocatedSizeNotOwned)      \ +  macro(CallocOverflow)                         \ +  macro(PvallocOverflow)                        \ +  macro(InvalidAllocationAlignment)             \ +  macro(InvalidAlignedAllocAlignment)           \ +  macro(InvalidPosixMemalignAlignment)          \ +  macro(AllocationSizeTooBig)                   \ +  macro(RssLimitExceeded)                       \ +  macro(OutOfMemory)                            \    macro(StringFunctionMemoryRangesOverlap)      \    macro(StringFunctionSizeOverflow)             \    macro(BadParamsToAnnotateContiguousContainer) \ @@ -334,6 +414,7 @@ struct ErrorDescription {    };    ErrorDescription() { internal_memset(this, 0, sizeof(*this)); } +  explicit ErrorDescription(LinkerInitialized) {}    ASAN_FOR_EACH_ERROR_KIND(ASAN_ERROR_DESCRIPTION_CONSTRUCTOR)    bool IsValid() { return kind != kErrorKindInvalid; } diff --git a/lib/asan/asan_flags.cc b/lib/asan/asan_flags.cc index 562168e6d4284..5682ab4eb4769 100644 --- a/lib/asan/asan_flags.cc +++ b/lib/asan/asan_flags.cc @@ -33,10 +33,7 @@ static const char *MaybeCallAsanDefaultOptions() {  static const char *MaybeUseAsanDefaultOptionsCompileDefinition() {  #ifdef ASAN_DEFAULT_OPTIONS -// Stringize the macro value. -# define ASAN_STRINGIZE(x) #x -# define ASAN_STRINGIZE_OPTIONS(options) ASAN_STRINGIZE(options) -  return ASAN_STRINGIZE_OPTIONS(ASAN_DEFAULT_OPTIONS); +  return SANITIZER_STRINGIFY(ASAN_DEFAULT_OPTIONS);  #else    return "";  #endif @@ -163,6 +160,10 @@ void InitializeFlags() {    CHECK_LE(f->max_redzone, 2048);    CHECK(IsPowerOfTwo(f->redzone));    CHECK(IsPowerOfTwo(f->max_redzone)); +  if (SANITIZER_RTEMS) { +    CHECK(!f->unmap_shadow_on_exit); +    CHECK(!f->protect_shadow_gap); +  }    // quarantine_size is deprecated but we still honor it.    // quarantine_size can not be used together with quarantine_size_mb. diff --git a/lib/asan/asan_flags.inc b/lib/asan/asan_flags.inc index 00071d39f041f..4af94c56fca0b 100644 --- a/lib/asan/asan_flags.inc +++ b/lib/asan/asan_flags.inc @@ -88,7 +88,8 @@ ASAN_FLAG(bool, check_malloc_usable_size, true,            "295.*.")  ASAN_FLAG(bool, unmap_shadow_on_exit, false,            "If set, explicitly unmaps the (huge) shadow at exit.") -ASAN_FLAG(bool, protect_shadow_gap, true, "If set, mprotect the shadow gap") +ASAN_FLAG(bool, protect_shadow_gap, !SANITIZER_RTEMS, +          "If set, mprotect the shadow gap")  ASAN_FLAG(bool, print_stats, false,            "Print various statistics after printing an error message or if "            "atexit=1.") @@ -136,9 +137,9 @@ ASAN_FLAG(      "Android. ")  ASAN_FLAG(      int, detect_invalid_pointer_pairs, 0, -    "If non-zero, try to detect operations like <, <=, >, >= and - on " -    "invalid pointer pairs (e.g. when pointers belong to different objects). " -    "The bigger the value the harder we try.") +    "If >= 2, detect operations like <, <=, >, >= and - on invalid pointer " +    "pairs (e.g. when pointers belong to different objects); " +    "If == 1, detect invalid operations only when both pointers are non-null.")  ASAN_FLAG(      bool, detect_container_overflow, true,      "If true, honor the container overflow annotations. See " diff --git a/lib/asan/asan_globals.cc b/lib/asan/asan_globals.cc index 0db65d0103499..898f7f40d31bd 100644 --- a/lib/asan/asan_globals.cc +++ b/lib/asan/asan_globals.cc @@ -224,8 +224,9 @@ static void RegisterGlobal(const Global *g) {    list_of_all_globals = l;    if (g->has_dynamic_init) {      if (!dynamic_init_globals) { -      dynamic_init_globals = new(allocator_for_globals) -          VectorOfGlobals(kDynamicInitGlobalsInitialCapacity); +      dynamic_init_globals = +          new (allocator_for_globals) VectorOfGlobals;  // NOLINT +      dynamic_init_globals->reserve(kDynamicInitGlobalsInitialCapacity);      }      DynInitGlobal dyn_global = { *g, false };      dynamic_init_globals->push_back(dyn_global); @@ -358,9 +359,11 @@ void __asan_register_globals(__asan_global *globals, uptr n) {    GET_STACK_TRACE_MALLOC;    u32 stack_id = StackDepotPut(stack);    BlockingMutexLock lock(&mu_for_globals); -  if (!global_registration_site_vector) +  if (!global_registration_site_vector) {      global_registration_site_vector = -        new(allocator_for_globals) GlobalRegistrationSiteVector(128); +        new (allocator_for_globals) GlobalRegistrationSiteVector;  // NOLINT +    global_registration_site_vector->reserve(128); +  }    GlobalRegistrationSite site = {stack_id, &globals[0], &globals[n - 1]};    global_registration_site_vector->push_back(site);    if (flags()->report_globals >= 2) { diff --git a/lib/asan/asan_globals_win.cc b/lib/asan/asan_globals_win.cc index 261762b63e2c6..29ab5ebf16d4c 100644 --- a/lib/asan/asan_globals_win.cc +++ b/lib/asan/asan_globals_win.cc @@ -19,9 +19,9 @@ namespace __asan {  #pragma section(".ASAN$GA", read, write)  // NOLINT  #pragma section(".ASAN$GZ", read, write)  // NOLINT  extern "C" __declspec(allocate(".ASAN$GA")) -__asan_global __asan_globals_start = {}; +    ALIGNED(sizeof(__asan_global)) __asan_global __asan_globals_start = {};  extern "C" __declspec(allocate(".ASAN$GZ")) -__asan_global __asan_globals_end = {}; +    ALIGNED(sizeof(__asan_global)) __asan_global __asan_globals_end = {};  #pragma comment(linker, "/merge:.ASAN=.data")  static void call_on_globals(void (*hook)(__asan_global *, uptr)) { diff --git a/lib/asan/asan_interceptors.cc b/lib/asan/asan_interceptors.cc index cb7dcb3b1ca82..aac2bb8a6bbf4 100644 --- a/lib/asan/asan_interceptors.cc +++ b/lib/asan/asan_interceptors.cc @@ -24,15 +24,20 @@  #include "lsan/lsan_common.h"  #include "sanitizer_common/sanitizer_libc.h" -// There is no general interception at all on Fuchsia. +// There is no general interception at all on Fuchsia and RTEMS.  // Only the functions in asan_interceptors_memintrinsics.cc are  // really defined to replace libc functions. -#if !SANITIZER_FUCHSIA +#if !SANITIZER_FUCHSIA && !SANITIZER_RTEMS  #if SANITIZER_POSIX  #include "sanitizer_common/sanitizer_posix.h"  #endif +#if ASAN_INTERCEPT__UNWIND_RAISEEXCEPTION || \ +    ASAN_INTERCEPT__SJLJ_UNWIND_RAISEEXCEPTION +#include <unwind.h> +#endif +  #if defined(__i386) && SANITIZER_LINUX  #define ASAN_PTHREAD_CREATE_VERSION "GLIBC_2.1"  #elif defined(__mips__) && SANITIZER_LINUX @@ -178,6 +183,7 @@ DECLARE_REAL_AND_INTERCEPTOR(void, free, void *)      (void)(s);                                \    } while (false)  #include "sanitizer_common/sanitizer_common_syscalls.inc" +#include "sanitizer_common/sanitizer_syscalls_netbsd.inc"  struct ThreadStartParam {    atomic_uintptr_t t; @@ -269,7 +275,15 @@ INTERCEPTOR(int, swapcontext, struct ucontext_t *oucp,    uptr stack, ssize;    ReadContextStack(ucp, &stack, &ssize);    ClearShadowMemoryForContextStack(stack, ssize); +#if __has_attribute(__indirect_return__) && \ +    (defined(__x86_64__) || defined(__i386__)) +  int (*real_swapcontext)(struct ucontext_t *, struct ucontext_t *) +    __attribute__((__indirect_return__)) +    = REAL(swapcontext); +  int res = real_swapcontext(oucp, ucp); +#else    int res = REAL(swapcontext)(oucp, ucp); +#endif    // swapcontext technically does not return, but program may swap context to    // "oucp" later, that would look as if swapcontext() returned 0.    // We need to clear shadow for ucp once again, as it may be in arbitrary @@ -318,6 +332,32 @@ INTERCEPTOR(void, __cxa_throw, void *a, void *b, void *c) {  }  #endif +#if ASAN_INTERCEPT___CXA_RETHROW_PRIMARY_EXCEPTION +INTERCEPTOR(void, __cxa_rethrow_primary_exception, void *a) { +  CHECK(REAL(__cxa_rethrow_primary_exception)); +  __asan_handle_no_return(); +  REAL(__cxa_rethrow_primary_exception)(a); +} +#endif + +#if ASAN_INTERCEPT__UNWIND_RAISEEXCEPTION +INTERCEPTOR(_Unwind_Reason_Code, _Unwind_RaiseException, +            _Unwind_Exception *object) { +  CHECK(REAL(_Unwind_RaiseException)); +  __asan_handle_no_return(); +  return REAL(_Unwind_RaiseException)(object); +} +#endif + +#if ASAN_INTERCEPT__SJLJ_UNWIND_RAISEEXCEPTION +INTERCEPTOR(_Unwind_Reason_Code, _Unwind_SjLj_RaiseException, +            _Unwind_Exception *object) { +  CHECK(REAL(_Unwind_SjLj_RaiseException)); +  __asan_handle_no_return(); +  return REAL(_Unwind_SjLj_RaiseException)(object); +} +#endif +  #if ASAN_INTERCEPT_INDEX  # if ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX  INTERCEPTOR(char*, index, const char *string, int c) @@ -540,14 +580,6 @@ INTERCEPTOR(int, __cxa_atexit, void (*func)(void *), void *arg,  }  #endif  // ASAN_INTERCEPT___CXA_ATEXIT -#if ASAN_INTERCEPT_FORK -INTERCEPTOR(int, fork, void) { -  ENSURE_ASAN_INITED(); -  int pid = REAL(fork)(); -  return pid; -} -#endif  // ASAN_INTERCEPT_FORK -  // ---------------------- InitializeAsanInterceptors ---------------- {{{1  namespace __asan {  void InitializeAsanInterceptors() { @@ -598,6 +630,17 @@ void InitializeAsanInterceptors() {  #if ASAN_INTERCEPT___CXA_THROW    ASAN_INTERCEPT_FUNC(__cxa_throw);  #endif +#if ASAN_INTERCEPT___CXA_RETHROW_PRIMARY_EXCEPTION +  ASAN_INTERCEPT_FUNC(__cxa_rethrow_primary_exception); +#endif +  // Indirectly intercept std::rethrow_exception. +#if ASAN_INTERCEPT__UNWIND_RAISEEXCEPTION +  INTERCEPT_FUNCTION(_Unwind_RaiseException); +#endif +  // Indirectly intercept std::rethrow_exception. +#if ASAN_INTERCEPT__UNWIND_SJLJ_RAISEEXCEPTION +  INTERCEPT_FUNCTION(_Unwind_SjLj_RaiseException); +#endif    // Intercept threading-related functions  #if ASAN_INTERCEPT_PTHREAD_CREATE @@ -614,10 +657,6 @@ void InitializeAsanInterceptors() {    ASAN_INTERCEPT_FUNC(__cxa_atexit);  #endif -#if ASAN_INTERCEPT_FORK -  ASAN_INTERCEPT_FUNC(fork); -#endif -    InitializePlatformInterceptors();    VReport(1, "AddressSanitizer: libc interceptors initialized\n"); diff --git a/lib/asan/asan_interceptors.h b/lib/asan/asan_interceptors.h index e13bdecfdeded..50895b1679901 100644 --- a/lib/asan/asan_interceptors.h +++ b/lib/asan/asan_interceptors.h @@ -34,10 +34,10 @@ void InitializePlatformInterceptors();  }  // namespace __asan -// There is no general interception at all on Fuchsia. +// There is no general interception at all on Fuchsia and RTEMS.  // Only the functions in asan_interceptors_memintrinsics.h are  // really defined to replace libc functions. -#if !SANITIZER_FUCHSIA +#if !SANITIZER_FUCHSIA && !SANITIZER_RTEMS  // Use macro to describe if specific function should be  // intercepted on a given platform. @@ -46,13 +46,11 @@ void InitializePlatformInterceptors();  # define ASAN_INTERCEPT__LONGJMP 1  # define ASAN_INTERCEPT_INDEX 1  # define ASAN_INTERCEPT_PTHREAD_CREATE 1 -# define ASAN_INTERCEPT_FORK 1  #else  # define ASAN_INTERCEPT_ATOLL_AND_STRTOLL 0  # define ASAN_INTERCEPT__LONGJMP 0  # define ASAN_INTERCEPT_INDEX 0  # define ASAN_INTERCEPT_PTHREAD_CREATE 0 -# define ASAN_INTERCEPT_FORK 0  #endif  #if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \ @@ -80,13 +78,20 @@ void InitializePlatformInterceptors();  # define ASAN_INTERCEPT___LONGJMP_CHK 0  #endif -// Android bug: https://code.google.com/p/android/issues/detail?id=61799 -#if ASAN_HAS_EXCEPTIONS && !SANITIZER_WINDOWS && \ -    !(SANITIZER_ANDROID && defined(__i386)) && \ -    !SANITIZER_SOLARIS +#if ASAN_HAS_EXCEPTIONS && !SANITIZER_WINDOWS && !SANITIZER_SOLARIS && \ +    !SANITIZER_NETBSD  # define ASAN_INTERCEPT___CXA_THROW 1 +# define ASAN_INTERCEPT___CXA_RETHROW_PRIMARY_EXCEPTION 1 +# if defined(_GLIBCXX_SJLJ_EXCEPTIONS) || (SANITIZER_IOS && defined(__arm__)) +#  define ASAN_INTERCEPT__UNWIND_SJLJ_RAISEEXCEPTION 1 +# else +#  define ASAN_INTERCEPT__UNWIND_RAISEEXCEPTION 1 +# endif  #else  # define ASAN_INTERCEPT___CXA_THROW 0 +# define ASAN_INTERCEPT___CXA_RETHROW_PRIMARY_EXCEPTION 0 +# define ASAN_INTERCEPT__UNWIND_RAISEEXCEPTION 0 +# define ASAN_INTERCEPT__UNWIND_SJLJ_RAISEEXCEPTION 0  #endif  #if !SANITIZER_WINDOWS diff --git a/lib/asan/asan_interceptors_memintrinsics.cc b/lib/asan/asan_interceptors_memintrinsics.cc index c89cb011492ec..39e32cdad12ed 100644 --- a/lib/asan/asan_interceptors_memintrinsics.cc +++ b/lib/asan/asan_interceptors_memintrinsics.cc @@ -31,14 +31,14 @@ void *__asan_memmove(void *to, const void *from, uptr size) {    ASAN_MEMMOVE_IMPL(nullptr, to, from, size);  } -#if SANITIZER_FUCHSIA +#if SANITIZER_FUCHSIA || SANITIZER_RTEMS -// Fuchsia doesn't use sanitizer_common_interceptors.inc, but the only -// things there it wants are these three.  Just define them as aliases -// here rather than repeating the contents. +// Fuchsia and RTEMS don't use sanitizer_common_interceptors.inc, but +// the only things there it wants are these three.  Just define them +// as aliases here rather than repeating the contents. -decltype(memcpy) memcpy[[gnu::alias("__asan_memcpy")]]; -decltype(memmove) memmove[[gnu::alias("__asan_memmove")]]; -decltype(memset) memset[[gnu::alias("__asan_memset")]]; +extern "C" decltype(__asan_memcpy) memcpy[[gnu::alias("__asan_memcpy")]]; +extern "C" decltype(__asan_memmove) memmove[[gnu::alias("__asan_memmove")]]; +extern "C" decltype(__asan_memset) memset[[gnu::alias("__asan_memset")]]; -#endif  // SANITIZER_FUCHSIA +#endif  // SANITIZER_FUCHSIA || SANITIZER_RTEMS diff --git a/lib/asan/asan_interceptors_memintrinsics.h b/lib/asan/asan_interceptors_memintrinsics.h index 5a8339a23e97d..a071e8f684a02 100644 --- a/lib/asan/asan_interceptors_memintrinsics.h +++ b/lib/asan/asan_interceptors_memintrinsics.h @@ -133,15 +133,22 @@ static inline bool RangesOverlap(const char *offset1, uptr length1,                                   const char *offset2, uptr length2) {    return !((offset1 + length1 <= offset2) || (offset2 + length2 <= offset1));  } -#define CHECK_RANGES_OVERLAP(name, _offset1, length1, _offset2, length2) do { \ -  const char *offset1 = (const char*)_offset1; \ -  const char *offset2 = (const char*)_offset2; \ -  if (RangesOverlap(offset1, length1, offset2, length2)) { \ -    GET_STACK_TRACE_FATAL_HERE; \ -    ReportStringFunctionMemoryRangesOverlap(name, offset1, length1, \ -                                            offset2, length2, &stack); \ -  } \ -} while (0) +#define CHECK_RANGES_OVERLAP(name, _offset1, length1, _offset2, length2)   \ +  do {                                                                     \ +    const char *offset1 = (const char *)_offset1;                          \ +    const char *offset2 = (const char *)_offset2;                          \ +    if (RangesOverlap(offset1, length1, offset2, length2)) {               \ +      GET_STACK_TRACE_FATAL_HERE;                                          \ +      bool suppressed = IsInterceptorSuppressed(name);                     \ +      if (!suppressed && HaveStackTraceBasedSuppressions()) {              \ +        suppressed = IsStackTraceSuppressed(&stack);                       \ +      }                                                                    \ +      if (!suppressed) {                                                   \ +        ReportStringFunctionMemoryRangesOverlap(name, offset1, length1,    \ +                                                offset2, length2, &stack); \ +      }                                                                    \ +    }                                                                      \ +  } while (0)  }  // namespace __asan diff --git a/lib/asan/asan_internal.h b/lib/asan/asan_internal.h index 19133e5291a9f..654878cd15f0b 100644 --- a/lib/asan/asan_internal.h +++ b/lib/asan/asan_internal.h @@ -36,7 +36,7 @@  // If set, values like allocator chunk size, as well as defaults for some flags  // will be changed towards less memory overhead.  #ifndef ASAN_LOW_MEMORY -# if SANITIZER_IOS || SANITIZER_ANDROID +# if SANITIZER_IOS || SANITIZER_ANDROID || SANITIZER_RTEMS  #  define ASAN_LOW_MEMORY 1  # else  #  define ASAN_LOW_MEMORY 0 @@ -78,7 +78,7 @@ void InitializeShadowMemory();  // asan_malloc_linux.cc / asan_malloc_mac.cc  void ReplaceSystemMalloc(); -// asan_linux.cc / asan_mac.cc / asan_win.cc +// asan_linux.cc / asan_mac.cc / asan_rtems.cc / asan_win.cc  uptr FindDynamicShadowStart();  void *AsanDoesNotSupportStaticLinkage();  void AsanCheckDynamicRTPrereqs(); @@ -147,6 +147,9 @@ const int kAsanArrayCookieMagic = 0xac;  const int kAsanIntraObjectRedzone = 0xbb;  const int kAsanAllocaLeftMagic = 0xca;  const int kAsanAllocaRightMagic = 0xcb; +// Used to populate the shadow gap for systems without memory +// protection there (i.e. Myriad). +const int kAsanShadowGap = 0xcc;  static const uptr kCurrentStackFrameMagic = 0x41B58AB3;  static const uptr kRetiredStackFrameMagic = 0x45E0360E; diff --git a/lib/asan/asan_linux.cc b/lib/asan/asan_linux.cc index 047e1dbb72fa9..625f32d408dfa 100644 --- a/lib/asan/asan_linux.cc +++ b/lib/asan/asan_linux.cc @@ -32,6 +32,7 @@  #include <sys/types.h>  #include <dlfcn.h>  #include <fcntl.h> +#include <limits.h>  #include <pthread.h>  #include <stdio.h>  #include <unistd.h> @@ -214,7 +215,7 @@ void AsanCheckIncompatibleRT() {        // the functions in dynamic ASan runtime instead of the functions in        // system libraries, causing crashes later in ASan initialization.        MemoryMappingLayout proc_maps(/*cache_enabled*/true); -      char filename[128]; +      char filename[PATH_MAX];        MemoryMappedSegment segment(filename, sizeof(filename));        while (proc_maps.Next(&segment)) {          if (IsDynamicRTName(segment.filename)) { diff --git a/lib/asan/asan_mac.cc b/lib/asan/asan_mac.cc index b7af1a58664c6..17a0ec57701d9 100644 --- a/lib/asan/asan_mac.cc +++ b/lib/asan/asan_mac.cc @@ -62,16 +62,36 @@ uptr FindDynamicShadowStart() {    uptr space_size = kHighShadowEnd + left_padding;    uptr largest_gap_found = 0; -  uptr shadow_start = FindAvailableMemoryRange(space_size, alignment, -                                               granularity, &largest_gap_found); +  uptr max_occupied_addr = 0; +  VReport(2, "FindDynamicShadowStart, space_size = %p\n", space_size); +  uptr shadow_start = +      FindAvailableMemoryRange(space_size, alignment, granularity, +                               &largest_gap_found, &max_occupied_addr);    // If the shadow doesn't fit, restrict the address space to make it fit.    if (shadow_start == 0) { +    VReport( +        2, +        "Shadow doesn't fit, largest_gap_found = %p, max_occupied_addr = %p\n", +        largest_gap_found, max_occupied_addr);      uptr new_max_vm = RoundDownTo(largest_gap_found << SHADOW_SCALE, alignment); +    if (new_max_vm < max_occupied_addr) { +      Report("Unable to find a memory range for dynamic shadow.\n"); +      Report( +          "space_size = %p, largest_gap_found = %p, max_occupied_addr = %p, " +          "new_max_vm = %p\n", +          space_size, largest_gap_found, max_occupied_addr, new_max_vm); +      CHECK(0 && "cannot place shadow"); +    }      RestrictMemoryToMaxAddress(new_max_vm);      kHighMemEnd = new_max_vm - 1;      space_size = kHighShadowEnd + left_padding; -    shadow_start = -        FindAvailableMemoryRange(space_size, alignment, granularity, nullptr); +    VReport(2, "FindDynamicShadowStart, space_size = %p\n", space_size); +    shadow_start = FindAvailableMemoryRange(space_size, alignment, granularity, +                                            nullptr, nullptr); +    if (shadow_start == 0) { +      Report("Unable to find a memory range after restricting VM.\n"); +      CHECK(0 && "cannot place shadow after restricting vm"); +    }    }    CHECK_NE((uptr)0, shadow_start);    CHECK(IsAligned(shadow_start, alignment)); diff --git a/lib/asan/asan_malloc_linux.cc b/lib/asan/asan_malloc_linux.cc index 6697ff8764edc..76bdff999d624 100644 --- a/lib/asan/asan_malloc_linux.cc +++ b/lib/asan/asan_malloc_linux.cc @@ -16,19 +16,23 @@  #include "sanitizer_common/sanitizer_platform.h"  #if SANITIZER_FREEBSD || SANITIZER_FUCHSIA || SANITIZER_LINUX || \ -    SANITIZER_NETBSD || SANITIZER_SOLARIS +    SANITIZER_NETBSD || SANITIZER_RTEMS || SANITIZER_SOLARIS +#include "sanitizer_common/sanitizer_allocator_checks.h" +#include "sanitizer_common/sanitizer_errno.h"  #include "sanitizer_common/sanitizer_tls_get_addr.h"  #include "asan_allocator.h"  #include "asan_interceptors.h"  #include "asan_internal.h" +#include "asan_malloc_local.h"  #include "asan_stack.h"  // ---------------------- Replacement functions ---------------- {{{1  using namespace __asan;  // NOLINT  static uptr allocated_for_dlsym; -static const uptr kDlsymAllocPoolSize = 1024; +static uptr last_dlsym_alloc_size_in_words; +static const uptr kDlsymAllocPoolSize = SANITIZER_RTEMS ? 4096 : 1024;  static uptr alloc_memory_for_dlsym[kDlsymAllocPoolSize];  static INLINE bool IsInDlsymAllocPool(const void *ptr) { @@ -39,21 +43,73 @@ static INLINE bool IsInDlsymAllocPool(const void *ptr) {  static void *AllocateFromLocalPool(uptr size_in_bytes) {    uptr size_in_words = RoundUpTo(size_in_bytes, kWordSize) / kWordSize;    void *mem = (void*)&alloc_memory_for_dlsym[allocated_for_dlsym]; +  last_dlsym_alloc_size_in_words = size_in_words;    allocated_for_dlsym += size_in_words;    CHECK_LT(allocated_for_dlsym, kDlsymAllocPoolSize);    return mem;  } +static void DeallocateFromLocalPool(const void *ptr) { +  // Hack: since glibc 2.27 dlsym no longer uses stack-allocated memory to store +  // error messages and instead uses malloc followed by free. To avoid pool +  // exhaustion due to long object filenames, handle that special case here. +  uptr prev_offset = allocated_for_dlsym - last_dlsym_alloc_size_in_words; +  void *prev_mem = (void*)&alloc_memory_for_dlsym[prev_offset]; +  if (prev_mem == ptr) { +    REAL(memset)(prev_mem, 0, last_dlsym_alloc_size_in_words * kWordSize); +    allocated_for_dlsym = prev_offset; +    last_dlsym_alloc_size_in_words = 0; +  } +} + +static int PosixMemalignFromLocalPool(void **memptr, uptr alignment, +                                      uptr size_in_bytes) { +  if (UNLIKELY(!CheckPosixMemalignAlignment(alignment))) +    return errno_EINVAL; + +  CHECK(alignment >= kWordSize); + +  uptr addr = (uptr)&alloc_memory_for_dlsym[allocated_for_dlsym]; +  uptr aligned_addr = RoundUpTo(addr, alignment); +  uptr aligned_size = RoundUpTo(size_in_bytes, kWordSize); + +  uptr *end_mem = (uptr*)(aligned_addr + aligned_size); +  uptr allocated = end_mem - alloc_memory_for_dlsym; +  if (allocated >= kDlsymAllocPoolSize) +    return errno_ENOMEM; + +  allocated_for_dlsym = allocated; +  *memptr = (void*)aligned_addr; +  return 0; +} + +#if SANITIZER_RTEMS +void* MemalignFromLocalPool(uptr alignment, uptr size) { +  void *ptr = nullptr; +  alignment = Max(alignment, kWordSize); +  PosixMemalignFromLocalPool(&ptr, alignment, size); +  return ptr; +} + +bool IsFromLocalPool(const void *ptr) { +  return IsInDlsymAllocPool(ptr); +} +#endif +  static INLINE bool MaybeInDlsym() {    // Fuchsia doesn't use dlsym-based interceptors.    return !SANITIZER_FUCHSIA && asan_init_is_running;  } +static INLINE bool UseLocalPool() { +  return EarlyMalloc() || MaybeInDlsym(); +} +  static void *ReallocFromLocalPool(void *ptr, uptr size) {    const uptr offset = (uptr)ptr - (uptr)alloc_memory_for_dlsym;    const uptr copy_size = Min(size, kDlsymAllocPoolSize - offset);    void *new_ptr; -  if (UNLIKELY(MaybeInDlsym())) { +  if (UNLIKELY(UseLocalPool())) {      new_ptr = AllocateFromLocalPool(size);    } else {      ENSURE_ASAN_INITED(); @@ -66,8 +122,10 @@ static void *ReallocFromLocalPool(void *ptr, uptr size) {  INTERCEPTOR(void, free, void *ptr) {    GET_STACK_TRACE_FREE; -  if (UNLIKELY(IsInDlsymAllocPool(ptr))) +  if (UNLIKELY(IsInDlsymAllocPool(ptr))) { +    DeallocateFromLocalPool(ptr);      return; +  }    asan_free(ptr, &stack, FROM_MALLOC);  } @@ -81,7 +139,7 @@ INTERCEPTOR(void, cfree, void *ptr) {  #endif // SANITIZER_INTERCEPT_CFREE  INTERCEPTOR(void*, malloc, uptr size) { -  if (UNLIKELY(MaybeInDlsym())) +  if (UNLIKELY(UseLocalPool()))      // Hack: dlsym calls malloc before REAL(malloc) is retrieved from dlsym.      return AllocateFromLocalPool(size);    ENSURE_ASAN_INITED(); @@ -90,7 +148,7 @@ INTERCEPTOR(void*, malloc, uptr size) {  }  INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) { -  if (UNLIKELY(MaybeInDlsym())) +  if (UNLIKELY(UseLocalPool()))      // Hack: dlsym calls calloc before REAL(calloc) is retrieved from dlsym.      return AllocateFromLocalPool(nmemb * size);    ENSURE_ASAN_INITED(); @@ -101,7 +159,7 @@ INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) {  INTERCEPTOR(void*, realloc, void *ptr, uptr size) {    if (UNLIKELY(IsInDlsymAllocPool(ptr)))      return ReallocFromLocalPool(ptr, size); -  if (UNLIKELY(MaybeInDlsym())) +  if (UNLIKELY(UseLocalPool()))      return AllocateFromLocalPool(size);    ENSURE_ASAN_INITED();    GET_STACK_TRACE_MALLOC; @@ -122,10 +180,12 @@ INTERCEPTOR(void*, __libc_memalign, uptr boundary, uptr size) {  }  #endif // SANITIZER_INTERCEPT_MEMALIGN +#if SANITIZER_INTERCEPT_ALIGNED_ALLOC  INTERCEPTOR(void*, aligned_alloc, uptr boundary, uptr size) {    GET_STACK_TRACE_MALLOC; -  return asan_memalign(boundary, size, &stack, FROM_MALLOC); +  return asan_aligned_alloc(boundary, size, &stack);  } +#endif // SANITIZER_INTERCEPT_ALIGNED_ALLOC  INTERCEPTOR(uptr, malloc_usable_size, void *ptr) {    GET_CURRENT_PC_BP_SP; @@ -154,8 +214,9 @@ INTERCEPTOR(int, mallopt, int cmd, int value) {  #endif // SANITIZER_INTERCEPT_MALLOPT_AND_MALLINFO  INTERCEPTOR(int, posix_memalign, void **memptr, uptr alignment, uptr size) { +  if (UNLIKELY(UseLocalPool())) +    return PosixMemalignFromLocalPool(memptr, alignment, size);    GET_STACK_TRACE_MALLOC; -  // Printf("posix_memalign: %zx %zu\n", alignment, size);    return asan_posix_memalign(memptr, alignment, size, &stack);  } diff --git a/lib/asan/asan_malloc_local.h b/lib/asan/asan_malloc_local.h new file mode 100644 index 0000000000000..0e8de207d98d3 --- /dev/null +++ b/lib/asan/asan_malloc_local.h @@ -0,0 +1,44 @@ +//===-- asan_malloc_local.h -------------------------------------*- C++ -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of AddressSanitizer, an address sanity checker. +// +// Provide interfaces to check for and handle local pool memory allocation. +//===----------------------------------------------------------------------===// + +#ifndef ASAN_MALLOC_LOCAL_H +#define ASAN_MALLOC_LOCAL_H + +#include "sanitizer_common/sanitizer_platform.h" +#include "asan_internal.h" + +// On RTEMS, we use the local pool to handle memory allocation when the ASan +// run-time is not up. +static INLINE bool EarlyMalloc() { +  return SANITIZER_RTEMS && (!__asan::asan_inited || +                             __asan::asan_init_is_running); +} + +void* MemalignFromLocalPool(uptr alignment, uptr size); + +#if SANITIZER_RTEMS + +bool IsFromLocalPool(const void *ptr); + +#define ALLOCATE_FROM_LOCAL_POOL UNLIKELY(EarlyMalloc()) +#define IS_FROM_LOCAL_POOL(ptr) UNLIKELY(IsFromLocalPool(ptr)) + +#else  // SANITIZER_RTEMS + +#define ALLOCATE_FROM_LOCAL_POOL 0 +#define IS_FROM_LOCAL_POOL(ptr) 0 + +#endif  // SANITIZER_RTEMS + +#endif  // ASAN_MALLOC_LOCAL_H diff --git a/lib/asan/asan_malloc_mac.cc b/lib/asan/asan_malloc_mac.cc index 744728d40df53..733ba2d86e13b 100644 --- a/lib/asan/asan_malloc_mac.cc +++ b/lib/asan/asan_malloc_mac.cc @@ -38,6 +38,9 @@ using namespace __asan;  #define COMMON_MALLOC_CALLOC(count, size) \    GET_STACK_TRACE_MALLOC; \    void *p = asan_calloc(count, size, &stack); +#define COMMON_MALLOC_POSIX_MEMALIGN(memptr, alignment, size) \ +  GET_STACK_TRACE_MALLOC; \ +  int res = asan_posix_memalign(memptr, alignment, size, &stack);  #define COMMON_MALLOC_VALLOC(size) \    GET_STACK_TRACE_MALLOC; \    void *p = asan_memalign(GetPageSizeCached(), size, &stack, FROM_MALLOC); diff --git a/lib/asan/asan_mapping.h b/lib/asan/asan_mapping.h index d3f360ffc969d..3f8cc004b95f5 100644 --- a/lib/asan/asan_mapping.h +++ b/lib/asan/asan_mapping.h @@ -122,6 +122,13 @@  // || `[0x400000000000, 0x47ffffffffff]` || LowShadow  ||  // || `[0x000000000000, 0x3fffffffffff]` || LowMem     ||  // +// Shadow mapping on NerBSD/i386 with SHADOW_OFFSET == 0x40000000: +// || `[0x60000000, 0xfffff000]` || HighMem    || +// || `[0x4c000000, 0x5fffffff]` || HighShadow || +// || `[0x48000000, 0x4bffffff]` || ShadowGap  || +// || `[0x40000000, 0x47ffffff]` || LowShadow  || +// || `[0x00000000, 0x3fffffff]` || LowMem     || +//  // Default Windows/i386 mapping:  // (the exact location of HighShadow/HighMem may vary depending  //  on WoW64, /LARGEADDRESSAWARE, etc). @@ -130,11 +137,17 @@  // || `[0x36000000, 0x39ffffff]` || ShadowGap  ||  // || `[0x30000000, 0x35ffffff]` || LowShadow  ||  // || `[0x00000000, 0x2fffffff]` || LowMem     || +// +// Shadow mapping on Myriad2 (for shadow scale 5): +// || `[0x9ff80000, 0x9fffffff]` || ShadowGap  || +// || `[0x9f000000, 0x9ff7ffff]` || LowShadow  || +// || `[0x80000000, 0x9effffff]` || LowMem     || +// || `[0x00000000, 0x7fffffff]` || Ignored    ||  #if defined(ASAN_SHADOW_SCALE)  static const u64 kDefaultShadowScale = ASAN_SHADOW_SCALE;  #else -static const u64 kDefaultShadowScale = 3; +static const u64 kDefaultShadowScale = SANITIZER_MYRIAD2 ? 5 : 3;  #endif  static const u64 kDefaultShadowSentinel = ~(uptr)0;  static const u64 kDefaultShadowOffset32 = 1ULL << 29;  // 0x20000000 @@ -152,9 +165,19 @@ static const u64 kPPC64_ShadowOffset64 = 1ULL << 44;  static const u64 kSystemZ_ShadowOffset64 = 1ULL << 52;  static const u64 kFreeBSD_ShadowOffset32 = 1ULL << 30;  // 0x40000000  static const u64 kFreeBSD_ShadowOffset64 = 1ULL << 46;  // 0x400000000000 +static const u64 kNetBSD_ShadowOffset32 = 1ULL << 30;  // 0x40000000  static const u64 kNetBSD_ShadowOffset64 = 1ULL << 46;  // 0x400000000000  static const u64 kWindowsShadowOffset32 = 3ULL << 28;  // 0x30000000 +static const u64 kMyriadMemoryOffset32 = 0x80000000ULL; +static const u64 kMyriadMemorySize32 = 0x20000000ULL; +static const u64 kMyriadMemoryEnd32 = +    kMyriadMemoryOffset32 + kMyriadMemorySize32 - 1; +static const u64 kMyriadShadowOffset32 = +    (kMyriadMemoryOffset32 + kMyriadMemorySize32 - +     (kMyriadMemorySize32 >> kDefaultShadowScale)); +static const u64 kMyriadCacheBitMask32 = 0x40000000ULL; +  #define SHADOW_SCALE kDefaultShadowScale  #if SANITIZER_FUCHSIA @@ -166,6 +189,8 @@ static const u64 kWindowsShadowOffset32 = 3ULL << 28;  // 0x30000000  #    define SHADOW_OFFSET kMIPS32_ShadowOffset32  #  elif SANITIZER_FREEBSD  #    define SHADOW_OFFSET kFreeBSD_ShadowOffset32 +#  elif SANITIZER_NETBSD +#    define SHADOW_OFFSET kNetBSD_ShadowOffset32  #  elif SANITIZER_WINDOWS  #    define SHADOW_OFFSET kWindowsShadowOffset32  #  elif SANITIZER_IOS @@ -174,6 +199,8 @@ static const u64 kWindowsShadowOffset32 = 3ULL << 28;  // 0x30000000  #    else  #      define SHADOW_OFFSET kIosShadowOffset32  #    endif +#  elif SANITIZER_MYRIAD2 +#    define SHADOW_OFFSET kMyriadShadowOffset32  #  else  #    define SHADOW_OFFSET kDefaultShadowOffset32  #  endif @@ -212,6 +239,39 @@ static const u64 kWindowsShadowOffset32 = 3ULL << 28;  // 0x30000000  #endif  #define SHADOW_GRANULARITY (1ULL << SHADOW_SCALE) + +#define DO_ASAN_MAPPING_PROFILE 0  // Set to 1 to profile the functions below. + +#if DO_ASAN_MAPPING_PROFILE +# define PROFILE_ASAN_MAPPING() AsanMappingProfile[__LINE__]++; +#else +# define PROFILE_ASAN_MAPPING() +#endif + +// If 1, all shadow boundaries are constants. +// Don't set to 1 other than for testing. +#define ASAN_FIXED_MAPPING 0 + +namespace __asan { + +extern uptr AsanMappingProfile[]; + +#if ASAN_FIXED_MAPPING +// Fixed mapping for 64-bit Linux. Mostly used for performance comparison +// with non-fixed mapping. As of r175253 (Feb 2013) the performance +// difference between fixed and non-fixed mapping is below the noise level. +static uptr kHighMemEnd = 0x7fffffffffffULL; +static uptr kMidMemBeg =    0x3000000000ULL; +static uptr kMidMemEnd =    0x4fffffffffULL; +#else +extern uptr kHighMemEnd, kMidMemBeg, kMidMemEnd;  // Initialized in __asan_init. +#endif + +}  // namespace __asan + +#if SANITIZER_MYRIAD2 +#include "asan_mapping_myriad.h" +#else  #define MEM_TO_SHADOW(mem) (((mem) >> SHADOW_SCALE) + (SHADOW_OFFSET))  #define kLowMemBeg      0 @@ -243,36 +303,11 @@ static const u64 kWindowsShadowOffset32 = 3ULL << 28;  // 0x30000000  #define kShadowGap3Beg (kMidMemBeg ? kMidMemEnd + 1 : 0)  #define kShadowGap3End (kMidMemBeg ? kHighShadowBeg - 1 : 0) -#define DO_ASAN_MAPPING_PROFILE 0  // Set to 1 to profile the functions below. - -#if DO_ASAN_MAPPING_PROFILE -# define PROFILE_ASAN_MAPPING() AsanMappingProfile[__LINE__]++; -#else -# define PROFILE_ASAN_MAPPING() -#endif - -// If 1, all shadow boundaries are constants. -// Don't set to 1 other than for testing. -#define ASAN_FIXED_MAPPING 0 -  namespace __asan { -extern uptr AsanMappingProfile[]; - -#if ASAN_FIXED_MAPPING -// Fixed mapping for 64-bit Linux. Mostly used for performance comparison -// with non-fixed mapping. As of r175253 (Feb 2013) the performance -// difference between fixed and non-fixed mapping is below the noise level. -static uptr kHighMemEnd = 0x7fffffffffffULL; -static uptr kMidMemBeg =    0x3000000000ULL; -static uptr kMidMemEnd =    0x4fffffffffULL; -#else -extern uptr kHighMemEnd, kMidMemBeg, kMidMemEnd;  // Initialized in __asan_init. -#endif -  static inline bool AddrIsInLowMem(uptr a) {    PROFILE_ASAN_MAPPING(); -  return a < kLowMemEnd; +  return a <= kLowMemEnd;  }  static inline bool AddrIsInLowShadow(uptr a) { @@ -280,14 +315,24 @@ static inline bool AddrIsInLowShadow(uptr a) {    return a >= kLowShadowBeg && a <= kLowShadowEnd;  } +static inline bool AddrIsInMidMem(uptr a) { +  PROFILE_ASAN_MAPPING(); +  return kMidMemBeg && a >= kMidMemBeg && a <= kMidMemEnd; +} + +static inline bool AddrIsInMidShadow(uptr a) { +  PROFILE_ASAN_MAPPING(); +  return kMidMemBeg && a >= kMidShadowBeg && a <= kMidShadowEnd; +} +  static inline bool AddrIsInHighMem(uptr a) {    PROFILE_ASAN_MAPPING(); -  return a >= kHighMemBeg && a <= kHighMemEnd; +  return kHighMemBeg && a >= kHighMemBeg && a <= kHighMemEnd;  } -static inline bool AddrIsInMidMem(uptr a) { +static inline bool AddrIsInHighShadow(uptr a) {    PROFILE_ASAN_MAPPING(); -  return kMidMemBeg && a >= kMidMemBeg && a <= kMidMemEnd; +  return kHighMemBeg && a >= kHighShadowBeg && a <= kHighShadowEnd;  }  static inline bool AddrIsInShadowGap(uptr a) { @@ -305,6 +350,12 @@ static inline bool AddrIsInShadowGap(uptr a) {    return a >= kShadowGapBeg && a <= kShadowGapEnd;  } +}  // namespace __asan + +#endif  // SANITIZER_MYRIAD2 + +namespace __asan { +  static inline bool AddrIsInMem(uptr a) {    PROFILE_ASAN_MAPPING();    return AddrIsInLowMem(a) || AddrIsInMidMem(a) || AddrIsInHighMem(a) || @@ -317,16 +368,6 @@ static inline uptr MemToShadow(uptr p) {    return MEM_TO_SHADOW(p);  } -static inline bool AddrIsInHighShadow(uptr a) { -  PROFILE_ASAN_MAPPING(); -  return a >= kHighShadowBeg && a <= kHighMemEnd; -} - -static inline bool AddrIsInMidShadow(uptr a) { -  PROFILE_ASAN_MAPPING(); -  return kMidMemBeg && a >= kMidShadowBeg && a <= kMidMemEnd; -} -  static inline bool AddrIsInShadow(uptr a) {    PROFILE_ASAN_MAPPING();    return AddrIsInLowShadow(a) || AddrIsInMidShadow(a) || AddrIsInHighShadow(a); @@ -339,6 +380,8 @@ static inline bool AddrIsAlignedByGranularity(uptr a) {  static inline bool AddressIsPoisoned(uptr a) {    PROFILE_ASAN_MAPPING(); +  if (SANITIZER_MYRIAD2 && !AddrIsInMem(a) && !AddrIsInShadow(a)) +    return false;    const uptr kAccessSize = 1;    u8 *shadow_address = (u8*)MEM_TO_SHADOW(a);    s8 shadow_value = *shadow_address; diff --git a/lib/asan/asan_mapping_myriad.h b/lib/asan/asan_mapping_myriad.h new file mode 100644 index 0000000000000..baa3247bd1901 --- /dev/null +++ b/lib/asan/asan_mapping_myriad.h @@ -0,0 +1,86 @@ +//===-- asan_mapping_myriad.h -----------------------------------*- C++ -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of AddressSanitizer, an address sanity checker. +// +// Myriad-specific definitions for ASan memory mapping. +//===----------------------------------------------------------------------===// +#ifndef ASAN_MAPPING_MYRIAD_H +#define ASAN_MAPPING_MYRIAD_H + +#define RAW_ADDR(mem) ((mem) & ~kMyriadCacheBitMask32) +#define MEM_TO_SHADOW(mem) \ +  (((RAW_ADDR(mem) - kLowMemBeg) >> SHADOW_SCALE) + (SHADOW_OFFSET)) + +#define kLowMemBeg     kMyriadMemoryOffset32 +#define kLowMemEnd     (SHADOW_OFFSET - 1) + +#define kLowShadowBeg  SHADOW_OFFSET +#define kLowShadowEnd  MEM_TO_SHADOW(kLowMemEnd) + +#define kHighMemBeg    0 + +#define kHighShadowBeg 0 +#define kHighShadowEnd 0 + +#define kMidShadowBeg  0 +#define kMidShadowEnd  0 + +#define kShadowGapBeg  (kLowShadowEnd + 1) +#define kShadowGapEnd  kMyriadMemoryEnd32 + +#define kShadowGap2Beg 0 +#define kShadowGap2End 0 + +#define kShadowGap3Beg 0 +#define kShadowGap3End 0 + +namespace __asan { + +static inline bool AddrIsInLowMem(uptr a) { +  PROFILE_ASAN_MAPPING(); +  a = RAW_ADDR(a); +  return a >= kLowMemBeg && a <= kLowMemEnd; +} + +static inline bool AddrIsInLowShadow(uptr a) { +  PROFILE_ASAN_MAPPING(); +  a = RAW_ADDR(a); +  return a >= kLowShadowBeg && a <= kLowShadowEnd; +} + +static inline bool AddrIsInMidMem(uptr a) { +  PROFILE_ASAN_MAPPING(); +  return false; +} + +static inline bool AddrIsInMidShadow(uptr a) { +  PROFILE_ASAN_MAPPING(); +  return false; +} + +static inline bool AddrIsInHighMem(uptr a) { +  PROFILE_ASAN_MAPPING(); +  return false; +} + +static inline bool AddrIsInHighShadow(uptr a) { +  PROFILE_ASAN_MAPPING(); +  return false; +} + +static inline bool AddrIsInShadowGap(uptr a) { +  PROFILE_ASAN_MAPPING(); +  a = RAW_ADDR(a); +  return a >= kShadowGapBeg && a <= kShadowGapEnd; +} + +}  // namespace __asan + +#endif  // ASAN_MAPPING_MYRIAD_H diff --git a/lib/asan/asan_memory_profile.cc b/lib/asan/asan_memory_profile.cc index 603284c8c688a..8c86d9fe49f2b 100644 --- a/lib/asan/asan_memory_profile.cc +++ b/lib/asan/asan_memory_profile.cc @@ -31,9 +31,9 @@ struct AllocationSite {  class HeapProfile {   public: -  HeapProfile() : allocations_(1024) {} +  HeapProfile() { allocations_.reserve(1024); } -  void ProcessChunk(const AsanChunkView& cv) { +  void ProcessChunk(const AsanChunkView &cv) {      if (cv.IsAllocated()) {        total_allocated_user_size_ += cv.UsedSize();        total_allocated_count_++; @@ -49,10 +49,10 @@ class HeapProfile {    }    void Print(uptr top_percent, uptr max_number_of_contexts) { -    InternalSort(&allocations_, allocations_.size(), -                 [](const AllocationSite &a, const AllocationSite &b) { -                   return a.total_size > b.total_size; -                 }); +    Sort(allocations_.data(), allocations_.size(), +         [](const AllocationSite &a, const AllocationSite &b) { +           return a.total_size > b.total_size; +         });      CHECK(total_allocated_user_size_);      uptr total_shown = 0;      Printf("Live Heap Allocations: %zd bytes in %zd chunks; quarantined: " diff --git a/lib/asan/asan_new_delete.cc b/lib/asan/asan_new_delete.cc index 072f027addd62..30efd61a9680f 100644 --- a/lib/asan/asan_new_delete.cc +++ b/lib/asan/asan_new_delete.cc @@ -14,6 +14,8 @@  #include "asan_allocator.h"  #include "asan_internal.h" +#include "asan_malloc_local.h" +#include "asan_report.h"  #include "asan_stack.h"  #include "interception/interception.h" @@ -67,16 +69,28 @@ struct nothrow_t {};  enum class align_val_t: size_t {};  }  // namespace std -// TODO(alekseys): throw std::bad_alloc instead of dying on OOM. +// TODO(alekseyshl): throw std::bad_alloc instead of dying on OOM. +// For local pool allocation, align to SHADOW_GRANULARITY to match asan +// allocator behavior.  #define OPERATOR_NEW_BODY(type, nothrow) \ +  if (ALLOCATE_FROM_LOCAL_POOL) {\ +    void *res = MemalignFromLocalPool(SHADOW_GRANULARITY, size);\ +    if (!nothrow) CHECK(res);\ +    return res;\ +  }\    GET_STACK_TRACE_MALLOC;\    void *res = asan_memalign(0, size, &stack, type);\ -  if (!nothrow && UNLIKELY(!res)) DieOnFailure::OnOOM();\ +  if (!nothrow && UNLIKELY(!res)) ReportOutOfMemory(size, &stack);\    return res;  #define OPERATOR_NEW_BODY_ALIGN(type, nothrow) \ +  if (ALLOCATE_FROM_LOCAL_POOL) {\ +    void *res = MemalignFromLocalPool((uptr)align, size);\ +    if (!nothrow) CHECK(res);\ +    return res;\ +  }\    GET_STACK_TRACE_MALLOC;\    void *res = asan_memalign((uptr)align, size, &stack, type);\ -  if (!nothrow && UNLIKELY(!res)) DieOnFailure::OnOOM();\ +  if (!nothrow && UNLIKELY(!res)) ReportOutOfMemory(size, &stack);\    return res;  // On OS X it's not enough to just provide our own 'operator new' and @@ -128,18 +142,22 @@ INTERCEPTOR(void *, _ZnamRKSt9nothrow_t, size_t size, std::nothrow_t const&) {  #endif  // !SANITIZER_MAC  #define OPERATOR_DELETE_BODY(type) \ +  if (IS_FROM_LOCAL_POOL(ptr)) return;\    GET_STACK_TRACE_FREE;\    asan_delete(ptr, 0, 0, &stack, type);  #define OPERATOR_DELETE_BODY_SIZE(type) \ +  if (IS_FROM_LOCAL_POOL(ptr)) return;\    GET_STACK_TRACE_FREE;\    asan_delete(ptr, size, 0, &stack, type);  #define OPERATOR_DELETE_BODY_ALIGN(type) \ +  if (IS_FROM_LOCAL_POOL(ptr)) return;\    GET_STACK_TRACE_FREE;\    asan_delete(ptr, 0, static_cast<uptr>(align), &stack, type);  #define OPERATOR_DELETE_BODY_SIZE_ALIGN(type) \ +  if (IS_FROM_LOCAL_POOL(ptr)) return;\    GET_STACK_TRACE_FREE;\    asan_delete(ptr, size, static_cast<uptr>(align), &stack, type); diff --git a/lib/asan/asan_poisoning.cc b/lib/asan/asan_poisoning.cc index c3a82aa0049e4..1e9c37a13a169 100644 --- a/lib/asan/asan_poisoning.cc +++ b/lib/asan/asan_poisoning.cc @@ -32,7 +32,7 @@ bool CanPoisonMemory() {  }  void PoisonShadow(uptr addr, uptr size, u8 value) { -  if (!CanPoisonMemory()) return; +  if (value && !CanPoisonMemory()) return;    CHECK(AddrIsAlignedByGranularity(addr));    CHECK(AddrIsInMem(addr));    CHECK(AddrIsAlignedByGranularity(addr + size)); @@ -182,8 +182,15 @@ int __asan_address_is_poisoned(void const volatile *addr) {  uptr __asan_region_is_poisoned(uptr beg, uptr size) {    if (!size) return 0;    uptr end = beg + size; -  if (!AddrIsInMem(beg)) return beg; -  if (!AddrIsInMem(end)) return end; +  if (SANITIZER_MYRIAD2) { +    // On Myriad, address not in DRAM range need to be treated as +    // unpoisoned. +    if (!AddrIsInMem(beg) && !AddrIsInShadow(beg)) return 0; +    if (!AddrIsInMem(end) && !AddrIsInShadow(end)) return 0; +  } else { +    if (!AddrIsInMem(beg)) return beg; +    if (!AddrIsInMem(end)) return end; +  }    CHECK_LT(beg, end);    uptr aligned_b = RoundUpTo(beg, SHADOW_GRANULARITY);    uptr aligned_e = RoundDownTo(end, SHADOW_GRANULARITY); @@ -452,4 +459,3 @@ bool WordIsPoisoned(uptr addr) {    return (__asan_region_is_poisoned(addr, sizeof(uptr)) != 0);  }  } - diff --git a/lib/asan/asan_poisoning.h b/lib/asan/asan_poisoning.h index 1e00070bcf631..c94794cead890 100644 --- a/lib/asan/asan_poisoning.h +++ b/lib/asan/asan_poisoning.h @@ -38,7 +38,7 @@ void PoisonShadowPartialRightRedzone(uptr addr,  // performance-critical code with care.  ALWAYS_INLINE void FastPoisonShadow(uptr aligned_beg, uptr aligned_size,                                      u8 value) { -  DCHECK(CanPoisonMemory()); +  DCHECK(!value || CanPoisonMemory());    uptr shadow_beg = MEM_TO_SHADOW(aligned_beg);    uptr shadow_end = MEM_TO_SHADOW(        aligned_beg + aligned_size - SHADOW_GRANULARITY) + 1; @@ -51,6 +51,9 @@ ALWAYS_INLINE void FastPoisonShadow(uptr aligned_beg, uptr aligned_size,        // changed at all.  It doesn't currently have an efficient means        // to zero a bunch of pages, but maybe we should add one.        SANITIZER_FUCHSIA == 1 || +      // RTEMS doesn't have have pages, let alone a fast way to zero +      // them, so default to memset. +      SANITIZER_RTEMS == 1 ||        shadow_end - shadow_beg < common_flags()->clear_shadow_mmap_threshold) {      REAL(memset)((void*)shadow_beg, value, shadow_end - shadow_beg);    } else { diff --git a/lib/asan/asan_report.cc b/lib/asan/asan_report.cc index e3bc02994efd6..439712350e46e 100644 --- a/lib/asan/asan_report.cc +++ b/lib/asan/asan_report.cc @@ -84,7 +84,7 @@ static void PrintZoneForPointer(uptr ptr, uptr zone_ptr,  bool ParseFrameDescription(const char *frame_descr,                             InternalMmapVector<StackVarDescr> *vars) {    CHECK(frame_descr); -  char *p; +  const char *p;    // This string is created by the compiler and has the following form:    // "n alloc_1 alloc_2 ... alloc_n"    // where alloc_i looks like "offset size len ObjectName" @@ -134,6 +134,10 @@ class ScopedInErrorReport {    }    ~ScopedInErrorReport() { +    if (halt_on_error_ && !__sanitizer_acquire_crash_state()) { +      asanThreadRegistry().Unlock(); +      return; +    }      ASAN_ON_ERROR();      if (current_error_.IsValid()) current_error_.Print(); @@ -152,7 +156,7 @@ class ScopedInErrorReport {      // Copy the message buffer so that we could start logging without holding a      // lock that gets aquired during printing. -    InternalScopedBuffer<char> buffer_copy(kErrorMessageBufferSize); +    InternalMmapVector<char> buffer_copy(kErrorMessageBufferSize);      {        BlockingMutexLock l(&error_message_buf_mutex);        internal_memcpy(buffer_copy.data(), @@ -202,7 +206,7 @@ class ScopedInErrorReport {    bool halt_on_error_;  }; -ErrorDescription ScopedInErrorReport::current_error_; +ErrorDescription ScopedInErrorReport::current_error_(LINKER_INITIALIZED);  void ReportDeadlySignal(const SignalContext &sig) {    ScopedInErrorReport in_report(/*fatal*/ true); @@ -254,6 +258,62 @@ void ReportSanitizerGetAllocatedSizeNotOwned(uptr addr,    in_report.ReportError(error);  } +void ReportCallocOverflow(uptr count, uptr size, BufferedStackTrace *stack) { +  ScopedInErrorReport in_report(/*fatal*/ true); +  ErrorCallocOverflow error(GetCurrentTidOrInvalid(), stack, count, size); +  in_report.ReportError(error); +} + +void ReportPvallocOverflow(uptr size, BufferedStackTrace *stack) { +  ScopedInErrorReport in_report(/*fatal*/ true); +  ErrorPvallocOverflow error(GetCurrentTidOrInvalid(), stack, size); +  in_report.ReportError(error); +} + +void ReportInvalidAllocationAlignment(uptr alignment, +                                      BufferedStackTrace *stack) { +  ScopedInErrorReport in_report(/*fatal*/ true); +  ErrorInvalidAllocationAlignment error(GetCurrentTidOrInvalid(), stack, +                                        alignment); +  in_report.ReportError(error); +} + +void ReportInvalidAlignedAllocAlignment(uptr size, uptr alignment, +                                        BufferedStackTrace *stack) { +  ScopedInErrorReport in_report(/*fatal*/ true); +  ErrorInvalidAlignedAllocAlignment error(GetCurrentTidOrInvalid(), stack, +                                          size, alignment); +  in_report.ReportError(error); +} + +void ReportInvalidPosixMemalignAlignment(uptr alignment, +                                         BufferedStackTrace *stack) { +  ScopedInErrorReport in_report(/*fatal*/ true); +  ErrorInvalidPosixMemalignAlignment error(GetCurrentTidOrInvalid(), stack, +                                           alignment); +  in_report.ReportError(error); +} + +void ReportAllocationSizeTooBig(uptr user_size, uptr total_size, uptr max_size, +                                BufferedStackTrace *stack) { +  ScopedInErrorReport in_report(/*fatal*/ true); +  ErrorAllocationSizeTooBig error(GetCurrentTidOrInvalid(), stack, user_size, +                                  total_size, max_size); +  in_report.ReportError(error); +} + +void ReportRssLimitExceeded(BufferedStackTrace *stack) { +  ScopedInErrorReport in_report(/*fatal*/ true); +  ErrorRssLimitExceeded error(GetCurrentTidOrInvalid(), stack); +  in_report.ReportError(error); +} + +void ReportOutOfMemory(uptr requested_size, BufferedStackTrace *stack) { +  ScopedInErrorReport in_report(/*fatal*/ true); +  ErrorOutOfMemory error(GetCurrentTidOrInvalid(), stack, requested_size); +  in_report.ReportError(error); +} +  void ReportStringFunctionMemoryRangesOverlap(const char *function,                                               const char *offset1, uptr length1,                                               const char *offset2, uptr length2, @@ -343,7 +403,11 @@ static bool IsInvalidPointerPair(uptr a1, uptr a2) {  }  static INLINE void CheckForInvalidPointerPair(void *p1, void *p2) { -  if (!flags()->detect_invalid_pointer_pairs) return; +  switch (flags()->detect_invalid_pointer_pairs) { +    case 0 : return; +    case 1 : if (p1 == nullptr || p2 == nullptr) return; break; +  } +    uptr a1 = reinterpret_cast<uptr>(p1);    uptr a2 = reinterpret_cast<uptr>(p2); diff --git a/lib/asan/asan_report.h b/lib/asan/asan_report.h index f2cdad47ee819..f7153d4810d06 100644 --- a/lib/asan/asan_report.h +++ b/lib/asan/asan_report.h @@ -58,6 +58,18 @@ void ReportAllocTypeMismatch(uptr addr, BufferedStackTrace *free_stack,  void ReportMallocUsableSizeNotOwned(uptr addr, BufferedStackTrace *stack);  void ReportSanitizerGetAllocatedSizeNotOwned(uptr addr,                                               BufferedStackTrace *stack); +void ReportCallocOverflow(uptr count, uptr size, BufferedStackTrace *stack); +void ReportPvallocOverflow(uptr size, BufferedStackTrace *stack); +void ReportInvalidAllocationAlignment(uptr alignment, +                                      BufferedStackTrace *stack); +void ReportInvalidAlignedAllocAlignment(uptr size, uptr alignment, +                                        BufferedStackTrace *stack); +void ReportInvalidPosixMemalignAlignment(uptr alignment, +                                         BufferedStackTrace *stack); +void ReportAllocationSizeTooBig(uptr user_size, uptr total_size, uptr max_size, +                                BufferedStackTrace *stack); +void ReportRssLimitExceeded(BufferedStackTrace *stack); +void ReportOutOfMemory(uptr requested_size, BufferedStackTrace *stack);  void ReportStringFunctionMemoryRangesOverlap(const char *function,                                               const char *offset1, uptr length1,                                               const char *offset2, uptr length2, diff --git a/lib/asan/asan_rtems.cc b/lib/asan/asan_rtems.cc new file mode 100644 index 0000000000000..a4af940057eb8 --- /dev/null +++ b/lib/asan/asan_rtems.cc @@ -0,0 +1,253 @@ +//===-- asan_rtems.cc -----------------------------------------------------===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of AddressSanitizer, an address sanity checker. +// +// RTEMS-specific details. +//===----------------------------------------------------------------------===// + +#include "sanitizer_common/sanitizer_rtems.h" +#if SANITIZER_RTEMS + +#include "asan_internal.h" +#include "asan_interceptors.h" +#include "asan_mapping.h" +#include "asan_poisoning.h" +#include "asan_report.h" +#include "asan_stack.h" +#include "sanitizer_common/sanitizer_common.h" +#include "sanitizer_common/sanitizer_libc.h" + +#include <pthread.h> +#include <stdlib.h> + +namespace __asan { + +static void ResetShadowMemory() { +  uptr shadow_start = SHADOW_OFFSET; +  uptr shadow_end = MEM_TO_SHADOW(kMyriadMemoryEnd32); +  uptr gap_start = MEM_TO_SHADOW(shadow_start); +  uptr gap_end = MEM_TO_SHADOW(shadow_end); + +  REAL(memset)((void *)shadow_start, 0, shadow_end - shadow_start); +  REAL(memset)((void *)gap_start, kAsanShadowGap, gap_end - gap_start); +} + +void InitializeShadowMemory() { +  kHighMemEnd = 0; +  kMidMemBeg =  0; +  kMidMemEnd =  0; + +  ResetShadowMemory(); +} + +void AsanApplyToGlobals(globals_op_fptr op, const void *needle) { +  UNIMPLEMENTED(); +} + +void AsanCheckDynamicRTPrereqs() {} +void AsanCheckIncompatibleRT() {} +void InitializeAsanInterceptors() {} +void InitializePlatformInterceptors() {} +void InitializePlatformExceptionHandlers() {} + +// RTEMS only support static linking; it sufficies to return with no +// error. +void *AsanDoesNotSupportStaticLinkage() { return nullptr; } + +void AsanOnDeadlySignal(int signo, void *siginfo, void *context) { +  UNIMPLEMENTED(); +} + +void EarlyInit() { +  // Provide early initialization of shadow memory so that +  // instrumented code running before full initialzation will not +  // report spurious errors. +  ResetShadowMemory(); +} + +// We can use a plain thread_local variable for TSD. +static thread_local void *per_thread; + +void *AsanTSDGet() { return per_thread; } + +void AsanTSDSet(void *tsd) { per_thread = tsd; } + +// There's no initialization needed, and the passed-in destructor +// will never be called.  Instead, our own thread destruction hook +// (below) will call AsanThread::TSDDtor directly. +void AsanTSDInit(void (*destructor)(void *tsd)) { +  DCHECK(destructor == &PlatformTSDDtor); +} + +void PlatformTSDDtor(void *tsd) { UNREACHABLE(__func__); } + +// +// Thread registration.  We provide an API similar to the Fushia port. +// + +struct AsanThread::InitOptions { +  uptr stack_bottom, stack_size, tls_bottom, tls_size; +}; + +// Shared setup between thread creation and startup for the initial thread. +static AsanThread *CreateAsanThread(StackTrace *stack, u32 parent_tid, +                                    uptr user_id, bool detached, +                                    uptr stack_bottom, uptr stack_size, +                                    uptr tls_bottom, uptr tls_size) { +  // In lieu of AsanThread::Create. +  AsanThread *thread = (AsanThread *)MmapOrDie(sizeof(AsanThread), __func__); +  AsanThreadContext::CreateThreadContextArgs args = {thread, stack}; +  asanThreadRegistry().CreateThread(user_id, detached, parent_tid, &args); + +  // On other systems, AsanThread::Init() is called from the new +  // thread itself.  But on RTEMS we already know the stack address +  // range beforehand, so we can do most of the setup right now. +  const AsanThread::InitOptions options = {stack_bottom, stack_size, +                                           tls_bottom, tls_size}; +  thread->Init(&options); +  return thread; +} + +// This gets the same arguments passed to Init by CreateAsanThread, above. +// We're in the creator thread before the new thread is actually started, but +// its stack and tls address range are already known. +void AsanThread::SetThreadStackAndTls(const AsanThread::InitOptions *options) { +  DCHECK_NE(GetCurrentThread(), this); +  DCHECK_NE(GetCurrentThread(), nullptr); +  CHECK_NE(options->stack_bottom, 0); +  CHECK_NE(options->stack_size, 0); +  stack_bottom_ = options->stack_bottom; +  stack_top_ = options->stack_bottom + options->stack_size; +  tls_begin_ = options->tls_bottom; +  tls_end_ = options->tls_bottom + options->tls_size; +} + +// Called by __asan::AsanInitInternal (asan_rtl.c).  Unlike other ports, the +// main thread on RTEMS does not require special treatment; its AsanThread is +// already created by the provided hooks.  This function simply looks up and +// returns the created thread. +AsanThread *CreateMainThread() { +  return GetThreadContextByTidLocked(0)->thread; +} + +// This is called before each thread creation is attempted.  So, in +// its first call, the calling thread is the initial and sole thread. +static void *BeforeThreadCreateHook(uptr user_id, bool detached, +                                    uptr stack_bottom, uptr stack_size, +                                    uptr tls_bottom, uptr tls_size) { +  EnsureMainThreadIDIsCorrect(); +  // Strict init-order checking is thread-hostile. +  if (flags()->strict_init_order) StopInitOrderChecking(); + +  GET_STACK_TRACE_THREAD; +  u32 parent_tid = GetCurrentTidOrInvalid(); + +  return CreateAsanThread(&stack, parent_tid, user_id, detached, +                          stack_bottom, stack_size, tls_bottom, tls_size); +} + +// This is called after creating a new thread (in the creating thread), +// with the pointer returned by BeforeThreadCreateHook (above). +static void ThreadCreateHook(void *hook, bool aborted) { +  AsanThread *thread = static_cast<AsanThread *>(hook); +  if (!aborted) { +    // The thread was created successfully. +    // ThreadStartHook is already running in the new thread. +  } else { +    // The thread wasn't created after all. +    // Clean up everything we set up in BeforeThreadCreateHook. +    asanThreadRegistry().FinishThread(thread->tid()); +    UnmapOrDie(thread, sizeof(AsanThread)); +  } +} + +// This is called (1) in the newly-created thread before it runs anything else, +// with the pointer returned by BeforeThreadCreateHook (above).  (2) before a +// thread restart. +static void ThreadStartHook(void *hook, uptr os_id) { +  if (!hook) +    return; + +  AsanThread *thread = static_cast<AsanThread *>(hook); +  SetCurrentThread(thread); + +  ThreadStatus status = +      asanThreadRegistry().GetThreadLocked(thread->tid())->status; +  DCHECK(status == ThreadStatusCreated || status == ThreadStatusRunning); +  // Determine whether we are starting or restarting the thread. +  if (status == ThreadStatusCreated) +    // In lieu of AsanThread::ThreadStart. +    asanThreadRegistry().StartThread(thread->tid(), os_id, +                                     /*workerthread*/ false, nullptr); +  else { +    // In a thread restart, a thread may resume execution at an +    // arbitrary function entry point, with its stack and TLS state +    // reset.  We unpoison the stack in that case. +    PoisonShadow(thread->stack_bottom(), thread->stack_size(), 0); +  } +} + +// Each thread runs this just before it exits, +// with the pointer returned by BeforeThreadCreateHook (above). +// All per-thread destructors have already been called. +static void ThreadExitHook(void *hook, uptr os_id) { +  AsanThread *thread = static_cast<AsanThread *>(hook); +  if (thread) +    AsanThread::TSDDtor(thread->context()); +} + +static void HandleExit() { +  // Disable ASan by setting it to uninitialized.  Also reset the +  // shadow memory to avoid reporting errors after the run-time has +  // been desroyed. +  if (asan_inited) { +    asan_inited = false; +    ResetShadowMemory(); +  } +} + +}  // namespace __asan + +// These are declared (in extern "C") by <some_path/sanitizer.h>. +// The system runtime will call our definitions directly. + +extern "C" { +void __sanitizer_early_init() { +  __asan::EarlyInit(); +} + +void *__sanitizer_before_thread_create_hook(uptr thread, bool detached, +                                            const char *name, +                                            void *stack_base, size_t stack_size, +                                            void *tls_base, size_t tls_size) { +  return __asan::BeforeThreadCreateHook( +      thread, detached, +      reinterpret_cast<uptr>(stack_base), stack_size, +      reinterpret_cast<uptr>(tls_base), tls_size); +} + +void __sanitizer_thread_create_hook(void *handle, uptr thread, int status) { +  __asan::ThreadCreateHook(handle, status != 0); +} + +void __sanitizer_thread_start_hook(void *handle, uptr self) { +  __asan::ThreadStartHook(handle, self); +} + +void __sanitizer_thread_exit_hook(void *handle, uptr self) { +  __asan::ThreadExitHook(handle, self); +} + +void __sanitizer_exit() { +  __asan::HandleExit(); +} +}  // "C" + +#endif  // SANITIZER_RTEMS diff --git a/lib/asan/asan_rtl.cc b/lib/asan/asan_rtl.cc index 21fd0e2407084..4cff736f213a6 100644 --- a/lib/asan/asan_rtl.cc +++ b/lib/asan/asan_rtl.cc @@ -56,7 +56,8 @@ static void AsanDie() {        UnmapOrDie((void*)kLowShadowBeg, kMidMemBeg - kLowShadowBeg);        UnmapOrDie((void*)kMidMemEnd, kHighShadowEnd - kMidMemEnd);      } else { -      UnmapOrDie((void*)kLowShadowBeg, kHighShadowEnd - kLowShadowBeg); +      if (kHighShadowEnd) +        UnmapOrDie((void*)kLowShadowBeg, kHighShadowEnd - kLowShadowBeg);      }    }  } @@ -65,8 +66,14 @@ static void AsanCheckFailed(const char *file, int line, const char *cond,                              u64 v1, u64 v2) {    Report("AddressSanitizer CHECK failed: %s:%d \"%s\" (0x%zx, 0x%zx)\n", file,           line, cond, (uptr)v1, (uptr)v2); -  // FIXME: check for infinite recursion without a thread-local counter here. -  PRINT_CURRENT_STACK_CHECK(); + +  // Print a stack trace the first time we come here. Otherwise, we probably +  // failed a CHECK during symbolization. +  static atomic_uint32_t num_calls; +  if (atomic_fetch_add(&num_calls, 1, memory_order_relaxed) == 0) { +    PRINT_CURRENT_STACK_CHECK(); +  } +    Die();  } @@ -140,6 +147,8 @@ ASAN_REPORT_ERROR_N(load, false)  ASAN_REPORT_ERROR_N(store, true)  #define ASAN_MEMORY_ACCESS_CALLBACK_BODY(type, is_write, size, exp_arg, fatal) \ +    if (SANITIZER_MYRIAD2 && !AddrIsInMem(addr) && !AddrIsInShadow(addr))      \ +      return;                                                                  \      uptr sp = MEM_TO_SHADOW(addr);                                             \      uptr s = size <= SHADOW_GRANULARITY ? *reinterpret_cast<u8 *>(sp)          \                                          : *reinterpret_cast<u16 *>(sp);        \ @@ -306,6 +315,7 @@ static void asan_atexit() {  }  static void InitializeHighMemEnd() { +#if !SANITIZER_MYRIAD2  #if !ASAN_FIXED_MAPPING    kHighMemEnd = GetMaxUserVirtualAddress();    // Increase kHighMemEnd to make sure it's properly @@ -313,13 +323,16 @@ static void InitializeHighMemEnd() {    kHighMemEnd |= SHADOW_GRANULARITY * GetMmapGranularity() - 1;  #endif  // !ASAN_FIXED_MAPPING    CHECK_EQ((kHighMemBeg % GetMmapGranularity()), 0); +#endif  // !SANITIZER_MYRIAD2  }  void PrintAddressSpaceLayout() { -  Printf("|| `[%p, %p]` || HighMem    ||\n", -         (void*)kHighMemBeg, (void*)kHighMemEnd); -  Printf("|| `[%p, %p]` || HighShadow ||\n", -         (void*)kHighShadowBeg, (void*)kHighShadowEnd); +  if (kHighMemBeg) { +    Printf("|| `[%p, %p]` || HighMem    ||\n", +           (void*)kHighMemBeg, (void*)kHighMemEnd); +    Printf("|| `[%p, %p]` || HighShadow ||\n", +           (void*)kHighShadowBeg, (void*)kHighShadowEnd); +  }    if (kMidMemBeg) {      Printf("|| `[%p, %p]` || ShadowGap3 ||\n",             (void*)kShadowGap3Beg, (void*)kShadowGap3End); @@ -338,11 +351,14 @@ void PrintAddressSpaceLayout() {      Printf("|| `[%p, %p]` || LowMem     ||\n",             (void*)kLowMemBeg, (void*)kLowMemEnd);    } -  Printf("MemToShadow(shadow): %p %p %p %p", +  Printf("MemToShadow(shadow): %p %p",           (void*)MEM_TO_SHADOW(kLowShadowBeg), -         (void*)MEM_TO_SHADOW(kLowShadowEnd), -         (void*)MEM_TO_SHADOW(kHighShadowBeg), -         (void*)MEM_TO_SHADOW(kHighShadowEnd)); +         (void*)MEM_TO_SHADOW(kLowShadowEnd)); +  if (kHighMemBeg) { +    Printf(" %p %p", +           (void*)MEM_TO_SHADOW(kHighShadowBeg), +           (void*)MEM_TO_SHADOW(kHighShadowEnd)); +  }    if (kMidMemBeg) {      Printf(" %p %p",             (void*)MEM_TO_SHADOW(kMidShadowBeg), @@ -374,6 +390,7 @@ static void AsanInitInternal() {    asan_init_is_running = true;    CacheBinaryName(); +  CheckASLR();    // Initialize flags. This must be done early, because most of the    // initialization steps look at flags(). @@ -526,6 +543,9 @@ void NOINLINE __asan_handle_no_return() {    if (curr_thread) {      top = curr_thread->stack_top();      bottom = ((uptr)&local_stack - PageSize) & ~(PageSize - 1); +  } else if (SANITIZER_RTEMS) { +    // Give up On RTEMS. +    return;    } else {      CHECK(!SANITIZER_FUCHSIA);      // If we haven't seen this thread, try asking the OS for stack bounds. diff --git a/lib/asan/asan_shadow_setup.cc b/lib/asan/asan_shadow_setup.cc index b3cf0b5c1ce25..083926e70aa2d 100644 --- a/lib/asan/asan_shadow_setup.cc +++ b/lib/asan/asan_shadow_setup.cc @@ -14,8 +14,9 @@  #include "sanitizer_common/sanitizer_platform.h" -// asan_fuchsia.cc has its own InitializeShadowMemory implementation. -#if !SANITIZER_FUCHSIA +// asan_fuchsia.cc and asan_rtems.cc have their own +// InitializeShadowMemory implementation. +#if !SANITIZER_FUCHSIA && !SANITIZER_RTEMS  #include "asan_internal.h"  #include "asan_mapping.h" @@ -30,8 +31,7 @@ void ReserveShadowMemoryRange(uptr beg, uptr end, const char *name) {    CHECK_EQ(((end + 1) % GetMmapGranularity()), 0);    uptr size = end - beg + 1;    DecreaseTotalMmap(size);  // Don't count the shadow against mmap_limit_mb. -  void *res = MmapFixedNoReserve(beg, size, name); -  if (res != (void *)beg) { +  if (!MmapFixedNoReserve(beg, size, name)) {      Report(          "ReserveShadowMemoryRange failed while trying to map 0x%zx bytes. "          "Perhaps you're using ulimit -v\n", @@ -162,4 +162,4 @@ void InitializeShadowMemory() {  }  // namespace __asan -#endif  // !SANITIZER_FUCHSIA +#endif  // !SANITIZER_FUCHSIA && !SANITIZER_RTEMS diff --git a/lib/asan/asan_thread.cc b/lib/asan/asan_thread.cc index ad81512dff080..faf423d305b7d 100644 --- a/lib/asan/asan_thread.cc +++ b/lib/asan/asan_thread.cc @@ -221,22 +221,25 @@ FakeStack *AsanThread::AsyncSignalSafeLazyInitFakeStack() {  void AsanThread::Init(const InitOptions *options) {    next_stack_top_ = next_stack_bottom_ = 0;    atomic_store(&stack_switching_, false, memory_order_release); -  fake_stack_ = nullptr;  // Will be initialized lazily if needed.    CHECK_EQ(this->stack_size(), 0U);    SetThreadStackAndTls(options);    CHECK_GT(this->stack_size(), 0U);    CHECK(AddrIsInMem(stack_bottom_));    CHECK(AddrIsInMem(stack_top_ - 1));    ClearShadowForThreadStackAndTLS(); +  fake_stack_ = nullptr; +  if (__asan_option_detect_stack_use_after_return) +    AsyncSignalSafeLazyInitFakeStack();    int local = 0;    VReport(1, "T%d: stack [%p,%p) size 0x%zx; local=%p\n", tid(),            (void *)stack_bottom_, (void *)stack_top_, stack_top_ - stack_bottom_,            &local);  } -// Fuchsia doesn't use ThreadStart. -// asan_fuchsia.c defines CreateMainThread and SetThreadStackAndTls. -#if !SANITIZER_FUCHSIA +// Fuchsia and RTEMS don't use ThreadStart. +// asan_fuchsia.c/asan_rtems.c define CreateMainThread and +// SetThreadStackAndTls. +#if !SANITIZER_FUCHSIA && !SANITIZER_RTEMS  thread_return_t AsanThread::ThreadStart(      tid_t os_id, atomic_uintptr_t *signal_thread_is_registered) { @@ -296,12 +299,17 @@ void AsanThread::SetThreadStackAndTls(const InitOptions *options) {    CHECK(AddrIsInStack((uptr)&local));  } -#endif  // !SANITIZER_FUCHSIA +#endif  // !SANITIZER_FUCHSIA && !SANITIZER_RTEMS  void AsanThread::ClearShadowForThreadStackAndTLS() {    PoisonShadow(stack_bottom_, stack_top_ - stack_bottom_, 0); -  if (tls_begin_ != tls_end_) -    PoisonShadow(tls_begin_, tls_end_ - tls_begin_, 0); +  if (tls_begin_ != tls_end_) { +    uptr tls_begin_aligned = RoundDownTo(tls_begin_, SHADOW_GRANULARITY); +    uptr tls_end_aligned = RoundUpTo(tls_end_, SHADOW_GRANULARITY); +    FastPoisonShadowPartialRightRedzone(tls_begin_aligned, +                                        tls_end_ - tls_begin_aligned, +                                        tls_end_aligned - tls_end_, 0); +  }  }  bool AsanThread::GetStackFrameAccessByAddr(uptr addr, @@ -386,6 +394,9 @@ static bool ThreadStackContainsAddress(ThreadContextBase *tctx_base,  }  AsanThread *GetCurrentThread() { +  if (SANITIZER_RTEMS && !asan_inited) +    return nullptr; +    AsanThreadContext *context =        reinterpret_cast<AsanThreadContext *>(AsanTSDGet());    if (!context) { @@ -477,6 +488,11 @@ void UnlockThreadRegistry() {    __asan::asanThreadRegistry().Unlock();  } +ThreadRegistry *GetThreadRegistryLocked() { +  __asan::asanThreadRegistry().CheckLocked(); +  return &__asan::asanThreadRegistry(); +} +  void EnsureMainThreadIDIsCorrect() {    __asan::EnsureMainThreadIDIsCorrect();  } diff --git a/lib/asan/asan_win.cc b/lib/asan/asan_win.cc index 68eedd1863bcb..67125d38ad4a3 100644 --- a/lib/asan/asan_win.cc +++ b/lib/asan/asan_win.cc @@ -222,8 +222,8 @@ uptr FindDynamicShadowStart() {    uptr alignment = 8 * granularity;    uptr left_padding = granularity;    uptr space_size = kHighShadowEnd + left_padding; -  uptr shadow_start = -      FindAvailableMemoryRange(space_size, alignment, granularity, nullptr); +  uptr shadow_start = FindAvailableMemoryRange(space_size, alignment, +                                               granularity, nullptr, nullptr);    CHECK_NE((uptr)0, shadow_start);    CHECK(IsAligned(shadow_start, alignment));    return shadow_start; @@ -265,11 +265,6 @@ ShadowExceptionHandler(PEXCEPTION_POINTERS exception_pointers) {    // Determine the address of the page that is being accessed.    uptr page = RoundDownTo(addr, page_size); -  // Query the existing page. -  MEMORY_BASIC_INFORMATION mem_info = {}; -  if (::VirtualQuery((LPVOID)page, &mem_info, sizeof(mem_info)) == 0) -    return EXCEPTION_CONTINUE_SEARCH; -    // Commit the page.    uptr result =        (uptr)::VirtualAlloc((LPVOID)page, page_size, MEM_COMMIT, PAGE_READWRITE); diff --git a/lib/asan/asan_win_dll_thunk.cc b/lib/asan/asan_win_dll_thunk.cc index c67116c42ca2a..c6a313d24026e 100644 --- a/lib/asan/asan_win_dll_thunk.cc +++ b/lib/asan/asan_win_dll_thunk.cc @@ -99,7 +99,7 @@ INTERCEPTOR(int, _except_handler4, void *a, void *b, void *c, void *d) {  }  #endif -// Window specific functions not included in asan_interface.inc. +// Windows specific functions not included in asan_interface.inc.  INTERCEPT_WRAP_W_V(__asan_should_detect_stack_use_after_return)  INTERCEPT_WRAP_W_V(__asan_get_shadow_memory_dynamic_address)  INTERCEPT_WRAP_W_W(__asan_unhandled_exception_filter) diff --git a/lib/asan/scripts/asan_device_setup b/lib/asan/scripts/asan_device_setup index 92a109727267f..5e679e366514a 100755 --- a/lib/asan/scripts/asan_device_setup +++ b/lib/asan/scripts/asan_device_setup @@ -309,7 +309,7 @@ if [[ -n "$ASAN_RT64" ]]; then    cp "$ASAN_RT_PATH/$ASAN_RT64" "$TMPDIR/"  fi -ASAN_OPTIONS=start_deactivated=1,malloc_context_size=0 +ASAN_OPTIONS=start_deactivated=1  # The name of a symlink to libclang_rt.asan-$ARCH-android.so used in LD_PRELOAD.  # The idea is to have the same name in lib and lib64 to keep it from falling @@ -336,6 +336,13 @@ exec $_to \$@  EOF  } +# On Android-L not allowing user segv handler breaks some applications. +# Since ~May 2017 this is the default setting; included for compatibility with +# older library versions. +if [[ PRE_L -eq 0 ]]; then +    ASAN_OPTIONS="$ASAN_OPTIONS,allow_user_segv_handler=1" +fi +  if [[ x$extra_options != x ]] ; then      ASAN_OPTIONS="$ASAN_OPTIONS,$extra_options"  fi diff --git a/lib/asan/tests/CMakeLists.txt b/lib/asan/tests/CMakeLists.txt index 67a8fafaba3c5..1b70605915301 100644 --- a/lib/asan/tests/CMakeLists.txt +++ b/lib/asan/tests/CMakeLists.txt @@ -237,6 +237,9 @@ if(COMPILER_RT_CAN_EXECUTE_TESTS AND NOT ANDROID)    if(APPLE)      darwin_filter_host_archs(ASAN_SUPPORTED_ARCH ASAN_TEST_ARCH)    endif() +  if(OS_NAME MATCHES "SunOS") +    list(REMOVE_ITEM ASAN_TEST_ARCH x86_64) +  endif()    foreach(arch ${ASAN_TEST_ARCH}) @@ -248,6 +251,8 @@ if(COMPILER_RT_CAN_EXECUTE_TESTS AND NOT ANDROID)          $<TARGET_OBJECTS:RTInterception.osx>          $<TARGET_OBJECTS:RTSanitizerCommon.osx>          $<TARGET_OBJECTS:RTSanitizerCommonLibc.osx> +        $<TARGET_OBJECTS:RTSanitizerCommonCoverage.osx> +        $<TARGET_OBJECTS:RTSanitizerCommonSymbolizer.osx>          $<TARGET_OBJECTS:RTLSanCommon.osx>          $<TARGET_OBJECTS:RTUbsan.osx>)      else() @@ -257,6 +262,8 @@ if(COMPILER_RT_CAN_EXECUTE_TESTS AND NOT ANDROID)          $<TARGET_OBJECTS:RTInterception.${arch}>          $<TARGET_OBJECTS:RTSanitizerCommon.${arch}>          $<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}> +        $<TARGET_OBJECTS:RTSanitizerCommonCoverage.${arch}> +        $<TARGET_OBJECTS:RTSanitizerCommonSymbolizer.${arch}>          $<TARGET_OBJECTS:RTLSanCommon.${arch}>          $<TARGET_OBJECTS:RTUbsan.${arch}>          $<TARGET_OBJECTS:RTUbsan_cxx.${arch}>) @@ -280,6 +287,8 @@ if(ANDROID)        $<TARGET_OBJECTS:RTInterception.${arch}>        $<TARGET_OBJECTS:RTSanitizerCommon.${arch}>        $<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}> +      $<TARGET_OBJECTS:RTSanitizerCommonCoverage.${arch}> +      $<TARGET_OBJECTS:RTSanitizerCommonSymbolizer.${arch}>        $<TARGET_OBJECTS:RTUbsan.${arch}>        $<TARGET_OBJECTS:RTUbsan_cxx.${arch}>        ${COMPILER_RT_GTEST_SOURCE} diff --git a/lib/asan/tests/asan_test.cc b/lib/asan/tests/asan_test.cc index ed000327f1266..11a3506a4853e 100644 --- a/lib/asan/tests/asan_test.cc +++ b/lib/asan/tests/asan_test.cc @@ -25,6 +25,11 @@  #endif  #endif +#if defined(__sun__) && defined(__svr4__) +using std::_setjmp; +using std::_longjmp; +#endif +  NOINLINE void *malloc_fff(size_t size) {    void *res = malloc/**/(size); break_optimization(0); return res;}  NOINLINE void *malloc_eee(size_t size) { diff --git a/lib/builtins/CMakeLists.txt b/lib/builtins/CMakeLists.txt index 0b50b5bb8d239..75ff66405649c 100644 --- a/lib/builtins/CMakeLists.txt +++ b/lib/builtins/CMakeLists.txt @@ -173,8 +173,8 @@ set(GENERIC_TF_SOURCES    trunctfsf2.c)  option(COMPILER_RT_EXCLUDE_ATOMIC_BUILTIN -  "Skip the atomic builtin (this may be needed if system headers are unavailable)" -  Off) +  "Skip the atomic builtin (these should normally be provided by a shared library)" +  On)  if(NOT FUCHSIA AND NOT COMPILER_RT_BAREMETAL_BUILD)    set(GENERIC_SOURCES @@ -406,6 +406,7 @@ if(MINGW)        arm/aeabi_ldivmod.S        arm/aeabi_uidivmod.S        arm/aeabi_uldivmod.S +      arm/chkstk.S        divmoddi4.c        divmodsi4.c        divdi3.c @@ -459,6 +460,41 @@ set(armv6m_SOURCES ${thumb1_SOURCES})  set(armv7m_SOURCES ${arm_SOURCES})  set(armv7em_SOURCES ${arm_SOURCES}) +# hexagon arch +set(hexagon_SOURCES ${GENERIC_SOURCES} ${GENERIC_TF_SOURCES}) +set(hexagon_SOURCES +  hexagon/common_entry_exit_abi1.S +  hexagon/common_entry_exit_abi2.S +  hexagon/common_entry_exit_legacy.S +  hexagon/dfaddsub.S +  hexagon/dfdiv.S +  hexagon/dffma.S +  hexagon/dfminmax.S +  hexagon/dfmul.S +  hexagon/dfsqrt.S +  hexagon/divdi3.S +  hexagon/divsi3.S +  hexagon/fabs_opt.S +  hexagon/fastmath2_dlib_asm.S +  hexagon/fastmath2_ldlib_asm.S +  hexagon/fastmath_dlib_asm.S +  hexagon/fma_opt.S +  hexagon/fmax_opt.S +  hexagon/fmin_opt.S +  hexagon/memcpy_forward_vp4cp4n2.S +  hexagon/memcpy_likely_aligned.S +  hexagon/moddi3.S +  hexagon/modsi3.S +  hexagon/sfdiv_opt.S +  hexagon/sfsqrt_opt.S +  hexagon/udivdi3.S +  hexagon/udivmoddi4.S +  hexagon/udivmodsi4.S +  hexagon/udivsi3.S +  hexagon/umoddi3.S +  hexagon/umodsi3.S) + +  set(mips_SOURCES ${GENERIC_SOURCES})  set(mipsel_SOURCES ${mips_SOURCES})  set(mips64_SOURCES ${GENERIC_TF_SOURCES} @@ -480,6 +516,12 @@ set(powerpc64_SOURCES    ${GENERIC_SOURCES})  set(powerpc64le_SOURCES ${powerpc64_SOURCES}) +set(riscv_SOURCES ${GENERIC_SOURCES} ${GENERIC_TF_SOURCES}) +set(riscv32_SOURCES +  riscv/mulsi3.S +  ${riscv_SOURCES}) +set(riscv64_SOURCES ${riscv_SOURCES}) +  set(wasm32_SOURCES    ${GENERIC_TF_SOURCES}    ${GENERIC_SOURCES}) @@ -542,6 +584,12 @@ else ()          list(APPEND BUILTIN_CFLAGS -fomit-frame-pointer -DCOMPILER_RT_ARMHF_TARGET)        endif() +      # For RISCV32, we must force enable int128 for compiling long +      # double routines. +      if("${arch}" STREQUAL "riscv32") +        list(APPEND BUILTIN_CFLAGS -fforce-enable-int128) +      endif() +        add_compiler_rt_runtime(clang_rt.builtins                                STATIC                                ARCHS ${arch} diff --git a/lib/builtins/arm/chkstk.S b/lib/builtins/arm/chkstk.S new file mode 100644 index 0000000000000..e3002105897ea --- /dev/null +++ b/lib/builtins/arm/chkstk.S @@ -0,0 +1,34 @@ +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. + +#include "../assembly.h" + +// __chkstk routine +// This routine is windows specific. +// http://msdn.microsoft.com/en-us/library/ms648426.aspx + +// This clobbers the register r12, and the condition codes, and uses r5 and r6 +// as temporaries by backing them up and restoring them afterwards. +// Does not modify any memory or the stack pointer. + +//      movw    r4,  #256 // Number of bytes of stack, in units of 4 byte +//      bl      __chkstk +//      sub.w   sp, sp, r4 + +#define PAGE_SIZE 4096 + +        .p2align 2 +DEFINE_COMPILERRT_FUNCTION(__chkstk) +        lsl    r4,  r4,  #2 +        mov    r12, sp +        push   {r5, r6} +        mov    r5,  r4 +1: +        sub    r12, r12, #PAGE_SIZE +        subs   r5,  r5,  #PAGE_SIZE +        ldr    r6,  [r12] +        bgt    1b + +        pop    {r5, r6} +        bx     lr +END_COMPILERRT_FUNCTION(__chkstk) diff --git a/lib/builtins/clear_cache.c b/lib/builtins/clear_cache.c index 4a01cb46d4ac4..9dcab344ad1b5 100644 --- a/lib/builtins/clear_cache.c +++ b/lib/builtins/clear_cache.c @@ -33,6 +33,11 @@ uintptr_t GetCurrentProcess(void);    #include <machine/sysarch.h>  #endif +#if defined(__OpenBSD__) && defined(__mips__) +  #include <sys/types.h> +  #include <machine/sysarch.h> +#endif +  #if defined(__linux__) && defined(__mips__)    #include <sys/cachectl.h>    #include <sys/syscall.h> @@ -96,6 +101,8 @@ void __clear_cache(void *start, void *end) {   * Intel processors have a unified instruction and data cache   * so there is nothing to do   */ +#elif defined(_WIN32) && (defined(__arm__) || defined(__aarch64__)) +    FlushInstructionCache(GetCurrentProcess(), start, end - start);  #elif defined(__arm__) && !defined(__APPLE__)      #if defined(__FreeBSD__) || defined(__NetBSD__)          struct arm_sync_icache_args arg; @@ -123,8 +130,6 @@ void __clear_cache(void *start, void *end) {                            : "r"(syscall_nr), "r"(start_reg), "r"(end_reg),                              "r"(flags));           assert(start_reg == 0 && "Cache flush syscall failed."); -    #elif defined(_WIN32) -        FlushInstructionCache(GetCurrentProcess(), start, end - start);      #else          compilerrt_abort();      #endif @@ -142,6 +147,8 @@ void __clear_cache(void *start, void *end) {      #else          syscall(__NR_cacheflush, start, (end_int - start_int), BCACHE);      #endif +#elif defined(__mips__) && defined(__OpenBSD__) +  cacheflush(start, (uintptr_t)end - (uintptr_t)start, BCACHE);  #elif defined(__aarch64__) && !defined(__APPLE__)    uint64_t xstart = (uint64_t)(uintptr_t) start;    uint64_t xend = (uint64_t)(uintptr_t) end; @@ -156,12 +163,14 @@ void __clear_cache(void *start, void *end) {     * uintptr_t in case this runs in an IPL32 environment.     */    const size_t dcache_line_size = 4 << ((ctr_el0 >> 16) & 15); -  for (addr = xstart; addr < xend; addr += dcache_line_size) +  for (addr = xstart & ~(dcache_line_size - 1); addr < xend; +       addr += dcache_line_size)      __asm __volatile("dc cvau, %0" :: "r"(addr));    __asm __volatile("dsb ish");    const size_t icache_line_size = 4 << ((ctr_el0 >> 0) & 15); -  for (addr = xstart; addr < xend; addr += icache_line_size) +  for (addr = xstart & ~(icache_line_size - 1); addr < xend; +       addr += icache_line_size)      __asm __volatile("ic ivau, %0" :: "r"(addr));    __asm __volatile("isb sy");  #elif defined (__powerpc64__) diff --git a/lib/builtins/clzdi2.c b/lib/builtins/clzdi2.c index b9e64da492bda..b56d98f5c01f5 100644 --- a/lib/builtins/clzdi2.c +++ b/lib/builtins/clzdi2.c @@ -16,6 +16,12 @@  /* Returns: the number of leading 0-bits */ +#if !defined(__clang__) && (defined(__sparc64__) || defined(__mips64) || defined(__riscv__)) +/* gcc resolves __builtin_clz -> __clzdi2 leading to infinite recursion */ +#define __builtin_clz(a) __clzsi2(a) +extern si_int __clzsi2(si_int); +#endif +  /* Precondition: a != 0 */  COMPILER_RT_ABI si_int diff --git a/lib/builtins/cpu_model.c b/lib/builtins/cpu_model.c index 4c96e9cd85d59..43b913390fc41 100644 --- a/lib/builtins/cpu_model.c +++ b/lib/builtins/cpu_model.c @@ -416,9 +416,9 @@ static void getAMDProcessorTypeAndSubtype(unsigned Family, unsigned Model,        *Subtype = AMDFAM15H_BDVER3;        break; // "bdver3"; 30h-3Fh: Steamroller      } -    if (Model >= 0x10 && Model <= 0x1f) { +    if ((Model >= 0x10 && Model <= 0x1f) || Model == 0x02) {        *Subtype = AMDFAM15H_BDVER2; -      break; // "bdver2"; 10h-1Fh: Piledriver +      break; // "bdver2"; 02h, 10h-1Fh: Piledriver      }      if (Model <= 0x0f) {        *Subtype = AMDFAM15H_BDVER1; diff --git a/lib/builtins/ctzdi2.c b/lib/builtins/ctzdi2.c index db3c6fdc08f10..eecde29718d73 100644 --- a/lib/builtins/ctzdi2.c +++ b/lib/builtins/ctzdi2.c @@ -16,6 +16,12 @@  /* Returns: the number of trailing 0-bits  */ +#if !defined(__clang__) && (defined(__sparc64__) || defined(__mips64) || defined(__riscv__)) +/* gcc resolves __builtin_ctz -> __ctzdi2 leading to infinite recursion */ +#define __builtin_ctz(a) __ctzsi2(a) +extern si_int __ctzsi2(si_int); +#endif +  /* Precondition: a != 0 */  COMPILER_RT_ABI si_int diff --git a/lib/builtins/emutls.c b/lib/builtins/emutls.c index 5dd8dd1547718..07d436e267d8d 100644 --- a/lib/builtins/emutls.c +++ b/lib/builtins/emutls.c @@ -14,7 +14,22 @@  #include "int_lib.h"  #include "int_util.h" +#ifdef __BIONIC__ +/* There are 4 pthread key cleanup rounds on Bionic. Delay emutls deallocation +   to round 2. We need to delay deallocation because: +    - Android versions older than M lack __cxa_thread_atexit_impl, so apps +      use a pthread key destructor to call C++ destructors. +    - Apps might use __thread/thread_local variables in pthread destructors. +   We can't wait until the final two rounds, because jemalloc needs two rounds +   after the final malloc/free call to free its thread-specific data (see +   https://reviews.llvm.org/D46978#1107507). */ +#define EMUTLS_SKIP_DESTRUCTOR_ROUNDS 1 +#else +#define EMUTLS_SKIP_DESTRUCTOR_ROUNDS 0 +#endif +  typedef struct emutls_address_array { +    uintptr_t skip_destructor_rounds;      uintptr_t size;  /* number of elements in the 'data' array */      void* data[];  } emutls_address_array; @@ -65,9 +80,30 @@ static __inline void emutls_memalign_free(void *base) {  #endif  } +static __inline void emutls_setspecific(emutls_address_array *value) { +    pthread_setspecific(emutls_pthread_key, (void*) value); +} + +static __inline emutls_address_array* emutls_getspecific() { +    return (emutls_address_array*) pthread_getspecific(emutls_pthread_key); +} +  static void emutls_key_destructor(void* ptr) { -    emutls_shutdown((emutls_address_array*)ptr); -    free(ptr); +    emutls_address_array *array = (emutls_address_array*)ptr; +    if (array->skip_destructor_rounds > 0) { +        /* emutls is deallocated using a pthread key destructor. These +         * destructors are called in several rounds to accommodate destructor +         * functions that (re)initialize key values with pthread_setspecific. +         * Delay the emutls deallocation to accommodate other end-of-thread +         * cleanup tasks like calling thread_local destructors (e.g. the +         * __cxa_thread_atexit fallback in libc++abi). +         */ +        array->skip_destructor_rounds--; +        emutls_setspecific(array); +    } else { +        emutls_shutdown(array); +        free(ptr); +    }  }  static __inline void emutls_init(void) { @@ -88,15 +124,7 @@ static __inline void emutls_unlock() {      pthread_mutex_unlock(&emutls_mutex);  } -static __inline void emutls_setspecific(emutls_address_array *value) { -    pthread_setspecific(emutls_pthread_key, (void*) value); -} - -static __inline emutls_address_array* emutls_getspecific() { -    return (emutls_address_array*) pthread_getspecific(emutls_pthread_key); -} - -#else +#else /* _WIN32 */  #include <windows.h>  #include <malloc.h> @@ -222,11 +250,11 @@ static __inline void __atomic_store_n(void *ptr, uintptr_t val, unsigned type) {      InterlockedExchangePointer((void *volatile *)ptr, (void *)val);  } -#endif +#endif /* __ATOMIC_RELEASE */  #pragma warning (pop) -#endif +#endif /* _WIN32 */  static size_t emutls_num_object = 0;  /* number of allocated TLS objects */ @@ -314,11 +342,12 @@ static __inline void emutls_check_array_set_size(emutls_address_array *array,   * which must be no smaller than the given index.   */  static __inline uintptr_t emutls_new_data_array_size(uintptr_t index) { -   /* Need to allocate emutls_address_array with one extra slot -    * to store the data array size. +   /* Need to allocate emutls_address_array with extra slots +    * to store the header.      * Round up the emutls_address_array size to multiple of 16.      */ -    return ((index + 1 + 15) & ~((uintptr_t)15)) - 1; +    uintptr_t header_words = sizeof(emutls_address_array) / sizeof(void *); +    return ((index + header_words + 15) & ~((uintptr_t)15)) - header_words;  }  /* Returns the size in bytes required for an emutls_address_array with @@ -337,8 +366,10 @@ emutls_get_address_array(uintptr_t index) {      if (array == NULL) {          uintptr_t new_size = emutls_new_data_array_size(index);          array = (emutls_address_array*) malloc(emutls_asize(new_size)); -        if (array) +        if (array) {              memset(array->data, 0, new_size * sizeof(void*)); +            array->skip_destructor_rounds = EMUTLS_SKIP_DESTRUCTOR_ROUNDS; +        }          emutls_check_array_set_size(array, new_size);      } else if (index > array->size) {          uintptr_t orig_size = array->size; diff --git a/lib/builtins/hexagon/common_entry_exit_abi1.S b/lib/builtins/hexagon/common_entry_exit_abi1.S new file mode 100644 index 0000000000000..d5479d2a52fa4 --- /dev/null +++ b/lib/builtins/hexagon/common_entry_exit_abi1.S @@ -0,0 +1,103 @@ +//===----------------------Hexagon builtin routine ------------------------===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +/* Functions that implement common sequences in function prologues and epilogues +   used to save code size */ + +	.macro FUNCTION_BEGIN name +	.text +	.globl \name +	.type  \name, @function +	.falign +\name: +	.endm + +	.macro FUNCTION_END name +	.size  \name, . - \name +	.endm + +	.macro FALLTHROUGH_TAIL_CALL name0 name1 +	.size \name0, . - \name0 +	.globl \name1 +	.type \name1, @function +	.falign +\name1: +	.endm + + + + +/* Save r25:24 at fp+#-8 and r27:26 at fp+#-16. */ + + + + +/* The compiler knows that the __save_* functions clobber LR.  No other +   registers should be used without informing the compiler. */ + +/* Since we can only issue one store per packet, we don't hurt performance by +   simply jumping to the right point in this sequence of stores. */ + +FUNCTION_BEGIN __save_r24_through_r27 +		memd(fp+#-16) = r27:26 +FALLTHROUGH_TAIL_CALL __save_r24_through_r27 __save_r24_through_r25 +	{ +		memd(fp+#-8) = r25:24 +		jumpr lr +	} +FUNCTION_END __save_r24_through_r25 + + + + +/* For each of the *_before_tailcall functions, jumpr lr is executed in parallel +   with deallocframe.  That way, the return gets the old value of lr, which is +   where these functions need to return, and at the same time, lr gets the value +   it needs going into the tail call. */ + +FUNCTION_BEGIN __restore_r24_through_r27_and_deallocframe_before_tailcall +		r27:26 = memd(fp+#-16) +FALLTHROUGH_TAIL_CALL __restore_r24_through_r27_and_deallocframe_before_tailcall __restore_r24_through_r25_and_deallocframe_before_tailcall +	{ +		r25:24 = memd(fp+#-8) +		deallocframe +		jumpr lr +	} +FUNCTION_END __restore_r24_through_r25_and_deallocframe_before_tailcall + + + + +/* Here we use the extra load bandwidth to restore LR early, allowing the return +   to occur in parallel with the deallocframe. */ + +FUNCTION_BEGIN __restore_r24_through_r27_and_deallocframe +	{ +		lr = memw(fp+#4) +		r27:26 = memd(fp+#-16) +	} +	{ +		r25:24 = memd(fp+#-8) +		deallocframe +		jumpr lr +	} +FUNCTION_END __restore_r24_through_r27_and_deallocframe + + + + +/* Here the load bandwidth is maximized. */ + +FUNCTION_BEGIN __restore_r24_through_r25_and_deallocframe +	{ +		r25:24 = memd(fp+#-8) +		deallocframe +	} +		jumpr lr +FUNCTION_END __restore_r24_through_r25_and_deallocframe diff --git a/lib/builtins/hexagon/common_entry_exit_abi2.S b/lib/builtins/hexagon/common_entry_exit_abi2.S new file mode 100644 index 0000000000000..6f470343db498 --- /dev/null +++ b/lib/builtins/hexagon/common_entry_exit_abi2.S @@ -0,0 +1,268 @@ +//===----------------------Hexagon builtin routine ------------------------===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +/* Functions that implement common sequences in function prologues and epilogues +   used to save code size */ + +	.macro FUNCTION_BEGIN name +	.p2align 2 +        .section .text.\name,"ax",@progbits +	.globl \name +	.type  \name, @function +\name: +	.endm + +	.macro FUNCTION_END name +	.size  \name, . - \name +	.endm + +	.macro FALLTHROUGH_TAIL_CALL name0 name1 +	.p2align 2 +	.size \name0, . - \name0 +	.globl \name1 +	.type \name1, @function +\name1: +	.endm + + + + +/* Save r17:16 at fp+#-8, r19:18 at fp+#-16, r21:20 at fp+#-24, r23:22 at +   fp+#-32, r25:24 at fp+#-40, and r27:26 at fp+#-48. +   The compiler knows that the __save_* functions clobber LR.  No other +   registers should be used without informing the compiler. */ + +FUNCTION_BEGIN __save_r16_through_r27 +        { +                memd(fp+#-48) = r27:26 +                memd(fp+#-40) = r25:24 +        } +        { +                memd(fp+#-32) = r23:22 +                memd(fp+#-24) = r21:20 +        } +        { +                memd(fp+#-16) = r19:18 +                memd(fp+#-8) = r17:16 +                jumpr lr +        } +FUNCTION_END __save_r16_through_r27 + +FUNCTION_BEGIN __save_r16_through_r25 +        { +                memd(fp+#-40) = r25:24 +                memd(fp+#-32) = r23:22 +        } +        { +                memd(fp+#-24) = r21:20 +                memd(fp+#-16) = r19:18 +        } +        { +                memd(fp+#-8) = r17:16 +                jumpr lr +        } +FUNCTION_END __save_r16_through_r25 + +FUNCTION_BEGIN __save_r16_through_r23 +        { +                memd(fp+#-32) = r23:22 +                memd(fp+#-24) = r21:20 +        } +        { +                memd(fp+#-16) = r19:18 +                memd(fp+#-8) = r17:16 +                jumpr lr +        } +FUNCTION_END __save_r16_through_r23 + +FUNCTION_BEGIN __save_r16_through_r21 +        { +                memd(fp+#-24) = r21:20 +                memd(fp+#-16) = r19:18 +        } +        { +                memd(fp+#-8) = r17:16 +                jumpr lr +        } +FUNCTION_END __save_r16_through_r21 + +FUNCTION_BEGIN __save_r16_through_r19 +        { +                memd(fp+#-16) = r19:18 +                memd(fp+#-8) = r17:16 +                jumpr lr +        } +FUNCTION_END __save_r16_through_r19 + +FUNCTION_BEGIN __save_r16_through_r17 +        { +                memd(fp+#-8) = r17:16 +                jumpr lr +        } +FUNCTION_END __save_r16_through_r17 + +/* For each of the *_before_tailcall functions, jumpr lr is executed in parallel +   with deallocframe.  That way, the return gets the old value of lr, which is +   where these functions need to return, and at the same time, lr gets the value +   it needs going into the tail call. */ + + +FUNCTION_BEGIN __restore_r16_through_r27_and_deallocframe_before_tailcall +                r27:26 = memd(fp+#-48) +        { +                r25:24 = memd(fp+#-40) +                r23:22 = memd(fp+#-32) +        } +        { +                r21:20 = memd(fp+#-24) +                r19:18 = memd(fp+#-16) +        } +        { +                r17:16 = memd(fp+#-8) +                deallocframe +                jumpr lr +        } +FUNCTION_END __restore_r16_through_r27_and_deallocframe_before_tailcall + +FUNCTION_BEGIN __restore_r16_through_r25_and_deallocframe_before_tailcall +        { +                r25:24 = memd(fp+#-40) +                r23:22 = memd(fp+#-32) +        } +        { +                r21:20 = memd(fp+#-24) +                r19:18 = memd(fp+#-16) +        } +        { +                r17:16 = memd(fp+#-8) +                deallocframe +                jumpr lr +        } +FUNCTION_END __restore_r16_through_r25_and_deallocframe_before_tailcall + +FUNCTION_BEGIN __restore_r16_through_r23_and_deallocframe_before_tailcall +        { +                r23:22 = memd(fp+#-32) +                r21:20 = memd(fp+#-24) +        } +                r19:18 = memd(fp+#-16) +        { +                r17:16 = memd(fp+#-8) +                deallocframe +                jumpr lr +        } +FUNCTION_END __restore_r16_through_r23_and_deallocframe_before_tailcall + + +FUNCTION_BEGIN __restore_r16_through_r21_and_deallocframe_before_tailcall +        { +                r21:20 = memd(fp+#-24) +                r19:18 = memd(fp+#-16) +        } +        { +                r17:16 = memd(fp+#-8) +                deallocframe +                jumpr lr +        } +FUNCTION_END __restore_r16_through_r19_and_deallocframe_before_tailcall + +FUNCTION_BEGIN __restore_r16_through_r19_and_deallocframe_before_tailcall +                r19:18 = memd(fp+#-16) +        { +                r17:16 = memd(fp+#-8) +                deallocframe +                jumpr lr +        } +FUNCTION_END __restore_r16_through_r19_and_deallocframe_before_tailcall + +FUNCTION_BEGIN __restore_r16_through_r17_and_deallocframe_before_tailcall +        { +                r17:16 = memd(fp+#-8) +                deallocframe +                jumpr lr +        } +FUNCTION_END __restore_r16_through_r17_and_deallocframe_before_tailcall + + +FUNCTION_BEGIN __restore_r16_through_r27_and_deallocframe +                r27:26 = memd(fp+#-48) +        { +                r25:24 = memd(fp+#-40) +                r23:22 = memd(fp+#-32) +        } +        { +                r21:20 = memd(fp+#-24) +                r19:18 = memd(fp+#-16) +        } +	{ +		r17:16 = memd(fp+#-8) +		dealloc_return +	} +FUNCTION_END __restore_r16_through_r27_and_deallocframe + +FUNCTION_BEGIN __restore_r16_through_r25_and_deallocframe +        { +                r25:24 = memd(fp+#-40) +                r23:22 = memd(fp+#-32) +        } +        { +                r21:20 = memd(fp+#-24) +                r19:18 = memd(fp+#-16) +        } +	{ +		r17:16 = memd(fp+#-8) +		dealloc_return +	} +FUNCTION_END __restore_r16_through_r25_and_deallocframe + +FUNCTION_BEGIN __restore_r16_through_r23_and_deallocframe +        { +                r23:22 = memd(fp+#-32) +        } +        { +                r21:20 = memd(fp+#-24) +                r19:18 = memd(fp+#-16) +        } +	{ +		r17:16 = memd(fp+#-8) +		dealloc_return +	} +FUNCTION_END __restore_r16_through_r23_and_deallocframe + +FUNCTION_BEGIN __restore_r16_through_r21_and_deallocframe +        { +                r21:20 = memd(fp+#-24) +                r19:18 = memd(fp+#-16) +        } +	{ +		r17:16 = memd(fp+#-8) +		dealloc_return +	} +FUNCTION_END __restore_r16_through_r21_and_deallocframe + +FUNCTION_BEGIN __restore_r16_through_r19_and_deallocframe +	{ +                r19:18 = memd(fp+#-16) +		r17:16 = memd(fp+#-8) +        } +        { +		dealloc_return +	} +FUNCTION_END __restore_r16_through_r19_and_deallocframe + +FUNCTION_BEGIN __restore_r16_through_r17_and_deallocframe +	{ +		r17:16 = memd(fp+#-8) +		dealloc_return +	} +FUNCTION_END __restore_r16_through_r17_and_deallocframe + +FUNCTION_BEGIN __deallocframe +        dealloc_return +FUNCTION_END __deallocframe diff --git a/lib/builtins/hexagon/common_entry_exit_legacy.S b/lib/builtins/hexagon/common_entry_exit_legacy.S new file mode 100644 index 0000000000000..3258f15a32677 --- /dev/null +++ b/lib/builtins/hexagon/common_entry_exit_legacy.S @@ -0,0 +1,157 @@ +//===----------------------Hexagon builtin routine ------------------------===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + + +/* Functions that implement common sequences in function prologues and epilogues +   used to save code size */ + +	.macro FUNCTION_BEGIN name +	.text +	.globl \name +	.type  \name, @function +	.falign +\name: +	.endm + +	.macro FUNCTION_END name +	.size  \name, . - \name +	.endm + +	.macro FALLTHROUGH_TAIL_CALL name0 name1 +	.size \name0, . - \name0 +	.globl \name1 +	.type \name1, @function +	.falign +\name1: +	.endm + + + + +/* Save r27:26 at fp+#-8, r25:24 at fp+#-16, r23:22 at fp+#-24, r21:20 at +   fp+#-32, r19:18 at fp+#-40, and r17:16 at fp+#-48. */ + + + + +/* The compiler knows that the __save_* functions clobber LR.  No other +   registers should be used without informing the compiler. */ + +/* Since we can only issue one store per packet, we don't hurt performance by +   simply jumping to the right point in this sequence of stores. */ + +FUNCTION_BEGIN __save_r27_through_r16 +		memd(fp+#-48) = r17:16 +FALLTHROUGH_TAIL_CALL __save_r27_through_r16 __save_r27_through_r18 +		memd(fp+#-40) = r19:18 +FALLTHROUGH_TAIL_CALL __save_r27_through_r18 __save_r27_through_r20 +		memd(fp+#-32) = r21:20 +FALLTHROUGH_TAIL_CALL __save_r27_through_r20 __save_r27_through_r22 +		memd(fp+#-24) = r23:22 +FALLTHROUGH_TAIL_CALL __save_r27_through_r22 __save_r27_through_r24 +		memd(fp+#-16) = r25:24 +	{ +		memd(fp+#-8) = r27:26 +		jumpr lr +	} +FUNCTION_END __save_r27_through_r24 + + + + +/* For each of the *_before_sibcall functions, jumpr lr is executed in parallel +   with deallocframe.  That way, the return gets the old value of lr, which is +   where these functions need to return, and at the same time, lr gets the value +   it needs going into the sibcall. */ + +FUNCTION_BEGIN __restore_r27_through_r20_and_deallocframe_before_sibcall +	{ +		r21:20 = memd(fp+#-32) +		r23:22 = memd(fp+#-24) +	} +FALLTHROUGH_TAIL_CALL __restore_r27_through_r20_and_deallocframe_before_sibcall __restore_r27_through_r24_and_deallocframe_before_sibcall +	{ +		r25:24 = memd(fp+#-16) +		jump __restore_r27_through_r26_and_deallocframe_before_sibcall +	} +FUNCTION_END __restore_r27_through_r24_and_deallocframe_before_sibcall + + + + +FUNCTION_BEGIN __restore_r27_through_r16_and_deallocframe_before_sibcall +		r17:16 = memd(fp+#-48) +FALLTHROUGH_TAIL_CALL __restore_r27_through_r16_and_deallocframe_before_sibcall __restore_r27_through_r18_and_deallocframe_before_sibcall +	{ +		r19:18 = memd(fp+#-40) +		r21:20 = memd(fp+#-32) +	} +FALLTHROUGH_TAIL_CALL __restore_r27_through_r18_and_deallocframe_before_sibcall __restore_r27_through_r22_and_deallocframe_before_sibcall +	{ +		r23:22 = memd(fp+#-24) +		r25:24 = memd(fp+#-16) +	} +FALLTHROUGH_TAIL_CALL __restore_r27_through_r22_and_deallocframe_before_sibcall __restore_r27_through_r26_and_deallocframe_before_sibcall +	{ +		r27:26 = memd(fp+#-8) +		deallocframe +		jumpr lr +	} +FUNCTION_END __restore_r27_through_r26_and_deallocframe_before_sibcall + + + + +/* Here we use the extra load bandwidth to restore LR early, allowing the return +   to occur in parallel with the deallocframe. */ + +FUNCTION_BEGIN __restore_r27_through_r16_and_deallocframe +	{ +		r17:16 = memd(fp+#-48) +		r19:18 = memd(fp+#-40) +	} +FALLTHROUGH_TAIL_CALL __restore_r27_through_r16_and_deallocframe __restore_r27_through_r20_and_deallocframe +	{ +		r21:20 = memd(fp+#-32) +		r23:22 = memd(fp+#-24) +	} +FALLTHROUGH_TAIL_CALL __restore_r27_through_r20_and_deallocframe __restore_r27_through_r24_and_deallocframe +	{ +		lr = memw(fp+#4) +		r25:24 = memd(fp+#-16) +	} +	{ +		r27:26 = memd(fp+#-8) +		deallocframe +		jumpr lr +	} +FUNCTION_END __restore_r27_through_r24_and_deallocframe + + + + +/* Here the load bandwidth is maximized for all three functions. */ + +FUNCTION_BEGIN __restore_r27_through_r18_and_deallocframe +	{ +		r19:18 = memd(fp+#-40) +		r21:20 = memd(fp+#-32) +	} +FALLTHROUGH_TAIL_CALL __restore_r27_through_r18_and_deallocframe __restore_r27_through_r22_and_deallocframe +	{ +		r23:22 = memd(fp+#-24) +		r25:24 = memd(fp+#-16) +	} +FALLTHROUGH_TAIL_CALL __restore_r27_through_r22_and_deallocframe __restore_r27_through_r26_and_deallocframe +	{ +		r27:26 = memd(fp+#-8) +		deallocframe +	} +		jumpr lr +FUNCTION_END __restore_r27_through_r26_and_deallocframe diff --git a/lib/builtins/hexagon/dfaddsub.S b/lib/builtins/hexagon/dfaddsub.S new file mode 100644 index 0000000000000..4173f86a4f548 --- /dev/null +++ b/lib/builtins/hexagon/dfaddsub.S @@ -0,0 +1,398 @@ +//===----------------------Hexagon builtin routine ------------------------===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +/* Double Precision Multiply */ + +#define A r1:0 +#define AH r1 +#define AL r0 +#define B r3:2 +#define BH r3 +#define BL r2 + +#define EXPA r4 +#define EXPB r5 +#define EXPB_A r5:4 + +#define ZTMP r7:6 +#define ZTMPH r7 +#define ZTMPL r6 + +#define ATMP r13:12 +#define ATMPH r13 +#define ATMPL r12 + +#define BTMP r9:8 +#define BTMPH r9 +#define BTMPL r8 + +#define ATMP2 r11:10 +#define ATMP2H r11 +#define ATMP2L r10 + +#define EXPDIFF r15 +#define EXTRACTOFF r14 +#define EXTRACTAMT r15:14 + +#define TMP r28 + +#define MANTBITS 52 +#define HI_MANTBITS 20 +#define EXPBITS 11 +#define BIAS 1024 +#define MANTISSA_TO_INT_BIAS 52 +#define SR_BIT_INEXACT 5 + +#ifndef SR_ROUND_OFF +#define SR_ROUND_OFF 22 +#endif + +#define NORMAL p3 +#define BIGB p2 + +#define Q6_ALIAS(TAG) .global __qdsp_##TAG ; .set __qdsp_##TAG, __hexagon_##TAG +#define FAST_ALIAS(TAG) .global __hexagon_fast_##TAG ; .set __hexagon_fast_##TAG, __hexagon_##TAG +#define FAST2_ALIAS(TAG) .global __hexagon_fast2_##TAG ; .set __hexagon_fast2_##TAG, __hexagon_##TAG +#define END(TAG) .size TAG,.-TAG + +	.text +	.global __hexagon_adddf3 +	.global __hexagon_subdf3 +	.type __hexagon_adddf3, @function +	.type __hexagon_subdf3, @function + +Q6_ALIAS(adddf3) +FAST_ALIAS(adddf3) +FAST2_ALIAS(adddf3) +Q6_ALIAS(subdf3) +FAST_ALIAS(subdf3) +FAST2_ALIAS(subdf3) + +	.p2align 5 +__hexagon_adddf3: +	{ +		EXPA = extractu(AH,#EXPBITS,#HI_MANTBITS) +		EXPB = extractu(BH,#EXPBITS,#HI_MANTBITS) +		ATMP = combine(##0x20000000,#0) +	} +	{ +		NORMAL = dfclass(A,#2) +		NORMAL = dfclass(B,#2) +		BTMP = ATMP +		BIGB = cmp.gtu(EXPB,EXPA)			// Is B substantially greater than A? +	} +	{ +		if (!NORMAL) jump .Ladd_abnormal		// If abnormal, go to special code +		if (BIGB) A = B				// if B >> A, swap A and B +		if (BIGB) B = A				// If B >> A, swap A and B +		if (BIGB) EXPB_A = combine(EXPA,EXPB)	// swap exponents +	} +	{ +		ATMP = insert(A,#MANTBITS,#EXPBITS-2)	// Q1.62 +		BTMP = insert(B,#MANTBITS,#EXPBITS-2)	// Q1.62 +		EXPDIFF = sub(EXPA,EXPB) +		ZTMP = combine(#62,#1) +	} +#undef BIGB +#undef NORMAL +#define B_POS p3 +#define A_POS p2 +#define NO_STICKIES p1 +.Ladd_continue: +	{ +		EXPDIFF = min(EXPDIFF,ZTMPH)		// If exponent difference >= ~60, +							// will collapse to sticky bit +		ATMP2 = neg(ATMP) +		A_POS = cmp.gt(AH,#-1) +		EXTRACTOFF = #0 +	} +	{ +		if (!A_POS) ATMP = ATMP2 +		ATMP2 = extractu(BTMP,EXTRACTAMT) +		BTMP = ASR(BTMP,EXPDIFF) +#undef EXTRACTAMT +#undef EXPDIFF +#undef EXTRACTOFF +#define ZERO r15:14 +		ZERO = #0 +	} +	{ +		NO_STICKIES = cmp.eq(ATMP2,ZERO) +		if (!NO_STICKIES.new) BTMPL = or(BTMPL,ZTMPL) +		EXPB = add(EXPA,#-BIAS-60) +		B_POS = cmp.gt(BH,#-1) +	} +	{ +		ATMP = add(ATMP,BTMP)			// ADD!!! +		ATMP2 = sub(ATMP,BTMP)			// Negate and ADD --> SUB!!! +		ZTMP = combine(#54,##2045) +	} +	{ +		p0 = cmp.gtu(EXPA,ZTMPH)		// must be pretty high in case of large cancellation +		p0 = !cmp.gtu(EXPA,ZTMPL) +		if (!p0.new) jump:nt .Ladd_ovf_unf +		if (!B_POS) ATMP = ATMP2		// if B neg, pick difference +	} +	{ +		A = convert_d2df(ATMP)			// Convert to Double Precision, taking care of flags, etc.  So nice! +		p0 = cmp.eq(ATMPH,#0) +		p0 = cmp.eq(ATMPL,#0) +		if (p0.new) jump:nt .Ladd_zero		// or maybe conversion handles zero case correctly? +	} +	{ +		AH += asl(EXPB,#HI_MANTBITS) +		jumpr r31 +	} +	.falign +__hexagon_subdf3: +	{ +		BH = togglebit(BH,#31) +		jump __qdsp_adddf3 +	} + + +	.falign +.Ladd_zero: +	// True zero, full cancellation +	// +0 unless round towards negative infinity +	{ +		TMP = USR +		A = #0 +		BH = #1 +	} +	{ +		TMP = extractu(TMP,#2,#22) +		BH = asl(BH,#31) +	} +	{ +		p0 = cmp.eq(TMP,#2) +		if (p0.new) AH = xor(AH,BH) +		jumpr r31 +	} +	.falign +.Ladd_ovf_unf: +	// Overflow or Denormal is possible +	// Good news: Underflow flag is not possible! +	/* +	 * ATMP has 2's complement value +	 * +	 * EXPA has A's exponent, EXPB has EXPA-BIAS-60 +	 * +	 * Convert, extract exponent, add adjustment. +	 * If > 2046, overflow +	 * If <= 0, denormal +	 * +	 * Note that we've not done our zero check yet, so do that too +	 * +	 */ +	{ +		A = convert_d2df(ATMP) +		p0 = cmp.eq(ATMPH,#0) +		p0 = cmp.eq(ATMPL,#0) +		if (p0.new) jump:nt .Ladd_zero +	} +	{ +		TMP = extractu(AH,#EXPBITS,#HI_MANTBITS) +		AH += asl(EXPB,#HI_MANTBITS) +	} +	{ +		EXPB = add(EXPB,TMP) +		B = combine(##0x00100000,#0) +	} +	{ +		p0 = cmp.gt(EXPB,##BIAS+BIAS-2) +		if (p0.new) jump:nt .Ladd_ovf +	} +	{ +		p0 = cmp.gt(EXPB,#0) +		if (p0.new) jumpr:t r31 +		TMP = sub(#1,EXPB) +	} +	{ +		B = insert(A,#MANTBITS,#0) +		A = ATMP +	} +	{ +		B = lsr(B,TMP) +	} +	{ +		A = insert(B,#63,#0) +		jumpr r31 +	} +	.falign +.Ladd_ovf: +	// We get either max finite value or infinity.  Either way, overflow+inexact +	{ +		A = ATMP				// 2's complement value +		TMP = USR +		ATMP = combine(##0x7fefffff,#-1)	// positive max finite +	} +	{ +		EXPB = extractu(TMP,#2,#SR_ROUND_OFF)	// rounding bits +		TMP = or(TMP,#0x28)			// inexact + overflow +		BTMP = combine(##0x7ff00000,#0)		// positive infinity +	} +	{ +		USR = TMP +		EXPB ^= lsr(AH,#31)			// Does sign match rounding? +		TMP = EXPB				// unmodified rounding mode +	} +	{ +		p0 = !cmp.eq(TMP,#1)			// If not round-to-zero and +		p0 = !cmp.eq(EXPB,#2)			// Not rounding the other way, +		if (p0.new) ATMP = BTMP			// we should get infinity +	} +	{ +		A = insert(ATMP,#63,#0)			// insert inf/maxfinite, leave sign +	} +	{ +		p0 = dfcmp.eq(A,A) +		jumpr r31 +	} + +.Ladd_abnormal: +	{ +		ATMP = extractu(A,#63,#0)		// strip off sign +		BTMP = extractu(B,#63,#0)		// strip off sign +	} +	{ +		p3 = cmp.gtu(ATMP,BTMP) +		if (!p3.new) A = B			// sort values +		if (!p3.new) B = A			// sort values +	} +	{ +		// Any NaN --> NaN, possibly raise invalid if sNaN +		p0 = dfclass(A,#0x0f)		// A not NaN? +		if (!p0.new) jump:nt .Linvalid_nan_add +		if (!p3) ATMP = BTMP +		if (!p3) BTMP = ATMP +	} +	{ +		// Infinity + non-infinity number is infinity +		// Infinity + infinity --> inf or nan +		p1 = dfclass(A,#0x08)		// A is infinity +		if (p1.new) jump:nt .Linf_add +	} +	{ +		p2 = dfclass(B,#0x01)		// B is zero +		if (p2.new) jump:nt .LB_zero	// so return A or special 0+0 +		ATMP = #0 +	} +	// We are left with adding one or more subnormals +	{ +		p0 = dfclass(A,#4) +		if (p0.new) jump:nt .Ladd_two_subnormal +		ATMP = combine(##0x20000000,#0) +	} +	{ +		EXPA = extractu(AH,#EXPBITS,#HI_MANTBITS) +		EXPB = #1 +		// BTMP already ABS(B) +		BTMP = asl(BTMP,#EXPBITS-2) +	} +#undef ZERO +#define EXTRACTOFF r14 +#define EXPDIFF r15 +	{ +		ATMP = insert(A,#MANTBITS,#EXPBITS-2) +		EXPDIFF = sub(EXPA,EXPB) +		ZTMP = combine(#62,#1) +		jump .Ladd_continue +	} + +.Ladd_two_subnormal: +	{ +		ATMP = extractu(A,#63,#0) +		BTMP = extractu(B,#63,#0) +	} +	{ +		ATMP = neg(ATMP) +		BTMP = neg(BTMP) +		p0 = cmp.gt(AH,#-1) +		p1 = cmp.gt(BH,#-1) +	} +	{ +		if (p0) ATMP = A +		if (p1) BTMP = B +	} +	{ +		ATMP = add(ATMP,BTMP) +	} +	{ +		BTMP = neg(ATMP) +		p0 = cmp.gt(ATMPH,#-1) +		B = #0 +	} +	{ +		if (!p0) A = BTMP +		if (p0) A = ATMP +		BH = ##0x80000000 +	} +	{ +		if (!p0) AH = or(AH,BH) +		p0 = dfcmp.eq(A,B) +		if (p0.new) jump:nt .Lzero_plus_zero +	} +	{ +		jumpr r31 +	} + +.Linvalid_nan_add: +	{ +		TMP = convert_df2sf(A)			// will generate invalid if sNaN +		p0 = dfclass(B,#0x0f)			// if B is not NaN +		if (p0.new) B = A 			// make it whatever A is +	} +	{ +		BL = convert_df2sf(B)			// will generate invalid if sNaN +		A = #-1 +		jumpr r31 +	} +	.falign +.LB_zero: +	{ +		p0 = dfcmp.eq(ATMP,A)			// is A also zero? +		if (!p0.new) jumpr:t r31		// If not, just return A +	} +	// 0 + 0 is special +	// if equal integral values, they have the same sign, which is fine for all rounding +	// modes. +	// If unequal in sign, we get +0 for all rounding modes except round down +.Lzero_plus_zero: +	{ +		p0 = cmp.eq(A,B) +		if (p0.new) jumpr:t r31 +	} +	{ +		TMP = USR +	} +	{ +		TMP = extractu(TMP,#2,#SR_ROUND_OFF) +		A = #0 +	} +	{ +		p0 = cmp.eq(TMP,#2) +		if (p0.new) AH = ##0x80000000 +		jumpr r31 +	} +.Linf_add: +	// adding infinities is only OK if they are equal +	{ +		p0 = !cmp.eq(AH,BH)			// Do they have different signs +		p0 = dfclass(B,#8)			// And is B also infinite? +		if (!p0.new) jumpr:t r31		// If not, just a normal inf +	} +	{ +		BL = ##0x7f800001			// sNAN +	} +	{ +		A = convert_sf2df(BL)			// trigger invalid, set NaN +		jumpr r31 +	} +END(__hexagon_adddf3) diff --git a/lib/builtins/hexagon/dfdiv.S b/lib/builtins/hexagon/dfdiv.S new file mode 100644 index 0000000000000..0c5dbe272c89a --- /dev/null +++ b/lib/builtins/hexagon/dfdiv.S @@ -0,0 +1,492 @@ +//===----------------------Hexagon builtin routine ------------------------===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +/* Double Precision Divide */ + +#define A r1:0 +#define AH r1 +#define AL r0 + +#define B r3:2 +#define BH r3 +#define BL r2 + +#define Q r5:4 +#define QH r5 +#define QL r4 + +#define PROD r7:6 +#define PRODHI r7 +#define PRODLO r6 + +#define SFONE r8 +#define SFDEN r9 +#define SFERROR r10 +#define SFRECIP r11 + +#define EXPBA r13:12 +#define EXPB r13 +#define EXPA r12 + +#define REMSUB2 r15:14 + + + +#define SIGN r28 + +#define Q_POSITIVE p3 +#define NORMAL p2 +#define NO_OVF_UNF p1 +#define P_TMP p0 + +#define RECIPEST_SHIFT 3 +#define QADJ 61 + +#define DFCLASS_NORMAL 0x02 +#define DFCLASS_NUMBER 0x0F +#define DFCLASS_INFINITE 0x08 +#define DFCLASS_ZERO 0x01 +#define DFCLASS_NONZERO (DFCLASS_NUMBER ^ DFCLASS_ZERO) +#define DFCLASS_NONINFINITE (DFCLASS_NUMBER ^ DFCLASS_INFINITE) + +#define DF_MANTBITS 52 +#define DF_EXPBITS 11 +#define SF_MANTBITS 23 +#define SF_EXPBITS 8 +#define DF_BIAS 0x3ff + +#define SR_ROUND_OFF 22 + +#define Q6_ALIAS(TAG) .global __qdsp_##TAG ; .set __qdsp_##TAG, __hexagon_##TAG +#define FAST_ALIAS(TAG) .global __hexagon_fast_##TAG ; .set __hexagon_fast_##TAG, __hexagon_##TAG +#define FAST2_ALIAS(TAG) .global __hexagon_fast2_##TAG ; .set __hexagon_fast2_##TAG, __hexagon_##TAG +#define END(TAG) .size TAG,.-TAG + +	.text +	.global __hexagon_divdf3 +	.type __hexagon_divdf3,@function +	Q6_ALIAS(divdf3) +        FAST_ALIAS(divdf3) +        FAST2_ALIAS(divdf3) +	.p2align 5 +__hexagon_divdf3: +	{ +		NORMAL = dfclass(A,#DFCLASS_NORMAL) +		NORMAL = dfclass(B,#DFCLASS_NORMAL) +		EXPBA = combine(BH,AH) +		SIGN = xor(AH,BH) +	} +#undef A +#undef AH +#undef AL +#undef B +#undef BH +#undef BL +#define REM r1:0 +#define REMHI r1 +#define REMLO r0 +#define DENOM r3:2 +#define DENOMHI r3 +#define DENOMLO r2 +	{ +		if (!NORMAL) jump .Ldiv_abnormal +		PROD = extractu(DENOM,#SF_MANTBITS,#DF_MANTBITS-SF_MANTBITS) +		SFONE = ##0x3f800001 +	} +	{ +		SFDEN = or(SFONE,PRODLO) +		EXPB = extractu(EXPB,#DF_EXPBITS,#DF_MANTBITS-32) +		EXPA = extractu(EXPA,#DF_EXPBITS,#DF_MANTBITS-32) +		Q_POSITIVE = cmp.gt(SIGN,#-1) +	} +#undef SIGN +#define ONE r28 +.Ldenorm_continue: +	{ +		SFRECIP,P_TMP = sfrecipa(SFONE,SFDEN) +		SFERROR = and(SFONE,#-2) +		ONE = #1 +		EXPA = sub(EXPA,EXPB) +	} +#undef EXPB +#define RECIPEST r13 +	{ +		SFERROR -= sfmpy(SFRECIP,SFDEN):lib +		REMHI = insert(ONE,#DF_EXPBITS+1,#DF_MANTBITS-32) +		RECIPEST = ##0x00800000 << RECIPEST_SHIFT +	} +	{ +		SFRECIP += sfmpy(SFRECIP,SFERROR):lib +		DENOMHI = insert(ONE,#DF_EXPBITS+1,#DF_MANTBITS-32) +		SFERROR = and(SFONE,#-2) +	} +	{ +		SFERROR -= sfmpy(SFRECIP,SFDEN):lib +		QH = #-DF_BIAS+1 +		QL = #DF_BIAS-1 +	} +	{ +		SFRECIP += sfmpy(SFRECIP,SFERROR):lib +		NO_OVF_UNF = cmp.gt(EXPA,QH) +		NO_OVF_UNF = !cmp.gt(EXPA,QL) +	} +	{ +		RECIPEST = insert(SFRECIP,#SF_MANTBITS,#RECIPEST_SHIFT) +		Q = #0 +		EXPA = add(EXPA,#-QADJ) +	} +#undef SFERROR +#undef SFRECIP +#define TMP r10 +#define TMP1 r11 +	{ +		RECIPEST = add(RECIPEST,#((-3) << RECIPEST_SHIFT)) +	} + +#define DIV_ITER1B(QSHIFTINSN,QSHIFT,REMSHIFT,EXTRA) \ +	{ \ +		PROD = mpyu(RECIPEST,REMHI); \ +		REM = asl(REM,# ## ( REMSHIFT )); \ +	}; \ +	{ \ +		PRODLO = # ## 0; \ +		REM -= mpyu(PRODHI,DENOMLO); \ +		REMSUB2 = mpyu(PRODHI,DENOMHI); \ +	}; \ +	{ \ +		Q += QSHIFTINSN(PROD, # ## ( QSHIFT )); \ +		REM -= asl(REMSUB2, # ## 32); \ +		EXTRA \ +	} + + +	DIV_ITER1B(ASL,14,15,) +	DIV_ITER1B(ASR,1,15,) +	DIV_ITER1B(ASR,16,15,) +	DIV_ITER1B(ASR,31,15,PROD=# ( 0 );) + +#undef REMSUB2 +#define TMPPAIR r15:14 +#define TMPPAIRHI r15 +#define TMPPAIRLO r14 +#undef RECIPEST +#define EXPB r13 +	{ +		// compare or sub with carry +		TMPPAIR = sub(REM,DENOM) +		P_TMP = cmp.gtu(DENOM,REM) +		// set up amt to add to q +		if (!P_TMP.new) PRODLO  = #2 +	} +	{ +		Q = add(Q,PROD) +		if (!P_TMP) REM = TMPPAIR +		TMPPAIR = #0 +	} +	{ +		P_TMP = cmp.eq(REM,TMPPAIR) +		if (!P_TMP.new) QL = or(QL,ONE) +	} +	{ +		PROD = neg(Q) +	} +	{ +		if (!Q_POSITIVE) Q = PROD +	} +#undef REM +#undef REMHI +#undef REMLO +#undef DENOM +#undef DENOMLO +#undef DENOMHI +#define A r1:0 +#define AH r1 +#define AL r0 +#define B r3:2 +#define BH r3 +#define BL r2 +	{ +		A = convert_d2df(Q) +		if (!NO_OVF_UNF) jump .Ldiv_ovf_unf +	} +	{ +		AH += asl(EXPA,#DF_MANTBITS-32) +		jumpr r31 +	} + +.Ldiv_ovf_unf: +	{ +		AH += asl(EXPA,#DF_MANTBITS-32) +		EXPB = extractu(AH,#DF_EXPBITS,#DF_MANTBITS-32) +	} +	{ +		PROD = abs(Q) +		EXPA = add(EXPA,EXPB) +	} +	{ +		P_TMP = cmp.gt(EXPA,##DF_BIAS+DF_BIAS)		// overflow +		if (P_TMP.new) jump:nt .Ldiv_ovf +	} +	{ +		P_TMP = cmp.gt(EXPA,#0) +		if (P_TMP.new) jump:nt .Lpossible_unf		// round up to normal possible... +	} +	/* Underflow */ +	/* We know what the infinite range exponent should be (EXPA) */ +	/* Q is 2's complement, PROD is abs(Q) */ +	/* Normalize Q, shift right, add a high bit, convert, change exponent */ + +#define FUDGE1 7	// how much to shift right +#define FUDGE2 4	// how many guard/round to keep at lsbs + +	{ +		EXPB = add(clb(PROD),#-1)			// doesn't need to be added in since +		EXPA = sub(#FUDGE1,EXPA)			// we extract post-converted exponent +		TMP = USR +		TMP1 = #63 +	} +	{ +		EXPB = min(EXPA,TMP1) +		TMP1 = or(TMP,#0x030) +		PROD = asl(PROD,EXPB) +		EXPA = #0 +	} +	{ +		TMPPAIR = extractu(PROD,EXPBA)				// bits that will get shifted out +		PROD = lsr(PROD,EXPB)					// shift out bits +		B = #1 +	} +	{ +		P_TMP = cmp.gtu(B,TMPPAIR) +		if (!P_TMP.new) PRODLO = or(BL,PRODLO) +		PRODHI = setbit(PRODHI,#DF_MANTBITS-32+FUDGE2) +	} +	{ +		Q = neg(PROD) +		P_TMP = bitsclr(PRODLO,#(1<<FUDGE2)-1) +		if (!P_TMP.new) TMP = TMP1 +	} +	{ +		USR = TMP +		if (Q_POSITIVE) Q = PROD +		TMP = #-DF_BIAS-(DF_MANTBITS+FUDGE2) +	} +	{ +		A = convert_d2df(Q) +	} +	{ +		AH += asl(TMP,#DF_MANTBITS-32) +		jumpr r31 +	} + + +.Lpossible_unf: +	/* If upper parts of Q were all F's, but abs(A) == 0x00100000_00000000, we rounded up to min_normal */ +	/* The answer is correct, but we need to raise Underflow */ +	{ +		B = extractu(A,#63,#0) +		TMPPAIR = combine(##0x00100000,#0)		// min normal +		TMP = #0x7FFF +	} +	{ +		P_TMP = dfcmp.eq(TMPPAIR,B)		// Is everything zero in the rounded value... +		P_TMP = bitsset(PRODHI,TMP)		// but a bunch of bits set in the unrounded abs(quotient)? +	} + +#if (__HEXAGON_ARCH__ == 60) +		TMP = USR		// If not, just return +		if (!P_TMP) jumpr r31   // Else, we want to set Unf+Inexact +					// Note that inexact is already set... +#else +	{ +		if (!P_TMP) jumpr r31			// If not, just return +		TMP = USR				// Else, we want to set Unf+Inexact +	}						// Note that inexact is already set... +#endif +	{ +		TMP = or(TMP,#0x30) +	} +	{ +		USR = TMP +	} +	{ +		p0 = dfcmp.eq(A,A) +		jumpr r31 +	} + +.Ldiv_ovf: +	/* +	 * Raise Overflow, and choose the correct overflow value (saturated normal or infinity) +	 */ +	{ +		TMP = USR +		B = combine(##0x7fefffff,#-1) +		AH = mux(Q_POSITIVE,#0,#-1) +	} +	{ +		PROD = combine(##0x7ff00000,#0) +		QH = extractu(TMP,#2,#SR_ROUND_OFF) +		TMP = or(TMP,#0x28) +	} +	{ +		USR = TMP +		QH ^= lsr(AH,#31) +		QL = QH +	} +	{ +		p0 = !cmp.eq(QL,#1)		// if not round-to-zero +		p0 = !cmp.eq(QH,#2)		// and not rounding the other way +		if (p0.new) B = PROD		// go to inf +		p0 = dfcmp.eq(B,B)		// get exceptions +	} +	{ +		A = insert(B,#63,#0) +		jumpr r31 +	} + +#undef ONE +#define SIGN r28 +#undef NORMAL +#undef NO_OVF_UNF +#define P_INF p1 +#define P_ZERO p2 +.Ldiv_abnormal: +	{ +		P_TMP = dfclass(A,#DFCLASS_NUMBER) +		P_TMP = dfclass(B,#DFCLASS_NUMBER) +		Q_POSITIVE = cmp.gt(SIGN,#-1) +	} +	{ +		P_INF = dfclass(A,#DFCLASS_INFINITE) +		P_INF = dfclass(B,#DFCLASS_INFINITE) +	} +	{ +		P_ZERO = dfclass(A,#DFCLASS_ZERO) +		P_ZERO = dfclass(B,#DFCLASS_ZERO) +	} +	{ +		if (!P_TMP) jump .Ldiv_nan +		if (P_INF) jump .Ldiv_invalid +	} +	{ +		if (P_ZERO) jump .Ldiv_invalid +	} +	{ +		P_ZERO = dfclass(A,#DFCLASS_NONZERO)		// nonzero +		P_ZERO = dfclass(B,#DFCLASS_NONINFINITE)	// non-infinite +	} +	{ +		P_INF = dfclass(A,#DFCLASS_NONINFINITE)	// non-infinite +		P_INF = dfclass(B,#DFCLASS_NONZERO)	// nonzero +	} +	{ +		if (!P_ZERO) jump .Ldiv_zero_result +		if (!P_INF) jump .Ldiv_inf_result +	} +	/* Now we've narrowed it down to (de)normal / (de)normal */ +	/* Set up A/EXPA B/EXPB and go back */ +#undef P_ZERO +#undef P_INF +#define P_TMP2 p1 +	{ +		P_TMP = dfclass(A,#DFCLASS_NORMAL) +		P_TMP2 = dfclass(B,#DFCLASS_NORMAL) +		TMP = ##0x00100000 +	} +	{ +		EXPBA = combine(BH,AH) +		AH = insert(TMP,#DF_EXPBITS+1,#DF_MANTBITS-32)		// clear out hidden bit, sign bit +		BH = insert(TMP,#DF_EXPBITS+1,#DF_MANTBITS-32)		// clear out hidden bit, sign bit +	} +	{ +		if (P_TMP) AH = or(AH,TMP)				// if normal, add back in hidden bit +		if (P_TMP2) BH = or(BH,TMP)				// if normal, add back in hidden bit +	} +	{ +		QH = add(clb(A),#-DF_EXPBITS) +		QL = add(clb(B),#-DF_EXPBITS) +		TMP = #1 +	} +	{ +		EXPA = extractu(EXPA,#DF_EXPBITS,#DF_MANTBITS-32) +		EXPB = extractu(EXPB,#DF_EXPBITS,#DF_MANTBITS-32) +	} +	{ +		A = asl(A,QH) +		B = asl(B,QL) +		if (!P_TMP) EXPA = sub(TMP,QH) +		if (!P_TMP2) EXPB = sub(TMP,QL) +	}	// recreate values needed by resume coke +	{ +		PROD = extractu(B,#SF_MANTBITS,#DF_MANTBITS-SF_MANTBITS) +	} +	{ +		SFDEN = or(SFONE,PRODLO) +		jump .Ldenorm_continue +	} + +.Ldiv_zero_result: +	{ +		AH = xor(AH,BH) +		B = #0 +	} +	{ +		A = insert(B,#63,#0) +		jumpr r31 +	} +.Ldiv_inf_result: +	{ +		p2 = dfclass(B,#DFCLASS_ZERO) +		p2 = dfclass(A,#DFCLASS_NONINFINITE) +	} +	{ +		TMP = USR +		if (!p2) jump 1f +		AH = xor(AH,BH) +	} +	{ +		TMP = or(TMP,#0x04)		// DBZ +	} +	{ +		USR = TMP +	} +1: +	{ +		B = combine(##0x7ff00000,#0) +		p0 = dfcmp.uo(B,B)		// take possible exception +	} +	{ +		A = insert(B,#63,#0) +		jumpr r31 +	} +.Ldiv_nan: +	{ +		p0 = dfclass(A,#0x10) +		p1 = dfclass(B,#0x10) +		if (!p0.new) A = B +		if (!p1.new) B = A +	} +	{ +		QH = convert_df2sf(A)	// get possible invalid exceptions +		QL = convert_df2sf(B) +	} +	{ +		A = #-1 +		jumpr r31 +	} + +.Ldiv_invalid: +	{ +		TMP = ##0x7f800001 +	} +	{ +		A = convert_sf2df(TMP)		// get invalid, get DF qNaN +		jumpr r31 +	} +END(__hexagon_divdf3) diff --git a/lib/builtins/hexagon/dffma.S b/lib/builtins/hexagon/dffma.S new file mode 100644 index 0000000000000..97b885a3bf27f --- /dev/null +++ b/lib/builtins/hexagon/dffma.S @@ -0,0 +1,705 @@ +//===----------------------Hexagon builtin routine ------------------------===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#define Q6_ALIAS(TAG) .global __qdsp_##TAG ; .set __qdsp_##TAG, __hexagon_##TAG +#define END(TAG) .size TAG,.-TAG + +/* Double Precision Multiply */ + + +#define A r1:0 +#define AH r1 +#define AL r0 +#define B r3:2 +#define BH r3 +#define BL r2 +#define C r5:4 +#define CH r5 +#define CL r4 + + + +#define BTMP r15:14 +#define BTMPH r15 +#define BTMPL r14 + +#define ATMP r13:12 +#define ATMPH r13 +#define ATMPL r12 + +#define CTMP r11:10 +#define CTMPH r11 +#define CTMPL r10 + +#define PP_LL r9:8 +#define PP_LL_H r9 +#define PP_LL_L r8 + +#define PP_ODD r7:6 +#define PP_ODD_H r7 +#define PP_ODD_L r6 + + +#define PP_HH r17:16 +#define PP_HH_H r17 +#define PP_HH_L r16 + +#define EXPA r18 +#define EXPB r19 +#define EXPBA r19:18 + +#define TMP r28 + +#define P_TMP p0 +#define PROD_NEG p3 +#define EXACT p2 +#define SWAP p1 + +#define MANTBITS 52 +#define HI_MANTBITS 20 +#define EXPBITS 11 +#define BIAS 1023 +#define STACKSPACE 32 + +#define ADJUST 4 + +#define FUDGE 7 +#define FUDGE2 3 + +#ifndef SR_ROUND_OFF +#define SR_ROUND_OFF 22 +#endif + +	/* +	 * First, classify for normal values, and abort if abnormal +	 * +	 * Next, unpack mantissa into 0x1000_0000_0000_0000 + mant<<8 +	 * +	 * Since we know that the 2 MSBs of the H registers is zero, we should never carry +	 * the partial products that involve the H registers +	 * +	 * Try to buy X slots, at the expense of latency if needed +	 * +	 * We will have PP_HH with the upper bits of the product, PP_LL with the lower +	 * PP_HH can have a maximum of 0x03FF_FFFF_FFFF_FFFF or thereabouts +	 * PP_HH can have a minimum of 0x0100_0000_0000_0000 +	 * +	 * 0x0100_0000_0000_0000 has EXP of EXPA+EXPB-BIAS +	 * +	 * We need to align CTMP. +	 * If CTMP >> PP, convert PP to 64 bit with sticky, align CTMP, and follow normal add +	 * If CTMP << PP align CTMP and add 128 bits.  Then compute sticky +	 * If CTMP ~= PP, align CTMP and add 128 bits.  May have massive cancellation. +	 * +	 * Convert partial product and CTMP to 2's complement prior to addition +	 * +	 * After we add, we need to normalize into upper 64 bits, then compute sticky. +	 * +	 * +	 */ + +	.text +	.global __hexagon_fmadf4 +        .type __hexagon_fmadf4,@function +	.global __hexagon_fmadf5 +        .type __hexagon_fmadf5,@function +	.global fma +	.type fma,@function +	Q6_ALIAS(fmadf5) +	.p2align 5 +__hexagon_fmadf4: +__hexagon_fmadf5: +fma: +	{ +		P_TMP = dfclass(A,#2) +		P_TMP = dfclass(B,#2) +		ATMP = #0 +		BTMP = #0 +	} +	{ +		ATMP = insert(A,#MANTBITS,#EXPBITS-3) +		BTMP = insert(B,#MANTBITS,#EXPBITS-3) +		PP_ODD_H = ##0x10000000 +		allocframe(#STACKSPACE) +	} +	{ +		PP_LL = mpyu(ATMPL,BTMPL) +		if (!P_TMP) jump .Lfma_abnormal_ab +		ATMPH = or(ATMPH,PP_ODD_H) +		BTMPH = or(BTMPH,PP_ODD_H) +	} +	{ +		P_TMP = dfclass(C,#2) +		if (!P_TMP.new) jump:nt .Lfma_abnormal_c +		CTMP = combine(PP_ODD_H,#0) +		PP_ODD = combine(#0,PP_LL_H) +	} +.Lfma_abnormal_c_restart: +	{ +		PP_ODD += mpyu(BTMPL,ATMPH) +		CTMP = insert(C,#MANTBITS,#EXPBITS-3) +		memd(r29+#0) = PP_HH +		memd(r29+#8) = EXPBA +	} +	{ +		PP_ODD += mpyu(ATMPL,BTMPH) +		EXPBA = neg(CTMP) +		P_TMP = cmp.gt(CH,#-1) +		TMP = xor(AH,BH) +	} +	{ +		EXPA = extractu(AH,#EXPBITS,#HI_MANTBITS) +		EXPB = extractu(BH,#EXPBITS,#HI_MANTBITS) +		PP_HH = combine(#0,PP_ODD_H) +		if (!P_TMP) CTMP = EXPBA +	} +	{ +		PP_HH += mpyu(ATMPH,BTMPH) +		PP_LL = combine(PP_ODD_L,PP_LL_L) +#undef PP_ODD +#undef PP_ODD_H +#undef PP_ODD_L +#undef ATMP +#undef ATMPL +#undef ATMPH +#undef BTMP +#undef BTMPL +#undef BTMPH +#define RIGHTLEFTSHIFT r13:12 +#define RIGHTSHIFT r13 +#define LEFTSHIFT r12 + +		EXPA = add(EXPA,EXPB) +#undef EXPB +#undef EXPBA +#define EXPC r19 +#define EXPCA r19:18 +		EXPC = extractu(CH,#EXPBITS,#HI_MANTBITS) +	} +	/* PP_HH:PP_LL now has product */ +	/* CTMP is negated */ +	/* EXPA,B,C are extracted */ +	/* +	 * We need to negate PP +	 * Since we will be adding with carry later, if we need to negate, +	 * just invert all bits now, which we can do conditionally and in parallel +	 */ +#define PP_HH_TMP r15:14 +#define PP_LL_TMP r7:6 +	{ +		EXPA = add(EXPA,#-BIAS+(ADJUST)) +		PROD_NEG = !cmp.gt(TMP,#-1) +		PP_LL_TMP = #0 +		PP_HH_TMP = #0 +	} +	{ +		PP_LL_TMP = sub(PP_LL_TMP,PP_LL,PROD_NEG):carry +		P_TMP = !cmp.gt(TMP,#-1) +		SWAP = cmp.gt(EXPC,EXPA)	// If C >> PP +		if (SWAP.new) EXPCA = combine(EXPA,EXPC) +	} +	{ +		PP_HH_TMP = sub(PP_HH_TMP,PP_HH,PROD_NEG):carry +		if (P_TMP) PP_LL = PP_LL_TMP +#undef PP_LL_TMP +#define CTMP2 r7:6 +#define CTMP2H r7 +#define CTMP2L r6 +		CTMP2 = #0 +		EXPC = sub(EXPA,EXPC) +	} +	{ +		if (P_TMP) PP_HH = PP_HH_TMP +		P_TMP = cmp.gt(EXPC,#63) +		if (SWAP) PP_LL = CTMP2 +		if (SWAP) CTMP2 = PP_LL +	} +#undef PP_HH_TMP +//#define ONE r15:14 +//#define S_ONE r14 +#define ZERO r15:14 +#define S_ZERO r15 +#undef PROD_NEG +#define P_CARRY p3 +	{ +		if (SWAP) PP_HH = CTMP	// Swap C and PP +		if (SWAP) CTMP = PP_HH +		if (P_TMP) EXPC = add(EXPC,#-64) +		TMP = #63 +	} +	{ +		// If diff > 63, pre-shift-right by 64... +		if (P_TMP) CTMP2 = CTMP +		TMP = asr(CTMPH,#31) +		RIGHTSHIFT = min(EXPC,TMP) +		LEFTSHIFT = #0 +	} +#undef C +#undef CH +#undef CL +#define STICKIES r5:4 +#define STICKIESH r5 +#define STICKIESL r4 +	{ +		if (P_TMP) CTMP = combine(TMP,TMP)	// sign extension of pre-shift-right-64 +		STICKIES = extract(CTMP2,RIGHTLEFTSHIFT) +		CTMP2 = lsr(CTMP2,RIGHTSHIFT) +		LEFTSHIFT = sub(#64,RIGHTSHIFT) +	} +	{ +		ZERO = #0 +		TMP = #-2 +		CTMP2 |= lsl(CTMP,LEFTSHIFT) +		CTMP = asr(CTMP,RIGHTSHIFT) +	} +	{ +		P_CARRY = cmp.gtu(STICKIES,ZERO)	// If we have sticky bits from C shift +		if (P_CARRY.new) CTMP2L = and(CTMP2L,TMP) // make sure adding 1 == OR +#undef ZERO +#define ONE r15:14 +#define S_ONE r14 +		ONE = #1 +		STICKIES = #0 +	} +	{ +		PP_LL = add(CTMP2,PP_LL,P_CARRY):carry	// use the carry to add the sticky +	} +	{ +		PP_HH = add(CTMP,PP_HH,P_CARRY):carry +		TMP = #62 +	} +	/* +	 * PP_HH:PP_LL now holds the sum +	 * We may need to normalize left, up to ??? bits. +	 * +	 * I think that if we have massive cancellation, the range we normalize by +	 * is still limited +	 */ +	{ +		LEFTSHIFT = add(clb(PP_HH),#-2) +		if (!cmp.eq(LEFTSHIFT.new,TMP)) jump:t 1f	// all sign bits? +	} +	/* We had all sign bits, shift left by 62. */ +	{ +		CTMP = extractu(PP_LL,#62,#2) +		PP_LL = asl(PP_LL,#62) +		EXPA = add(EXPA,#-62)			// And adjust exponent of result +	} +	{ +		PP_HH = insert(CTMP,#62,#0)		// Then shift 63 +	} +	{ +		LEFTSHIFT = add(clb(PP_HH),#-2) +	} +	.falign +1: +	{ +		CTMP = asl(PP_HH,LEFTSHIFT) +		STICKIES |= asl(PP_LL,LEFTSHIFT) +		RIGHTSHIFT = sub(#64,LEFTSHIFT) +		EXPA = sub(EXPA,LEFTSHIFT) +	} +	{ +		CTMP |= lsr(PP_LL,RIGHTSHIFT) +		EXACT = cmp.gtu(ONE,STICKIES) +		TMP = #BIAS+BIAS-2 +	} +	{ +		if (!EXACT) CTMPL = or(CTMPL,S_ONE) +		// If EXPA is overflow/underflow, jump to ovf_unf +		P_TMP = !cmp.gt(EXPA,TMP) +		P_TMP = cmp.gt(EXPA,#1) +		if (!P_TMP.new) jump:nt .Lfma_ovf_unf +	} +	{ +		// XXX: FIXME: should PP_HH for check of zero be CTMP? +		P_TMP = cmp.gtu(ONE,CTMP)		// is result true zero? +		A = convert_d2df(CTMP) +		EXPA = add(EXPA,#-BIAS-60) +		PP_HH = memd(r29+#0) +	} +	{ +		AH += asl(EXPA,#HI_MANTBITS) +		EXPCA = memd(r29+#8) +		if (!P_TMP) dealloc_return		// not zero, return +	} +.Ladd_yields_zero: +	/* We had full cancellation.  Return +/- zero (-0 when round-down) */ +	{ +		TMP = USR +		A = #0 +	} +	{ +		TMP = extractu(TMP,#2,#SR_ROUND_OFF) +		PP_HH = memd(r29+#0) +		EXPCA = memd(r29+#8) +	} +	{ +		p0 = cmp.eq(TMP,#2) +		if (p0.new) AH = ##0x80000000 +		dealloc_return +	} + +#undef RIGHTLEFTSHIFT +#undef RIGHTSHIFT +#undef LEFTSHIFT +#undef CTMP2 +#undef CTMP2H +#undef CTMP2L + +.Lfma_ovf_unf: +	{ +		p0 = cmp.gtu(ONE,CTMP) +		if (p0.new) jump:nt .Ladd_yields_zero +	} +	{ +		A = convert_d2df(CTMP) +		EXPA = add(EXPA,#-BIAS-60) +		TMP = EXPA +	} +#define NEW_EXPB r7 +#define NEW_EXPA r6 +	{ +		AH += asl(EXPA,#HI_MANTBITS) +		NEW_EXPB = extractu(AH,#EXPBITS,#HI_MANTBITS) +	} +	{ +		NEW_EXPA = add(EXPA,NEW_EXPB) +		PP_HH = memd(r29+#0) +		EXPCA = memd(r29+#8) +#undef PP_HH +#undef PP_HH_H +#undef PP_HH_L +#undef EXPCA +#undef EXPC +#undef EXPA +#undef PP_LL +#undef PP_LL_H +#undef PP_LL_L +#define EXPA r6 +#define EXPB r7 +#define EXPBA r7:6 +#define ATMP r9:8 +#define ATMPH r9 +#define ATMPL r8 +#undef NEW_EXPB +#undef NEW_EXPA +		ATMP = abs(CTMP) +	} +	{ +		p0 = cmp.gt(EXPA,##BIAS+BIAS) +		if (p0.new) jump:nt .Lfma_ovf +	} +	{ +		p0 = cmp.gt(EXPA,#0) +		if (p0.new) jump:nt .Lpossible_unf +	} +	{ +		// TMP has original EXPA. +		// ATMP is corresponding value +		// Normalize ATMP and shift right to correct location +		EXPB = add(clb(ATMP),#-2)		// Amount to left shift to normalize +		EXPA = sub(#1+5,TMP)			// Amount to right shift to denormalize +		p3 = cmp.gt(CTMPH,#-1) +	} +	/* Underflow */ +	/* We know that the infinte range exponent should be EXPA */ +	/* CTMP is 2's complement, ATMP is abs(CTMP) */ +	{ +		EXPA = add(EXPA,EXPB)		// how much to shift back right +		ATMP = asl(ATMP,EXPB)		// shift left +		AH = USR +		TMP = #63 +	} +	{ +		EXPB = min(EXPA,TMP) +		EXPA = #0 +		AL = #0x0030 +	} +	{ +		B = extractu(ATMP,EXPBA) +		ATMP = asr(ATMP,EXPB) +	} +	{ +		p0 = cmp.gtu(ONE,B) +		if (!p0.new) ATMPL = or(ATMPL,S_ONE) +		ATMPH = setbit(ATMPH,#HI_MANTBITS+FUDGE2) +	} +	{ +		CTMP = neg(ATMP) +		p1 = bitsclr(ATMPL,#(1<<FUDGE2)-1) +		if (!p1.new) AH = or(AH,AL) +		B = #0 +	} +	{ +		if (p3) CTMP = ATMP +		USR = AH +		TMP = #-BIAS-(MANTBITS+FUDGE2) +	} +	{ +		A = convert_d2df(CTMP) +	} +	{ +		AH += asl(TMP,#HI_MANTBITS) +		dealloc_return +	} +.Lpossible_unf: +	{ +		TMP = ##0x7fefffff +		ATMP = abs(CTMP) +	} +	{ +		p0 = cmp.eq(AL,#0) +		p0 = bitsclr(AH,TMP) +		if (!p0.new) dealloc_return:t +		TMP = #0x7fff +	} +	{ +		p0 = bitsset(ATMPH,TMP) +		BH = USR +		BL = #0x0030 +	} +	{ +		if (p0) BH = or(BH,BL) +	} +	{ +		USR = BH +	} +	{ +		p0 = dfcmp.eq(A,A) +		dealloc_return +	} +.Lfma_ovf: +	{ +		TMP = USR +		CTMP = combine(##0x7fefffff,#-1) +		A = CTMP +	} +	{ +		ATMP = combine(##0x7ff00000,#0) +		BH = extractu(TMP,#2,#SR_ROUND_OFF) +		TMP = or(TMP,#0x28) +	} +	{ +		USR = TMP +		BH ^= lsr(AH,#31) +		BL = BH +	} +	{ +		p0 = !cmp.eq(BL,#1) +		p0 = !cmp.eq(BH,#2) +	} +	{ +		p0 = dfcmp.eq(ATMP,ATMP) +		if (p0.new) CTMP = ATMP +	} +	{ +		A = insert(CTMP,#63,#0) +		dealloc_return +	} +#undef CTMP +#undef CTMPH +#undef CTMPL +#define BTMP r11:10 +#define BTMPH r11 +#define BTMPL r10 + +#undef STICKIES +#undef STICKIESH +#undef STICKIESL +#define C r5:4 +#define CH r5 +#define CL r4 + +.Lfma_abnormal_ab: +	{ +		ATMP = extractu(A,#63,#0) +		BTMP = extractu(B,#63,#0) +		deallocframe +	} +	{ +		p3 = cmp.gtu(ATMP,BTMP) +		if (!p3.new) A = B		// sort values +		if (!p3.new) B = A +	} +	{ +		p0 = dfclass(A,#0x0f)		// A NaN? +		if (!p0.new) jump:nt .Lnan +		if (!p3) ATMP = BTMP +		if (!p3) BTMP = ATMP +	} +	{ +		p1 = dfclass(A,#0x08)		// A is infinity +		p1 = dfclass(B,#0x0e)		// B is nonzero +	} +	{ +		p0 = dfclass(A,#0x08)		// a is inf +		p0 = dfclass(B,#0x01)		// b is zero +	} +	{ +		if (p1) jump .Lab_inf +		p2 = dfclass(B,#0x01) +	} +	{ +		if (p0) jump .Linvalid +		if (p2) jump .Lab_true_zero +		TMP = ##0x7c000000 +	} +	// We are left with a normal or subnormal times a subnormal, A > B +	// If A and B are both very small, we will go to a single sticky bit; replace +	// A and B lower 63 bits with 0x0010_0000_0000_0000, which yields equivalent results +	// if A and B might multiply to something bigger, decrease A exp and increase B exp +	// and start over +	{ +		p0 = bitsclr(AH,TMP) +		if (p0.new) jump:nt .Lfma_ab_tiny +	} +	{ +		TMP = add(clb(BTMP),#-EXPBITS) +	} +	{ +		BTMP = asl(BTMP,TMP) +	} +	{ +		B = insert(BTMP,#63,#0) +		AH -= asl(TMP,#HI_MANTBITS) +	} +	jump fma + +.Lfma_ab_tiny: +	ATMP = combine(##0x00100000,#0) +	{ +		A = insert(ATMP,#63,#0) +		B = insert(ATMP,#63,#0) +	} +	jump fma + +.Lab_inf: +	{ +		B = lsr(B,#63) +		p0 = dfclass(C,#0x10) +	} +	{ +		A ^= asl(B,#63) +		if (p0) jump .Lnan +	} +	{ +		p1 = dfclass(C,#0x08) +		if (p1.new) jump:nt .Lfma_inf_plus_inf +	} +	/* A*B is +/- inf, C is finite.  Return A */ +	{ +		jumpr r31 +	} +	.falign +.Lfma_inf_plus_inf: +	{	// adding infinities of different signs is invalid +		p0 = dfcmp.eq(A,C) +		if (!p0.new) jump:nt .Linvalid +	} +	{ +		jumpr r31 +	} + +.Lnan: +	{ +		p0 = dfclass(B,#0x10) +		p1 = dfclass(C,#0x10) +		if (!p0.new) B = A +		if (!p1.new) C = A +	} +	{	// find sNaNs +		BH = convert_df2sf(B) +		BL = convert_df2sf(C) +	} +	{ +		BH = convert_df2sf(A) +		A = #-1 +		jumpr r31 +	} + +.Linvalid: +	{ +		TMP = ##0x7f800001		// sp snan +	} +	{ +		A = convert_sf2df(TMP) +		jumpr r31 +	} + +.Lab_true_zero: +	// B is zero, A is finite number +	{ +		p0 = dfclass(C,#0x10) +		if (p0.new) jump:nt .Lnan +		if (p0.new) A = C +	} +	{ +		p0 = dfcmp.eq(B,C)		// is C also zero? +		AH = lsr(AH,#31)		// get sign +	} +	{ +		BH ^= asl(AH,#31)		// form correctly signed zero in B +		if (!p0) A = C			// If C is not zero, return C +		if (!p0) jumpr r31 +	} +	/* B has correctly signed zero, C is also zero */ +.Lzero_plus_zero: +	{ +		p0 = cmp.eq(B,C)		// yes, scalar equals.  +0++0 or -0+-0 +		if (p0.new) jumpr:t r31 +		A = B +	} +	{ +		TMP = USR +	} +	{ +		TMP = extractu(TMP,#2,#SR_ROUND_OFF) +		A = #0 +	} +	{ +		p0 = cmp.eq(TMP,#2) +		if (p0.new) AH = ##0x80000000 +		jumpr r31 +	} +#undef BTMP +#undef BTMPH +#undef BTMPL +#define CTMP r11:10 +	.falign +.Lfma_abnormal_c: +	/* We know that AB is normal * normal */ +	/* C is not normal: zero, subnormal, inf, or NaN. */ +	{ +		p0 = dfclass(C,#0x10)		// is C NaN? +		if (p0.new) jump:nt .Lnan +		if (p0.new) A = C		// move NaN to A +		deallocframe +	} +	{ +		p0 = dfclass(C,#0x08)		// is C inf? +		if (p0.new) A = C		// return C +		if (p0.new) jumpr:nt r31 +	} +	// zero or subnormal +	// If we have a zero, and we know AB is normal*normal, we can just call normal multiply +	{ +		p0 = dfclass(C,#0x01)		// is C zero? +		if (p0.new) jump:nt __hexagon_muldf3 +		TMP = #1 +	} +	// Left with: subnormal +	// Adjust C and jump back to restart +	{ +		allocframe(#STACKSPACE)		// oops, deallocated above, re-allocate frame +		CTMP = #0 +		CH = insert(TMP,#EXPBITS,#HI_MANTBITS) +		jump .Lfma_abnormal_c_restart +	} +END(fma) diff --git a/lib/builtins/hexagon/dfminmax.S b/lib/builtins/hexagon/dfminmax.S new file mode 100644 index 0000000000000..41122911f1839 --- /dev/null +++ b/lib/builtins/hexagon/dfminmax.S @@ -0,0 +1,79 @@ +//===----------------------Hexagon builtin routine ------------------------===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#define A r1:0 +#define B r3:2 +#define ATMP r5:4 + + +#define Q6_ALIAS(TAG) .global __qdsp_##TAG ; .set __qdsp_##TAG, __hexagon_##TAG +#define END(TAG) .size TAG,.-TAG + +/* + * Min and Max return A if B is NaN, or B if A is NaN + * Otherwise, they return the smaller or bigger value + * + * If values are equal, we want to favor -0.0 for min and +0.0 for max. + */ + +/* + * Compares always return false for NaN + * if (isnan(A)) A = B; if (A > B) A = B will only trigger at most one of those options. + */ +	.text +	.global __hexagon_mindf3 +	.global __hexagon_maxdf3 +	.global fmin +	.type fmin,@function +	.global fmax +	.type fmax,@function +	.type __hexagon_mindf3,@function +	.type __hexagon_maxdf3,@function +	Q6_ALIAS(mindf3) +	Q6_ALIAS(maxdf3) +	.p2align 5 +__hexagon_mindf3: +fmin: +	{ +		p0 = dfclass(A,#0x10)		// If A is a number +		p1 = dfcmp.gt(A,B)		// AND B > A, don't swap +		ATMP = A +	} +	{ +		if (p0) A = B			// if A is NaN use B +		if (p1) A = B			// gt is always false if either is NaN +		p2 = dfcmp.eq(A,B)		// if A == B +		if (!p2.new) jumpr:t r31 +	} +	/* A == B, return A|B to select -0.0 over 0.0 */ +	{ +		A = or(ATMP,B) +		jumpr r31 +	} +END(__hexagon_mindf3) +	.falign +__hexagon_maxdf3: +fmax: +	{ +		p0 = dfclass(A,#0x10) +		p1 = dfcmp.gt(B,A) +		ATMP = A +	} +	{ +		if (p0) A = B +		if (p1) A = B +		p2 = dfcmp.eq(A,B) +		if (!p2.new) jumpr:t r31 +	} +	/* A == B, return A&B to select 0.0 over -0.0 */ +	{ +		A = and(ATMP,B) +		jumpr r31 +	} +END(__hexagon_maxdf3) diff --git a/lib/builtins/hexagon/dfmul.S b/lib/builtins/hexagon/dfmul.S new file mode 100644 index 0000000000000..fde6d77bdcff4 --- /dev/null +++ b/lib/builtins/hexagon/dfmul.S @@ -0,0 +1,418 @@ +//===----------------------Hexagon builtin routine ------------------------===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +/* Double Precision Multiply */ +#define A r1:0 +#define AH r1 +#define AL r0 +#define B r3:2 +#define BH r3 +#define BL r2 + +#define BTMP r5:4 +#define BTMPH r5 +#define BTMPL r4 + +#define PP_ODD r7:6 +#define PP_ODD_H r7 +#define PP_ODD_L r6 + +#define ONE r9:8 +#define S_ONE r8 +#define S_ZERO r9 + +#define PP_HH r11:10 +#define PP_HH_H r11 +#define PP_HH_L r10 + +#define ATMP r13:12 +#define ATMPH r13 +#define ATMPL r12 + +#define PP_LL r15:14 +#define PP_LL_H r15 +#define PP_LL_L r14 + +#define TMP r28 + +#define MANTBITS 52 +#define HI_MANTBITS 20 +#define EXPBITS 11 +#define BIAS 1024 +#define MANTISSA_TO_INT_BIAS 52 + +/* Some constant to adjust normalization amount in error code */ +/* Amount to right shift the partial product to get to a denorm */ +#define FUDGE 5 + +#define Q6_ALIAS(TAG) .global __qdsp_##TAG ; .set __qdsp_##TAG, __hexagon_##TAG +#define FAST_ALIAS(TAG) .global __hexagon_fast_##TAG ; .set __hexagon_fast_##TAG, __hexagon_##TAG +#define FAST2_ALIAS(TAG) .global __hexagon_fast2_##TAG ; .set __hexagon_fast2_##TAG, __hexagon_##TAG +#define END(TAG) .size TAG,.-TAG + +#define SR_ROUND_OFF 22 +	.text +	.global __hexagon_muldf3 +	.type __hexagon_muldf3,@function +	Q6_ALIAS(muldf3) +  FAST_ALIAS(muldf3) +  FAST2_ALIAS(muldf3) +	.p2align 5 +__hexagon_muldf3: +	{ +		p0 = dfclass(A,#2) +		p0 = dfclass(B,#2) +		ATMP = combine(##0x40000000,#0) +	} +	{ +		ATMP = insert(A,#MANTBITS,#EXPBITS-1) +		BTMP = asl(B,#EXPBITS-1) +		TMP = #-BIAS +		ONE = #1 +	} +	{ +		PP_ODD = mpyu(BTMPL,ATMPH) +		BTMP = insert(ONE,#2,#62) +	} +	/* since we know that the MSB of the H registers is zero, we should never carry */ +	/* H <= 2^31-1.  L <= 2^32-1.  Therefore, HL <= 2^63-2^32-2^31+1 */ +	/* Adding 2 HLs, we get 2^64-3*2^32+2 maximum.  */ +	/* Therefore, we can add 3 2^32-1 values safely without carry.  We only need one. */ +	{ +		PP_LL = mpyu(ATMPL,BTMPL) +		PP_ODD += mpyu(ATMPL,BTMPH) +	} +	{ +		PP_ODD += lsr(PP_LL,#32) +		PP_HH = mpyu(ATMPH,BTMPH) +		BTMP = combine(##BIAS+BIAS-4,#0) +	} +	{ +		PP_HH += lsr(PP_ODD,#32) +		if (!p0) jump .Lmul_abnormal +		p1 = cmp.eq(PP_LL_L,#0)		// 64 lsb's 0? +		p1 = cmp.eq(PP_ODD_L,#0)	// 64 lsb's 0? +	} +	/* +	 * PP_HH can have a maximum of 0x3FFF_FFFF_FFFF_FFFF or thereabouts +	 * PP_HH can have a minimum of 0x1000_0000_0000_0000 or so +	 */ +#undef PP_ODD +#undef PP_ODD_H +#undef PP_ODD_L +#define EXP10 r7:6 +#define EXP1 r7 +#define EXP0 r6 +	{ +		if (!p1) PP_HH_L = or(PP_HH_L,S_ONE) +		EXP0 = extractu(AH,#EXPBITS,#HI_MANTBITS) +		EXP1 = extractu(BH,#EXPBITS,#HI_MANTBITS) +	} +	{ +		PP_LL = neg(PP_HH) +		EXP0 += add(TMP,EXP1) +		TMP = xor(AH,BH) +	} +	{ +		if (!p2.new) PP_HH = PP_LL +		p2 = cmp.gt(TMP,#-1) +		p0 = !cmp.gt(EXP0,BTMPH) +		p0 = cmp.gt(EXP0,BTMPL) +		if (!p0.new) jump:nt .Lmul_ovf_unf +	} +	{ +		A = convert_d2df(PP_HH) +		EXP0 = add(EXP0,#-BIAS-58) +	} +	{ +		AH += asl(EXP0,#HI_MANTBITS) +		jumpr r31 +	} + +	.falign +.Lpossible_unf: +	/* We end up with a positive exponent */ +	/* But we may have rounded up to an exponent of 1. */ +	/* If the exponent is 1, if we rounded up to it +	 * we need to also raise underflow +	 * Fortunately, this is pretty easy to detect, we must have +/- 0x0010_0000_0000_0000 +	 * And the PP should also have more than one bit set +	 */ +	/* Note: ATMP should have abs(PP_HH) */ +	/* Note: BTMPL should have 0x7FEFFFFF */ +	{ +		p0 = cmp.eq(AL,#0) +		p0 = bitsclr(AH,BTMPL) +		if (!p0.new) jumpr:t r31 +		BTMPH = #0x7fff +	} +	{ +		p0 = bitsset(ATMPH,BTMPH) +		BTMPL = USR +		BTMPH = #0x030 +	} +	{ +		if (p0) BTMPL = or(BTMPL,BTMPH) +	} +	{ +		USR = BTMPL +	} +	{ +		p0 = dfcmp.eq(A,A) +		jumpr r31 +	} +	.falign +.Lmul_ovf_unf: +	{ +		A = convert_d2df(PP_HH) +		ATMP = abs(PP_HH)			// take absolute value +		EXP1 = add(EXP0,#-BIAS-58) +	} +	{ +		AH += asl(EXP1,#HI_MANTBITS) +		EXP1 = extractu(AH,#EXPBITS,#HI_MANTBITS) +		BTMPL = ##0x7FEFFFFF +	} +	{ +		EXP1 += add(EXP0,##-BIAS-58) +		//BTMPH = add(clb(ATMP),#-2) +		BTMPH = #0 +	} +	{ +		p0 = cmp.gt(EXP1,##BIAS+BIAS-2)	// overflow +		if (p0.new) jump:nt .Lmul_ovf +	} +	{ +		p0 = cmp.gt(EXP1,#0) +		if (p0.new) jump:nt .Lpossible_unf +		BTMPH = sub(EXP0,BTMPH) +		TMP = #63				// max amount to shift +	} +	/* Underflow */ +	/* +	 * PP_HH has the partial product with sticky LSB. +	 * PP_HH can have a maximum of 0x3FFF_FFFF_FFFF_FFFF or thereabouts +	 * PP_HH can have a minimum of 0x1000_0000_0000_0000 or so +	 * The exponent of PP_HH is in  EXP1, which is non-positive (0 or negative) +	 * That's the exponent that happens after the normalization +	 * +	 * EXP0 has the exponent that, when added to the normalized value, is out of range. +	 * +	 * Strategy: +	 * +	 * * Shift down bits, with sticky bit, such that the bits are aligned according +	 *   to the LZ count and appropriate exponent, but not all the way to mantissa +	 *   field, keep around the last few bits. +	 * * Put a 1 near the MSB +	 * * Check the LSBs for inexact; if inexact also set underflow +	 * * Convert [u]d2df -- will correctly round according to rounding mode +	 * * Replace exponent field with zero +	 * +	 * +	 */ + + +	{ +		BTMPL = #0	 			// offset for extract +		BTMPH = sub(#FUDGE,BTMPH)		// amount to right shift +	} +	{ +		p3 = cmp.gt(PP_HH_H,#-1)		// is it positive? +		BTMPH = min(BTMPH,TMP)			// Don't shift more than 63 +		PP_HH = ATMP +	} +	{ +		TMP = USR +		PP_LL = extractu(PP_HH,BTMP) +	} +	{ +		PP_HH = asr(PP_HH,BTMPH) +		BTMPL = #0x0030					// underflow flag +		AH = insert(S_ZERO,#EXPBITS,#HI_MANTBITS) +	} +	{ +		p0 = cmp.gtu(ONE,PP_LL)				// Did we extract all zeros? +		if (!p0.new) PP_HH_L = or(PP_HH_L,S_ONE)	// add sticky bit +		PP_HH_H = setbit(PP_HH_H,#HI_MANTBITS+3)	// Add back in a bit so we can use convert instruction +	} +	{ +		PP_LL = neg(PP_HH) +		p1 = bitsclr(PP_HH_L,#0x7)		// Are the LSB's clear? +		if (!p1.new) TMP = or(BTMPL,TMP)	// If not, Inexact+Underflow +	} +	{ +		if (!p3) PP_HH = PP_LL +		USR = TMP +	} +	{ +		A = convert_d2df(PP_HH)			// Do rounding +		p0 = dfcmp.eq(A,A)			// realize exception +	} +	{ +		AH = insert(S_ZERO,#EXPBITS-1,#HI_MANTBITS+1)		// Insert correct exponent +		jumpr r31 +	} +	.falign +.Lmul_ovf: +	// We get either max finite value or infinity.  Either way, overflow+inexact +	{ +		TMP = USR +		ATMP = combine(##0x7fefffff,#-1)	// positive max finite +		A = PP_HH +	} +	{ +		PP_LL_L = extractu(TMP,#2,#SR_ROUND_OFF)	// rounding bits +		TMP = or(TMP,#0x28)			// inexact + overflow +		BTMP = combine(##0x7ff00000,#0)		// positive infinity +	} +	{ +		USR = TMP +		PP_LL_L ^= lsr(AH,#31)			// Does sign match rounding? +		TMP = PP_LL_L				// unmodified rounding mode +	} +	{ +		p0 = !cmp.eq(TMP,#1)			// If not round-to-zero and +		p0 = !cmp.eq(PP_LL_L,#2)		// Not rounding the other way, +		if (p0.new) ATMP = BTMP			// we should get infinity +		p0 = dfcmp.eq(A,A)			// Realize FP exception if enabled +	} +	{ +		A = insert(ATMP,#63,#0)			// insert inf/maxfinite, leave sign +		jumpr r31 +	} + +.Lmul_abnormal: +	{ +		ATMP = extractu(A,#63,#0)		// strip off sign +		BTMP = extractu(B,#63,#0)		// strip off sign +	} +	{ +		p3 = cmp.gtu(ATMP,BTMP) +		if (!p3.new) A = B			// sort values +		if (!p3.new) B = A			// sort values +	} +	{ +		// Any NaN --> NaN, possibly raise invalid if sNaN +		p0 = dfclass(A,#0x0f)		// A not NaN? +		if (!p0.new) jump:nt .Linvalid_nan +		if (!p3) ATMP = BTMP +		if (!p3) BTMP = ATMP +	} +	{ +		// Infinity * nonzero number is infinity +		p1 = dfclass(A,#0x08)		// A is infinity +		p1 = dfclass(B,#0x0e)		// B is nonzero +	} +	{ +		// Infinity * zero --> NaN, raise invalid +		// Other zeros return zero +		p0 = dfclass(A,#0x08)		// A is infinity +		p0 = dfclass(B,#0x01)		// B is zero +	} +	{ +		if (p1) jump .Ltrue_inf +		p2 = dfclass(B,#0x01) +	} +	{ +		if (p0) jump .Linvalid_zeroinf +		if (p2) jump .Ltrue_zero		// so return zero +		TMP = ##0x7c000000 +	} +	// We are left with a normal or subnormal times a subnormal. A > B +	// If A and B are both very small (exp(a) < BIAS-MANTBITS), +	// we go to a single sticky bit, which we can round easily. +	// If A and B might multiply to something bigger, decrease A exponent and increase +	// B exponent and try again +	{ +		p0 = bitsclr(AH,TMP) +		if (p0.new) jump:nt .Lmul_tiny +	} +	{ +		TMP = cl0(BTMP) +	} +	{ +		TMP = add(TMP,#-EXPBITS) +	} +	{ +		BTMP = asl(BTMP,TMP) +	} +	{ +		B = insert(BTMP,#63,#0) +		AH -= asl(TMP,#HI_MANTBITS) +	} +	jump __hexagon_muldf3 +.Lmul_tiny: +	{ +		TMP = USR +		A = xor(A,B)				// get sign bit +	} +	{ +		TMP = or(TMP,#0x30)			// Inexact + Underflow +		A = insert(ONE,#63,#0)			// put in rounded up value +		BTMPH = extractu(TMP,#2,#SR_ROUND_OFF)	// get rounding mode +	} +	{ +		USR = TMP +		p0 = cmp.gt(BTMPH,#1)			// Round towards pos/neg inf? +		if (!p0.new) AL = #0			// If not, zero +		BTMPH ^= lsr(AH,#31)			// rounding my way --> set LSB +	} +	{ +		p0 = cmp.eq(BTMPH,#3)			// if rounding towards right inf +		if (!p0.new) AL = #0			// don't go to zero +		jumpr r31 +	} +.Linvalid_zeroinf: +	{ +		TMP = USR +	} +	{ +		A = #-1 +		TMP = or(TMP,#2) +	} +	{ +		USR = TMP +	} +	{ +		p0 = dfcmp.uo(A,A)			// force exception if enabled +		jumpr r31 +	} +.Linvalid_nan: +	{ +		p0 = dfclass(B,#0x0f)			// if B is not NaN +		TMP = convert_df2sf(A)			// will generate invalid if sNaN +		if (p0.new) B = A 			// make it whatever A is +	} +	{ +		BL = convert_df2sf(B)			// will generate invalid if sNaN +		A = #-1 +		jumpr r31 +	} +	.falign +.Ltrue_zero: +	{ +		A = B +		B = A +	} +.Ltrue_inf: +	{ +		BH = extract(BH,#1,#31) +	} +	{ +		AH ^= asl(BH,#31) +		jumpr r31 +	} +END(__hexagon_muldf3) + +#undef ATMP +#undef ATMPL +#undef ATMPH +#undef BTMP +#undef BTMPL +#undef BTMPH diff --git a/lib/builtins/hexagon/dfsqrt.S b/lib/builtins/hexagon/dfsqrt.S new file mode 100644 index 0000000000000..027d9e1fde432 --- /dev/null +++ b/lib/builtins/hexagon/dfsqrt.S @@ -0,0 +1,406 @@ +//===----------------------Hexagon builtin routine ------------------------===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +/* Double Precision square root */ + +#define EXP r28 + +#define A r1:0 +#define AH r1 +#define AL r0 + +#define SFSH r3:2 +#define SF_S r3 +#define SF_H r2 + +#define SFHALF_SONE r5:4 +#define S_ONE r4 +#define SFHALF r5 +#define SF_D r6 +#define SF_E r7 +#define RECIPEST r8 +#define SFRAD r9 + +#define FRACRAD r11:10 +#define FRACRADH r11 +#define FRACRADL r10 + +#define ROOT r13:12 +#define ROOTHI r13 +#define ROOTLO r12 + +#define PROD r15:14 +#define PRODHI r15 +#define PRODLO r14 + +#define P_TMP p0 +#define P_EXP1 p1 +#define NORMAL p2 + +#define SF_EXPBITS 8 +#define SF_MANTBITS 23 + +#define DF_EXPBITS 11 +#define DF_MANTBITS 52 + +#define DF_BIAS 0x3ff + +#define DFCLASS_ZERO     0x01 +#define DFCLASS_NORMAL   0x02 +#define DFCLASS_DENORMAL 0x02 +#define DFCLASS_INFINITE 0x08 +#define DFCLASS_NAN      0x10 + +#define Q6_ALIAS(TAG) .global __qdsp_##TAG ; .set __qdsp_##TAG, __hexagon_##TAG; .type __qdsp_##TAG,@function +#define FAST_ALIAS(TAG) .global __hexagon_fast_##TAG ; .set __hexagon_fast_##TAG, __hexagon_##TAG; .type __hexagon_fast_##TAG,@function +#define FAST2_ALIAS(TAG) .global __hexagon_fast2_##TAG ; .set __hexagon_fast2_##TAG, __hexagon_##TAG; .type __hexagon_fast2_##TAG,@function +#define END(TAG) .size TAG,.-TAG + +	.text +	.global __hexagon_sqrtdf2 +	.type __hexagon_sqrtdf2,@function +	.global __hexagon_sqrt +	.type __hexagon_sqrt,@function +	Q6_ALIAS(sqrtdf2) +	Q6_ALIAS(sqrt) +	FAST_ALIAS(sqrtdf2) +	FAST_ALIAS(sqrt) +	FAST2_ALIAS(sqrtdf2) +	FAST2_ALIAS(sqrt) +	.type sqrt,@function +	.p2align 5 +__hexagon_sqrtdf2: +__hexagon_sqrt: +	{ +		PROD = extractu(A,#SF_MANTBITS+1,#DF_MANTBITS-SF_MANTBITS) +		EXP = extractu(AH,#DF_EXPBITS,#DF_MANTBITS-32) +		SFHALF_SONE = combine(##0x3f000004,#1) +	} +	{ +		NORMAL = dfclass(A,#DFCLASS_NORMAL)		// Is it normal +		NORMAL = cmp.gt(AH,#-1)				// and positive? +		if (!NORMAL.new) jump:nt .Lsqrt_abnormal +		SFRAD = or(SFHALF,PRODLO) +	} +#undef NORMAL +.Ldenormal_restart: +	{ +		FRACRAD = A +		SF_E,P_TMP = sfinvsqrta(SFRAD) +		SFHALF = and(SFHALF,#-16) +		SFSH = #0 +	} +#undef A +#undef AH +#undef AL +#define ERROR r1:0 +#define ERRORHI r1 +#define ERRORLO r0 +	// SF_E : reciprocal square root +	// SF_H : half rsqrt +	// sf_S : square root +	// SF_D : error term +	// SFHALF: 0.5 +	{ +		SF_S += sfmpy(SF_E,SFRAD):lib		// s0: root +		SF_H += sfmpy(SF_E,SFHALF):lib		// h0: 0.5*y0. Could also decrement exponent... +		SF_D = SFHALF +#undef SFRAD +#define SHIFTAMT r9 +		SHIFTAMT = and(EXP,#1) +	} +	{ +		SF_D -= sfmpy(SF_S,SF_H):lib		// d0: 0.5-H*S = 0.5-0.5*~1 +		FRACRADH = insert(S_ONE,#DF_EXPBITS+1,#DF_MANTBITS-32)	// replace upper bits with hidden +		P_EXP1 = cmp.gtu(SHIFTAMT,#0) +	} +	{ +		SF_S += sfmpy(SF_S,SF_D):lib		// s1: refine sqrt +		SF_H += sfmpy(SF_H,SF_D):lib		// h1: refine half-recip +		SF_D = SFHALF +		SHIFTAMT = mux(P_EXP1,#8,#9) +	} +	{ +		SF_D -= sfmpy(SF_S,SF_H):lib		// d1: error term +		FRACRAD = asl(FRACRAD,SHIFTAMT)		// Move fracrad bits to right place +		SHIFTAMT = mux(P_EXP1,#3,#2) +	} +	{ +		SF_H += sfmpy(SF_H,SF_D):lib		// d2: rsqrt +		// cool trick: half of 1/sqrt(x) has same mantissa as 1/sqrt(x). +		PROD = asl(FRACRAD,SHIFTAMT)		// fracrad<<(2+exp1) +	} +	{ +		SF_H = and(SF_H,##0x007fffff) +	} +	{ +		SF_H = add(SF_H,##0x00800000 - 3) +		SHIFTAMT = mux(P_EXP1,#7,#8) +	} +	{ +		RECIPEST = asl(SF_H,SHIFTAMT) +		SHIFTAMT = mux(P_EXP1,#15-(1+1),#15-(1+0)) +	} +	{ +		ROOT = mpyu(RECIPEST,PRODHI)		// root = mpyu_full(recipest,hi(fracrad<<(2+exp1))) +	} + +#undef SFSH	// r3:2 +#undef SF_H	// r2 +#undef SF_S	// r3 +#undef S_ONE	// r4 +#undef SFHALF	// r5 +#undef SFHALF_SONE	// r5:4 +#undef SF_D	// r6 +#undef SF_E	// r7 + +#define HL r3:2 +#define LL r5:4 +#define HH r7:6 + +#undef P_EXP1 +#define P_CARRY0 p1 +#define P_CARRY1 p2 +#define P_CARRY2 p3 + +	/* Iteration 0 */ +	/* Maybe we can save a cycle by starting with ERROR=asl(fracrad), then as we multiply */ +	/* We can shift and subtract instead of shift and add? */ +	{ +		ERROR = asl(FRACRAD,#15) +		PROD = mpyu(ROOTHI,ROOTHI) +		P_CARRY0 = cmp.eq(r0,r0) +	} +	{ +		ERROR -= asl(PROD,#15) +		PROD = mpyu(ROOTHI,ROOTLO) +		P_CARRY1 = cmp.eq(r0,r0) +	} +	{ +		ERROR -= lsr(PROD,#16) +		P_CARRY2 = cmp.eq(r0,r0) +	} +	{ +		ERROR = mpyu(ERRORHI,RECIPEST) +	} +	{ +		ROOT += lsr(ERROR,SHIFTAMT) +		SHIFTAMT = add(SHIFTAMT,#16) +		ERROR = asl(FRACRAD,#31)		// for next iter +	} +	/* Iteration 1 */ +	{ +		PROD = mpyu(ROOTHI,ROOTHI) +		ERROR -= mpyu(ROOTHI,ROOTLO)	// amount is 31, no shift needed +	} +	{ +		ERROR -= asl(PROD,#31) +		PROD = mpyu(ROOTLO,ROOTLO) +	} +	{ +		ERROR -= lsr(PROD,#33) +	} +	{ +		ERROR = mpyu(ERRORHI,RECIPEST) +	} +	{ +		ROOT += lsr(ERROR,SHIFTAMT) +		SHIFTAMT = add(SHIFTAMT,#16) +		ERROR = asl(FRACRAD,#47)	// for next iter +	} +	/* Iteration 2 */ +	{ +		PROD = mpyu(ROOTHI,ROOTHI) +	} +	{ +		ERROR -= asl(PROD,#47) +		PROD = mpyu(ROOTHI,ROOTLO) +	} +	{ +		ERROR -= asl(PROD,#16)		// bidir shr 31-47 +		PROD = mpyu(ROOTLO,ROOTLO) +	} +	{ +		ERROR -= lsr(PROD,#17)		// 64-47 +	} +	{ +		ERROR = mpyu(ERRORHI,RECIPEST) +	} +	{ +		ROOT += lsr(ERROR,SHIFTAMT) +	} +#undef ERROR +#undef PROD +#undef PRODHI +#undef PRODLO +#define REM_HI r15:14 +#define REM_HI_HI r15 +#define REM_LO r1:0 +#undef RECIPEST +#undef SHIFTAMT +#define TWOROOT_LO r9:8 +	/* Adjust Root */ +	{ +		HL = mpyu(ROOTHI,ROOTLO) +		LL = mpyu(ROOTLO,ROOTLO) +		REM_HI = #0 +		REM_LO = #0 +	} +	{ +		HL += lsr(LL,#33) +		LL += asl(HL,#33) +		P_CARRY0 = cmp.eq(r0,r0) +	} +	{ +		HH = mpyu(ROOTHI,ROOTHI) +		REM_LO = sub(REM_LO,LL,P_CARRY0):carry +		TWOROOT_LO = #1 +	} +	{ +		HH += lsr(HL,#31) +		TWOROOT_LO += asl(ROOT,#1) +	} +#undef HL +#undef LL +#define REM_HI_TMP r3:2 +#define REM_HI_TMP_HI r3 +#define REM_LO_TMP r5:4 +	{ +		REM_HI = sub(FRACRAD,HH,P_CARRY0):carry +		REM_LO_TMP = sub(REM_LO,TWOROOT_LO,P_CARRY1):carry +#undef FRACRAD +#undef HH +#define ZERO r11:10 +#define ONE r7:6 +		ONE = #1 +		ZERO = #0 +	} +	{ +		REM_HI_TMP = sub(REM_HI,ZERO,P_CARRY1):carry +		ONE = add(ROOT,ONE) +		EXP = add(EXP,#-DF_BIAS)			// subtract bias --> signed exp +	} +	{ +				// If carry set, no borrow: result was still positive +		if (P_CARRY1) ROOT = ONE +		if (P_CARRY1) REM_LO = REM_LO_TMP +		if (P_CARRY1) REM_HI = REM_HI_TMP +	} +	{ +		REM_LO_TMP = sub(REM_LO,TWOROOT_LO,P_CARRY2):carry +		ONE = #1 +		EXP = asr(EXP,#1)				// divide signed exp by 2 +	} +	{ +		REM_HI_TMP = sub(REM_HI,ZERO,P_CARRY2):carry +		ONE = add(ROOT,ONE) +	} +	{ +		if (P_CARRY2) ROOT = ONE +		if (P_CARRY2) REM_LO = REM_LO_TMP +								// since tworoot <= 2^32, remhi must be zero +#undef REM_HI_TMP +#undef REM_HI_TMP_HI +#define S_ONE r2 +#define ADJ r3 +		S_ONE = #1 +	} +	{ +		P_TMP = cmp.eq(REM_LO,ZERO)			// is the low part zero +		if (!P_TMP.new) ROOTLO = or(ROOTLO,S_ONE)	// if so, it's exact... hopefully +		ADJ = cl0(ROOT) +		EXP = add(EXP,#-63) +	} +#undef REM_LO +#define RET r1:0 +#define RETHI r1 +	{ +		RET = convert_ud2df(ROOT)			// set up mantissa, maybe set inexact flag +		EXP = add(EXP,ADJ)				// add back bias +	} +	{ +		RETHI += asl(EXP,#DF_MANTBITS-32)		// add exponent adjust +		jumpr r31 +	} +#undef REM_LO_TMP +#undef REM_HI_TMP +#undef REM_HI_TMP_HI +#undef REM_LO +#undef REM_HI +#undef TWOROOT_LO + +#undef RET +#define A r1:0 +#define AH r1 +#define AL r1 +#undef S_ONE +#define TMP r3:2 +#define TMPHI r3 +#define TMPLO r2 +#undef P_CARRY0 +#define P_NEG p1 + + +#define SFHALF r5 +#define SFRAD r9 +.Lsqrt_abnormal: +	{ +		P_TMP = dfclass(A,#DFCLASS_ZERO)			// zero? +		if (P_TMP.new) jumpr:t r31 +	} +	{ +		P_TMP = dfclass(A,#DFCLASS_NAN) +		if (P_TMP.new) jump:nt .Lsqrt_nan +	} +	{ +		P_TMP = cmp.gt(AH,#-1) +		if (!P_TMP.new) jump:nt .Lsqrt_invalid_neg +		if (!P_TMP.new) EXP = ##0x7F800001			// sNaN +	} +	{ +		P_TMP = dfclass(A,#DFCLASS_INFINITE) +		if (P_TMP.new) jumpr:nt r31 +	} +	// If we got here, we're denormal +	// prepare to restart +	{ +		A = extractu(A,#DF_MANTBITS,#0)		// Extract mantissa +	} +	{ +		EXP = add(clb(A),#-DF_EXPBITS)		// how much to normalize? +	} +	{ +		A = asl(A,EXP)				// Shift mantissa +		EXP = sub(#1,EXP)			// Form exponent +	} +	{ +		AH = insert(EXP,#1,#DF_MANTBITS-32)		// insert lsb of exponent +	} +	{ +		TMP = extractu(A,#SF_MANTBITS+1,#DF_MANTBITS-SF_MANTBITS)	// get sf value (mant+exp1) +		SFHALF = ##0x3f000004						// form half constant +	} +	{ +		SFRAD = or(SFHALF,TMPLO)			// form sf value +		SFHALF = and(SFHALF,#-16) +		jump .Ldenormal_restart				// restart +	} +.Lsqrt_nan: +	{ +		EXP = convert_df2sf(A)				// if sNaN, get invalid +		A = #-1						// qNaN +		jumpr r31 +	} +.Lsqrt_invalid_neg: +	{ +		A = convert_sf2df(EXP)				// Invalid,NaNval +		jumpr r31 +	} +END(__hexagon_sqrt) +END(__hexagon_sqrtdf2) diff --git a/lib/builtins/hexagon/divdi3.S b/lib/builtins/hexagon/divdi3.S new file mode 100644 index 0000000000000..49ee8104f3055 --- /dev/null +++ b/lib/builtins/hexagon/divdi3.S @@ -0,0 +1,85 @@ +//===----------------------Hexagon builtin routine ------------------------===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +	.macro FUNCTION_BEGIN name +	.text +        .p2align 5 +	.globl \name +	.type  \name, @function +\name: +	.endm + +	.macro FUNCTION_END name +	.size  \name, . - \name +	.endm + + +FUNCTION_BEGIN __hexagon_divdi3 +	{ +		p2 = tstbit(r1,#31) +		p3 = tstbit(r3,#31) +	} +	{ +		r1:0 = abs(r1:0) +		r3:2 = abs(r3:2) +	} +	{ +		r6 = cl0(r1:0)              // count leading 0's of dividend (numerator) +		r7 = cl0(r3:2)              // count leading 0's of divisor (denominator) +		r5:4 = r3:2                 // divisor moved into working registers +		r3:2 = r1:0                 // dividend is the initial remainder, r3:2 contains remainder +	} +	{ +		p3 = xor(p2,p3) +		r10 = sub(r7,r6)            // left shift count for bit & divisor +		r1:0 = #0                   // initialize quotient to 0 +		r15:14 = #1                 // initialize bit to 1 +	} +	{ +		r11 = add(r10,#1)           // loop count is 1 more than shift count +		r13:12 = lsl(r5:4,r10)      // shift divisor msb into same bit position as dividend msb +		r15:14 = lsl(r15:14,r10)    // shift the bit left by same amount as divisor +	} +	{ +		p0 = cmp.gtu(r5:4,r3:2)     // check if divisor > dividend +		loop0(1f,r11)               // register loop +	} +	{ +		if (p0) jump .hexagon_divdi3_return          // if divisor > dividend, we're done, so return +	} +	.falign +1: +	{ +		p0 = cmp.gtu(r13:12,r3:2)   // set predicate reg if shifted divisor > current remainder +	} +	{ +		r7:6 = sub(r3:2, r13:12)    // subtract shifted divisor from current remainder +		r9:8 = add(r1:0, r15:14)    // save current quotient to temp (r9:8) +	} +	{ +		r1:0 = vmux(p0, r1:0, r9:8) // choose either current quotient or new quotient (r9:8) +		r3:2 = vmux(p0, r3:2, r7:6) // choose either current remainder or new remainder (r7:6) +	} +	{ +		r15:14 = lsr(r15:14, #1)    // shift bit right by 1 for next iteration +		r13:12 = lsr(r13:12, #1)    // shift "shifted divisor" right by 1 for next iteration +	}:endloop0 + +.hexagon_divdi3_return: +	{ +		r3:2 = neg(r1:0) +	} +	{ +		r1:0 = vmux(p3,r3:2,r1:0) +		jumpr r31 +	} +FUNCTION_END __hexagon_divdi3 + +  .globl __qdsp_divdi3 +  .set   __qdsp_divdi3, __hexagon_divdi3 diff --git a/lib/builtins/hexagon/divsi3.S b/lib/builtins/hexagon/divsi3.S new file mode 100644 index 0000000000000..8e159baa192f7 --- /dev/null +++ b/lib/builtins/hexagon/divsi3.S @@ -0,0 +1,84 @@ +//===----------------------Hexagon builtin routine ------------------------===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + + + +	.macro FUNCTION_BEGIN name +	.text +        .p2align 5 +	.globl \name +	.type  \name, @function +\name: +	.endm + +	.macro FUNCTION_END name +	.size  \name, . - \name +	.endm + + +FUNCTION_BEGIN __hexagon_divsi3 +	{ +		p0 = cmp.ge(r0,#0) +		p1 = cmp.ge(r1,#0) +		r1 = abs(r0) +		r2 = abs(r1) +	} +	{ +		r3 = cl0(r1) +		r4 = cl0(r2) +		r5 = sub(r1,r2) +		p2 = cmp.gtu(r2,r1) +	} +#if (__HEXAGON_ARCH__ == 60) +	{ +		r0 = #0 +		p1 = xor(p0,p1) +		p0 = cmp.gtu(r2,r5) +	} +		if (p2) jumpr r31 +#else +	{ +		r0 = #0 +		p1 = xor(p0,p1) +		p0 = cmp.gtu(r2,r5) +		if (p2) jumpr r31 +	} +#endif +	{ +		r0 = mux(p1,#-1,#1) +		if (p0) jumpr r31 +		r4 = sub(r4,r3) +		r3 = #1 +	} +	{ +		r0 = #0 +		r3:2 = vlslw(r3:2,r4) +		loop0(1f,r4) +	} +	.falign +1: +	{ +		p0 = cmp.gtu(r2,r1) +		if (!p0.new) r1 = sub(r1,r2) +		if (!p0.new) r0 = add(r0,r3) +		r3:2 = vlsrw(r3:2,#1) +	}:endloop0 +	{ +		p0 = cmp.gtu(r2,r1) +		if (!p0.new) r0 = add(r0,r3) +		if (!p1) jumpr r31 +	} +	{ +		r0 = neg(r0) +		jumpr r31 +	} +FUNCTION_END __hexagon_divsi3 + +  .globl __qdsp_divsi3 +  .set   __qdsp_divsi3, __hexagon_divsi3 diff --git a/lib/builtins/hexagon/fabs_opt.S b/lib/builtins/hexagon/fabs_opt.S new file mode 100644 index 0000000000000..b09b00734d988 --- /dev/null +++ b/lib/builtins/hexagon/fabs_opt.S @@ -0,0 +1,37 @@ +//===----------------------Hexagon builtin routine ------------------------===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +.macro FUNCTION_BEGIN name +.text +.p2align 5 +.globl \name +.type  \name, @function +\name: +.endm + +.macro FUNCTION_END name +.size  \name, . - \name +.endm + +FUNCTION_BEGIN fabs +  { +    r1 = clrbit(r1, #31) +    jumpr r31 +  } +FUNCTION_END fabs + +FUNCTION_BEGIN fabsf +  { +    r0 = clrbit(r0, #31) +    jumpr r31 +  } +FUNCTION_END fabsf + +  .globl fabsl +  .set fabsl, fabs diff --git a/lib/builtins/hexagon/fastmath2_dlib_asm.S b/lib/builtins/hexagon/fastmath2_dlib_asm.S new file mode 100644 index 0000000000000..9286df06c26d1 --- /dev/null +++ b/lib/builtins/hexagon/fastmath2_dlib_asm.S @@ -0,0 +1,491 @@ +//===----------------------Hexagon builtin routine ------------------------===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/* ==================================================================== */ +/*   FUNCTIONS Optimized double floating point operators                */ +/* ==================================================================== */ +/*      c = dadd_asm(a, b)                                              */ +/* ==================================================================== * +fast2_QDOUBLE fast2_dadd(fast2_QDOUBLE a,fast2_QDOUBLE b) { +      fast2_QDOUBLE c; +      lint manta = a & MANTMASK; +      int  expa  = Q6_R_sxth_R(a) ; +      lint mantb = b & MANTMASK; +      int  expb  = Q6_R_sxth_R(b) ; +      int  exp, expdiff, j, k, hi, lo, cn; +      lint mant; + +        expdiff = (int) Q6_P_vabsdiffh_PP(a, b); +        expdiff = Q6_R_sxth_R(expdiff) ; +        if (expdiff > 63) { expdiff = 62;} +        if (expa > expb) { +          exp = expa + 1; +          expa = 1; +          expb = expdiff + 1; +        } else { +          exp = expb + 1; +          expb = 1; +          expa = expdiff + 1; +        } +        mant = (manta>>expa) + (mantb>>expb); + +        hi = (int) (mant>>32); +        lo = (int) (mant); + +        k =  Q6_R_normamt_R(hi); +        if(hi == 0 || hi == -1) k = 31+Q6_R_normamt_R(lo); + +        mant = (mant << k); +        cn  = (mant == 0x8000000000000000LL); +        exp = exp - k + cn; + +        if (mant ==  0 || mant == -1)  exp = 0x8001; +        c = (mant & MANTMASK) | (((lint) exp) & EXP_MASK); +      return(c); + } + * ==================================================================== */ +        .text +        .global fast2_dadd_asm +        .type fast2_dadd_asm, @function +fast2_dadd_asm: +#define manta      R0 +#define mantexpa   R1:0 +#define lmanta     R1:0 +#define mantb      R2 +#define mantexpb   R3:2 +#define lmantb     R3:2 +#define expa       R4 +#define expb       R5 +#define mantexpd   R7:6 +#define expd       R6 +#define exp        R8 +#define c63        R9 +#define lmant      R1:0 +#define manth      R1 +#define mantl      R0 +#define minmin     R11:10  // exactly 0x000000000000008001LL +#define minminl    R10 +#define k          R4 +#define ce         P0 +        .falign +      { +        mantexpd = VABSDIFFH(mantexpa, mantexpb) //represented as 0x08001LL +        c63 = #62 +        expa = SXTH(manta) +        expb = SXTH(mantb) +      } { +        expd = SXTH(expd) +        ce = CMP.GT(expa, expb); +        if ( ce.new) exp = add(expa, #1) +        if (!ce.new) exp = add(expb, #1) +      } { +        if ( ce) expa = #1 +        if (!ce) expb = #1 +        manta.L = #0 +        expd = MIN(expd, c63) +      } { +        if (!ce) expa = add(expd, #1) +        if ( ce) expb = add(expd, #1) +        mantb.L = #0 +        minmin = #0 +      } { +        lmanta = ASR(lmanta, expa) +        lmantb = ASR(lmantb, expb) +      } { +        lmant = add(lmanta, lmantb) +        minminl.L = #0x8001 +      } { +        k  = clb(lmant) +        c63 = #58 +      } { +        k = add(k, #-1) +        p0 = cmp.gt(k, c63) +      } { +        mantexpa = ASL(lmant, k) +        exp = SUB(exp, k) +        if(p0) jump .Ldenorma +      } { +        manta = insert(exp, #16, #0) +        jumpr  r31 +      } +.Ldenorma: +      { +        mantexpa = minmin +        jumpr  r31 +      } +/* =================================================================== * + fast2_QDOUBLE fast2_dsub(fast2_QDOUBLE a,fast2_QDOUBLE b) { +      fast2_QDOUBLE c; +      lint manta = a & MANTMASK; +      int  expa  = Q6_R_sxth_R(a) ; +      lint mantb = b & MANTMASK; +      int  expb  = Q6_R_sxth_R(b) ; +      int  exp, expdiff, j, k; +      lint mant; + +        expdiff = (int) Q6_P_vabsdiffh_PP(a, b); +        expdiff = Q6_R_sxth_R(expdiff) ; +        if (expdiff > 63) { expdiff = 62;} +        if (expa > expb) { +          exp = expa + 1; +          expa = 1; +          expb = expdiff + 1; +        } else { +          exp = expb + 1; +          expb = 1; +          expa = expdiff + 1; +        } +        mant = (manta>>expa) - (mantb>>expb); +        k =  Q6_R_clb_P(mant)-1; +        mant = (mant << k); +        exp = exp - k; +        if (mant ==  0 || mant == -1)  exp = 0x8001; +        c = (mant & MANTMASK) | (((lint) exp) & EXP_MASK); +      return(c); + } + * ==================================================================== */ +        .text +        .global fast2_dsub_asm +        .type fast2_dsub_asm, @function +fast2_dsub_asm: + +#define manta      R0 +#define mantexpa   R1:0 +#define lmanta     R1:0 +#define mantb      R2 +#define mantexpb   R3:2 +#define lmantb     R3:2 +#define expa       R4 +#define expb       R5 +#define mantexpd   R7:6 +#define expd       R6 +#define exp        R8 +#define c63        R9 +#define lmant      R1:0 +#define manth      R1 +#define mantl      R0 +#define minmin     R11:10  // exactly 0x000000000000008001LL +#define minminl    R10 +#define k          R4 +#define ce         P0 +        .falign +      { +        mantexpd = VABSDIFFH(mantexpa, mantexpb) //represented as 0x08001LL +        c63 = #62 +        expa = SXTH(manta) +        expb = SXTH(mantb) +      } { +        expd = SXTH(expd) +        ce = CMP.GT(expa, expb); +        if ( ce.new) exp = add(expa, #1) +        if (!ce.new) exp = add(expb, #1) +      } { +        if ( ce) expa = #1 +        if (!ce) expb = #1 +        manta.L = #0 +        expd = MIN(expd, c63) +      } { +        if (!ce) expa = add(expd, #1) +        if ( ce) expb = add(expd, #1) +        mantb.L = #0 +        minmin = #0 +      } { +        lmanta = ASR(lmanta, expa) +        lmantb = ASR(lmantb, expb) +      } { +        lmant = sub(lmanta, lmantb) +        minminl.L = #0x8001 +      } { +        k  = clb(lmant) +        c63 = #58 +      } { +        k = add(k, #-1) +        p0 = cmp.gt(k, c63) +      } { +        mantexpa = ASL(lmant, k) +        exp = SUB(exp, k) +        if(p0) jump .Ldenorm +      } { +        manta = insert(exp, #16, #0) +        jumpr  r31 +      } +.Ldenorm: +      { +        mantexpa = minmin +        jumpr  r31 +      } +/* ==================================================================== * + fast2_QDOUBLE fast2_dmpy(fast2_QDOUBLE a,fast2_QDOUBLE b) { +        fast2_QDOUBLE c; +        lint manta = a & MANTMASK; +        int  expa  = Q6_R_sxth_R(a) ; +        lint mantb = b & MANTMASK; +        int  expb  = Q6_R_sxth_R(b) ; +        int exp, k; +        lint mant; +        int          hia, hib, hi, lo; +        unsigned int loa, lob; + +        hia = (int)(a >> 32); +        loa = Q6_R_extractu_RII((int)manta, 31, 1); +        hib = (int)(b >> 32); +        lob = Q6_R_extractu_RII((int)mantb, 31, 1); + +        mant = Q6_P_mpy_RR(hia, lob); +        mant = Q6_P_mpyacc_RR(mant,hib, loa); +        mant = (mant >> 30) + (Q6_P_mpy_RR(hia, hib)<<1); + +        hi = (int) (mant>>32); + +        k =  Q6_R_normamt_R(hi); +        mant = mant << k; +        exp = expa + expb - k; +        if (mant ==  0 || mant == -1)  exp = 0x8001; +        c = (mant & MANTMASK) | (((lint) exp) & EXP_MASK); +        return(c); + } + * ==================================================================== */ +        .text +        .global fast2_dmpy_asm +        .type fast2_dmpy_asm, @function +fast2_dmpy_asm: + +#define mantal     R0 +#define mantah     R1 +#define mantexpa   R1:0 +#define mantbl     R2 +#define mantbh     R3 +#define mantexpb   R3:2 +#define expa       R4 +#define expb       R5 +#define c8001      R12 +#define mantexpd   R7:6 +#define mantdh     R7 +#define exp        R8 +#define lmantc     R11:10 +#define kb         R9 +#define guard      R11 +#define mantal_    R12 +#define mantbl_    R13 +#define min        R15:14 +#define minh       R15 + +        .falign +      { +        mantbl_= lsr(mantbl, #16) +        expb = sxth(mantbl) +        expa = sxth(mantal) +        mantal_= lsr(mantal, #16) +      } +      { +        lmantc = mpy(mantah, mantbh) +        mantexpd = mpy(mantah, mantbl_) +        mantal.L = #0x0 +        min = #0 +      } +      { +        lmantc = add(lmantc, lmantc) +        mantexpd+= mpy(mantbh, mantal_) +        mantbl.L = #0x0 +        minh.H = #0x8000 +      } +      { +        mantexpd = asr(mantexpd, #15) +        c8001.L =  #0x8001 +        p1 = cmp.eq(mantexpa, mantexpb) +      } +      { +        mantexpd = add(mantexpd, lmantc) +        exp = add(expa, expb) +        p2 = cmp.eq(mantexpa, min) +      } +      { +        kb  = clb(mantexpd) +        mantexpb = abs(mantexpd) +        guard = #58 +      } +      { +        p1 = and(p1, p2) +        exp = sub(exp, kb) +        kb = add(kb, #-1) +	p0 = cmp.gt(kb, guard) +      } +      { +        exp = add(exp, #1) +        mantexpa = asl(mantexpd, kb) +        if(p1) jump .Lsat   //rarely happens +      } +      { +        mantal = insert(exp,#16, #0) +        if(!p0) jumpr  r31 +      } +      { +        mantal = insert(c8001,#16, #0) +        jumpr  r31 +      } +.Lsat: +      { +        mantexpa = #-1 +      } +      { +        mantexpa = lsr(mantexpa, #1) +      } +      { +        mantal = insert(exp,#16, #0) +        jumpr  r31 +      } + +/* ==================================================================== * + int fast2_qd2f(fast2_QDOUBLE a) { +        int exp; +        long long int manta; +        int ic, rnd, mantb; + +        manta = a>>32; +        exp = Q6_R_sxth_R(a) ; +        ic = 0x80000000 & manta; +        manta = Q6_R_abs_R_sat(manta); +        mantb = (manta + rnd)>>7; +        rnd = 0x40 +        exp = (exp + 126); +        if((manta & 0xff) == rnd) rnd = 0x00; +        if((manta & 0x7fffffc0) == 0x7fffffc0) { +           manta = 0x0; exp++; +        } else { +           manta= mantb & 0x007fffff; +        } +        exp = (exp << 23) & 0x7fffffc0; +        ic = Q6_R_addacc_RR(ic, exp, manta); +        return (ic); + } + * ==================================================================== */ + +        .text +        .global fast2_qd2f_asm +        .type fast2_qd2f_asm, @function +fast2_qd2f_asm: +#define mantah   R1 +#define mantal   R0 +#define cff      R0 +#define mant     R3 +#define expo     R4 +#define rnd      R5 +#define mask     R6 +#define c07f     R7 +#define c80      R0 +#define mantb    R2 +#define ic       R0 + +      .falign +     { +       mant = abs(mantah):sat +       expo = sxth(mantal) +       rnd = #0x40 +       mask.L = #0xffc0 +     } +     { +       cff = extractu(mant, #8, #0) +       p2 = cmp.gt(expo, #126) +       p3 = cmp.ge(expo, #-126) +       mask.H = #0x7fff +     } +     { +       p1 = cmp.eq(cff,#0x40) +       if(p1.new) rnd = #0 +       expo = add(expo, #126) +       if(!p3) jump .Lmin +     } +     { +       p0 = bitsset(mant, mask) +       c80.L = #0x0000 +       mantb = add(mant, rnd) +       c07f = lsr(mask, #8) +     } +     { +       if(p0) expo = add(expo, #1) +       if(p0) mant = #0 +       mantb = lsr(mantb, #7) +       c80.H = #0x8000 +     } +     { +       ic = and(c80, mantah) +       mask &= asl(expo, #23) +       if(!p0) mant = and(mantb, c07f) +       if(p2) jump .Lmax +     } +     { +       ic += add(mask, mant) +       jumpr r31 +     } +.Lmax: +     { +       ic.L = #0xffff; +     } +     { +       ic.H = #0x7f7f; +       jumpr r31 +     } +.Lmin: +     { +       ic = #0x0 +       jumpr r31 +     } + +/* ==================================================================== * +fast2_QDOUBLE fast2_f2qd(int ia) { +        lint exp; +        lint mant; +        fast2_QDOUBLE c; + +        mant = ((ia << 7) | 0x40000000)&0x7fffff80 ; +        if (ia & 0x80000000) mant = -mant; +        exp =  ((ia >> 23) & 0xFFLL) - 126; +        c = (mant<<32) | Q6_R_zxth_R(exp);; +        return(c); +} + * ==================================================================== */ +        .text +        .global fast2_f2qd_asm +        .type fast2_f2qd_asm, @function +fast2_f2qd_asm: +#define ia    R0 +#define mag   R3 +#define mantr R1 +#define expr  R0 +#define zero  R2 +#define maxneg R5:4 +#define maxnegl R4 +        .falign +  { +       mantr = asl(ia, #7) +       p0 = tstbit(ia, #31) +       maxneg = #0 +       mag = add(ia,ia) +  } +  { +       mantr = setbit(mantr, #30) +       expr= extractu(ia,#8,#23) +       maxnegl.L = #0x8001 +       p1 = cmp.eq(mag, #0) +  } +  { +       mantr= extractu(mantr, #31, #0) +       expr= add(expr, #-126) +       zero = #0 +       if(p1) jump .Lminqd +  } +  { +       expr = zxth(expr) +       if(p0) mantr= sub(zero, mantr) +       jumpr r31 +  } +.Lminqd: +  { +       R1:0 = maxneg +       jumpr r31 +  } diff --git a/lib/builtins/hexagon/fastmath2_ldlib_asm.S b/lib/builtins/hexagon/fastmath2_ldlib_asm.S new file mode 100644 index 0000000000000..4192555351a6b --- /dev/null +++ b/lib/builtins/hexagon/fastmath2_ldlib_asm.S @@ -0,0 +1,345 @@ +//===----------------------Hexagon builtin routine ------------------------===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/* ==================================================================== * + +fast2_QLDOUBLE fast2_ldadd(fast2_QLDOUBLE a,fast2_QLDOUBLE b) { +      fast2_QLDOUBLE c; +      lint manta = a & MANTMASK; +      int  expa  = Q6_R_sxth_R(a) ; +      lint mantb = b & MANTMASK; +      int  expb  = Q6_R_sxth_R(b) ; +      int  exp, expdiff, j, k, hi, lo, cn; +      lint mant; + +        expdiff = (int) Q6_P_vabsdiffh_PP(a, b); +        expdiff = Q6_R_sxth_R(expdiff) ; +        if (expdiff > 63) { expdiff = 62;} +        if (expa > expb) { +          exp = expa + 1; +          expa = 1; +          expb = expdiff + 1; +        } else { +          exp = expb + 1; +          expb = 1; +          expa = expdiff + 1; +        } +        mant = (manta>>expa) + (mantb>>expb); + +        hi = (int) (mant>>32); +        lo = (int) (mant); + +        k =  Q6_R_normamt_R(hi); +        if(hi == 0 || hi == -1) k = 31+Q6_R_normamt_R(lo); + +        mant = (mant << k); +        cn  = (mant == 0x8000000000000000LL); +        exp = exp - k + cn; + +        if (mant ==  0 || mant == -1)  exp = 0x8001; +        c = (mant & MANTMASK) | (((lint) exp) & EXP_MASK); +      return(c); + } + * ==================================================================== */ +        .text +        .global fast2_ldadd_asm +        .type fast2_ldadd_asm, @function +fast2_ldadd_asm: +#define manta      R1:0 +#define lmanta     R1:0 +#define mantb      R3:2 +#define lmantb     R3:2 +#define expa       R4 +#define expb       R5 +#define expd       R6 +#define exp        R8 +#define c63        R9 +#define lmant      R1:0 +#define k          R4 +#define ce         P0 +#define zero       R3:2 +        .falign +      { +        expa = memw(r29+#8) +        expb = memw(r29+#24) +        r7 = r0 +      } +      { +        expd = sub(expa, expb):sat +        ce = CMP.GT(expa, expb); +        if ( ce.new) exp = add(expa, #1) +        if (!ce.new) exp = add(expb, #1) +      } { +        expd = abs(expd):sat +        if ( ce) expa = #1 +        if (!ce) expb = #1 +        c63 = #62 +      } { +        expd = MIN(expd, c63) +        manta = memd(r29+#0) +        mantb = memd(r29+#16) +      } { +        if (!ce) expa = add(expd, #1) +        if ( ce) expb = add(expd, #1) +      } { +        lmanta = ASR(lmanta, expa) +        lmantb = ASR(lmantb, expb) +      } { +        lmant = add(lmanta, lmantb) +        zero = #0 +      } { +        k  = clb(lmant) +        c63.L =#0x0001 +      } { +        exp -= add(k, #-1)  //exp =  exp - (k-1) +        k = add(k, #-1) +        p0 = cmp.gt(k, #58) +        c63.H =#0x8000 +      } { +        if(!p0)memw(r7+#8) = exp +        lmant = ASL(lmant, k) +        if(p0) jump .Ldenorma +      } { +        memd(r7+#0) = lmant +        jumpr  r31 +      } +.Ldenorma: +        memd(r7+#0) = zero +      { +        memw(r7+#8) = c63 +        jumpr  r31 +      } +/* =================================================================== * + fast2_QLDOUBLE fast2_ldsub(fast2_QLDOUBLE a,fast2_QLDOUBLE b) { +      fast2_QLDOUBLE c; +      lint manta = a & MANTMASK; +      int  expa  = Q6_R_sxth_R(a) ; +      lint mantb = b & MANTMASK; +      int  expb  = Q6_R_sxth_R(b) ; +      int  exp, expdiff, j, k; +      lint mant; + +        expdiff = (int) Q6_P_vabsdiffh_PP(a, b); +        expdiff = Q6_R_sxth_R(expdiff) ; +        if (expdiff > 63) { expdiff = 62;} +        if (expa > expb) { +          exp = expa + 1; +          expa = 1; +          expb = expdiff + 1; +        } else { +          exp = expb + 1; +          expb = 1; +          expa = expdiff + 1; +        } +        mant = (manta>>expa) - (mantb>>expb); +        k =  Q6_R_clb_P(mant)-1; +        mant = (mant << k); +        exp = exp - k; +        if (mant ==  0 || mant == -1)  exp = 0x8001; +        c = (mant & MANTMASK) | (((lint) exp) & EXP_MASK); +      return(c); + } + * ==================================================================== */ +        .text +        .global fast2_ldsub_asm +        .type fast2_ldsub_asm, @function +fast2_ldsub_asm: +#define manta      R1:0 +#define lmanta     R1:0 +#define mantb      R3:2 +#define lmantb     R3:2 +#define expa       R4 +#define expb       R5 +#define expd       R6 +#define exp        R8 +#define c63        R9 +#define lmant      R1:0 +#define k          R4 +#define ce         P0 +#define zero       R3:2 +        .falign +      { +        expa = memw(r29+#8) +        expb = memw(r29+#24) +        r7 = r0 +      } +      { +        expd = sub(expa, expb):sat +        ce = CMP.GT(expa, expb); +        if ( ce.new) exp = add(expa, #1) +        if (!ce.new) exp = add(expb, #1) +      } { +        expd = abs(expd):sat +        if ( ce) expa = #1 +        if (!ce) expb = #1 +        c63 = #62 +      } { +        expd = min(expd, c63) +        manta = memd(r29+#0) +        mantb = memd(r29+#16) +      } { +        if (!ce) expa = add(expd, #1) +        if ( ce) expb = add(expd, #1) +      } { +        lmanta = ASR(lmanta, expa) +        lmantb = ASR(lmantb, expb) +      } { +        lmant = sub(lmanta, lmantb) +        zero = #0 +      } { +        k  = clb(lmant) +        c63.L =#0x0001 +      } { +        exp -= add(k, #-1)  //exp =  exp - (k+1) +        k = add(k, #-1) +        p0 = cmp.gt(k, #58) +        c63.H =#0x8000 +      } { +        if(!p0)memw(r7+#8) = exp +        lmant = asl(lmant, k) +        if(p0) jump .Ldenorma_s +      } { +        memd(r7+#0) = lmant +        jumpr  r31 +      } +.Ldenorma_s: +        memd(r7+#0) = zero +      { +        memw(r7+#8) = c63 +        jumpr  r31 +      } + +/* ==================================================================== * + fast2_QLDOUBLE fast2_ldmpy(fast2_QLDOUBLE a,fast2_QLDOUBLE b) { +        fast2_QLDOUBLE c; +        lint manta = a & MANTMASK; +        int  expa  = Q6_R_sxth_R(a) ; +        lint mantb = b & MANTMASK; +        int  expb  = Q6_R_sxth_R(b) ; +        int exp, k; +        lint mant; +        int          hia, hib, hi, lo; +        unsigned int loa, lob; + +        hia = (int)(a >> 32); +        loa = Q6_R_extractu_RII((int)manta, 31, 1); +        hib = (int)(b >> 32); +        lob = Q6_R_extractu_RII((int)mantb, 31, 1); + +        mant = Q6_P_mpy_RR(hia, lob); +        mant = Q6_P_mpyacc_RR(mant,hib, loa); +        mant = (mant >> 30) + (Q6_P_mpy_RR(hia, hib)<<1); + +        hi = (int) (mant>>32); + +        k =  Q6_R_normamt_R(hi); +        mant = mant << k; +        exp = expa + expb - k; +        if (mant ==  0 || mant == -1)  exp = 0x8001; +        c = (mant & MANTMASK) | (((lint) exp) & EXP_MASK); +        return(c); + } + * ==================================================================== */ +        .text +        .global fast2_ldmpy_asm +        .type fast2_ldmpy_asm, @function +fast2_ldmpy_asm: + +#define mantxl_    R9 +#define mantxl     R14 +#define mantxh     R15 +#define mantx      R15:14 +#define mantbl     R2 +#define mantbl_    R8 +#define mantbh     R3 +#define mantb      R3:2 +#define expa       R4 +#define expb       R5 +#define c8001      R8 +#define mantd      R7:6 +#define lmantc     R11:10 +#define kp         R9 +#define min        R13:12 +#define minh       R13 +#define max        R13:12 +#define maxh       R13 +#define ret        R0 + +        .falign +      { +        mantx = memd(r29+#0) +        mantb = memd(r29+#16) +        min = #0 +      } +      { +        mantbl_= extractu(mantbl, #31, #1) +        mantxl_= extractu(mantxl, #31, #1) +        minh.H = #0x8000 +      } +      { +        lmantc = mpy(mantxh, mantbh) +        mantd = mpy(mantxh, mantbl_) +        expa = memw(r29+#8) +        expb = memw(r29+#24) +      } +      { +        lmantc = add(lmantc, lmantc) +        mantd += mpy(mantbh, mantxl_) +      } +      { +        mantd = asr(mantd, #30) +        c8001.L =  #0x0001 +        p1 = cmp.eq(mantx, mantb) +      } +      { +        mantd = add(mantd, lmantc) +        expa= add(expa, expb) +        p2 = cmp.eq(mantb, min) +      } +      { +        kp  = clb(mantd) +        c8001.H =  #0x8000 +        p1 = and(p1, p2) +      } +      { +        expa-= add(kp, #-1) +        kp = add(kp, #-1) +        if(p1) jump .Lsat +      } +      { +        mantd = asl(mantd, kp) +        memw(ret+#8) = expa +	p0 = cmp.gt(kp, #58) +        if(p0.new) jump:NT .Ldenorm   //rarely happens +      } +      { +        memd(ret+#0) = mantd +        jumpr  r31 +      } +.Lsat: +      { +        max = #0 +        expa+= add(kp, #1) +      } +      { +        maxh.H = #0x4000 +        memw(ret+#8) = expa +      } +      { +        memd(ret+#0) = max +        jumpr  r31 +      } +.Ldenorm: +      { +        memw(ret+#8) = c8001 +        mantx = #0 +      } +      { +        memd(ret+#0) = mantx +        jumpr  r31 +      } diff --git a/lib/builtins/hexagon/fastmath_dlib_asm.S b/lib/builtins/hexagon/fastmath_dlib_asm.S new file mode 100644 index 0000000000000..215936b783ca8 --- /dev/null +++ b/lib/builtins/hexagon/fastmath_dlib_asm.S @@ -0,0 +1,400 @@ +//===----------------------Hexagon builtin routine ------------------------===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/* ==================================================================== */ +/*   FUNCTIONS Optimized double floating point operators                */ +/* ==================================================================== */ +/*      c = dadd_asm(a, b)                                              */ +/* ==================================================================== + +QDOUBLE dadd(QDOUBLE a,QDOUBLE b) { +      QDOUBLE c; +      lint manta = a & MANTMASK; +      int  expa  = HEXAGON_R_sxth_R(a) ; +      lint mantb = b & MANTMASK; +      int  expb  = HEXAGON_R_sxth_R(b) ; +      int  exp, expdiff, j, k, hi, lo, cn; +      lint mant; + +        expdiff = (int) HEXAGON_P_vabsdiffh_PP(a, b); +        expdiff = HEXAGON_R_sxth_R(expdiff) ; +        if (expdiff > 63) { expdiff = 62;} +        if (expa > expb) { +          exp = expa + 1; +          expa = 1; +          expb = expdiff + 1; +        } else { +          exp = expb + 1; +          expb = 1; +          expa = expdiff + 1; +        } +        mant = (manta>>expa) + (mantb>>expb); + +        hi = (int) (mant>>32); +        lo = (int) (mant); + +        k =  HEXAGON_R_normamt_R(hi); +        if(hi == 0 || hi == -1) k =  31+HEXAGON_R_normamt_R(lo); + +        mant = (mant << k); +        cn  = (mant == 0x8000000000000000LL); +        exp = exp - k + cn; + +        if (mant ==  0 || mant == -1)  exp = 0x8001; +        c = (mant & MANTMASK) | (((lint) exp) & EXP_MASK); +      return(c); + } + * ==================================================================== */ +        .text +        .global dadd_asm +        .type dadd_asm, @function +dadd_asm: + +#define manta      R0 +#define mantexpa   R1:0 +#define lmanta     R1:0 +#define mantb      R2 +#define mantexpb   R3:2 +#define lmantb     R3:2 +#define expa       R4 +#define expb       R5 +#define mantexpd   R7:6 +#define expd       R6 +#define exp        R8 +#define c63        R9 +#define lmant      R1:0 +#define manth      R1 +#define mantl      R0 +#define zero       R7:6 +#define zerol      R6 +#define minus      R3:2 +#define minusl     R2 +#define maxneg     R9 +#define minmin     R11:10  // exactly 0x800000000000000000LL +#define minminh    R11 +#define k          R4 +#define kl         R5 +#define ce         P0 +        .falign +      { +        mantexpd = VABSDIFFH(mantexpa, mantexpb) //represented as 0x08001LL +        c63 = #62 +        expa = SXTH(manta) +        expb = SXTH(mantb) +      } { +        expd = SXTH(expd) +        ce = CMP.GT(expa, expb); +        if ( ce.new) exp = add(expa, #1) +        if (!ce.new) exp = add(expb, #1) +      } { +        if ( ce) expa = #1 +        if (!ce) expb = #1 +        manta.L = #0 +        expd = MIN(expd, c63) +      } { +        if (!ce) expa = add(expd, #1) +        if ( ce) expb = add(expd, #1) +        mantb.L = #0 +        zero = #0 +      } { +        lmanta = ASR(lmanta, expa) +        lmantb = ASR(lmantb, expb) +        minmin = #0 +      } { +        lmant = add(lmanta, lmantb) +        minus = #-1 +        minminh.H = #0x8000 +      } { +        k  = NORMAMT(manth) +        kl = NORMAMT(mantl) +        p0 = cmp.eq(manth, zerol) +        p1 = cmp.eq(manth, minusl) +      } { +        p0 = OR(p0, p1) +        if(p0.new) k = add(kl, #31) +        maxneg.H = #0 +      } { +        mantexpa = ASL(lmant, k) +        exp = SUB(exp, k) +        maxneg.L = #0x8001 +      } { +        p0 = cmp.eq(mantexpa, zero) +        p1 = cmp.eq(mantexpa, minus) +        manta.L = #0 +        exp = ZXTH(exp) +      } { +        p2 = cmp.eq(mantexpa, minmin)    //is result 0x80....0 +        if(p2.new) exp = add(exp, #1) +      } +#if (__HEXAGON_ARCH__ == 60) +      { +        p0 = OR(p0, p1) +        if( p0.new) manta = OR(manta,maxneg) +        if(!p0.new) manta = OR(manta,exp) +      } +        jumpr  r31 +#else +      { +        p0 = OR(p0, p1) +        if( p0.new) manta = OR(manta,maxneg) +        if(!p0.new) manta = OR(manta,exp) +        jumpr  r31 +      } +#endif +/* =================================================================== * + QDOUBLE dsub(QDOUBLE a,QDOUBLE b) { +      QDOUBLE c; +      lint manta = a & MANTMASK; +      int  expa  = HEXAGON_R_sxth_R(a) ; +      lint mantb = b & MANTMASK; +      int  expb  = HEXAGON_R_sxth_R(b) ; +      int  exp, expdiff, j, k, hi, lo, cn; +      lint mant; + +        expdiff = (int) HEXAGON_P_vabsdiffh_PP(a, b); +        expdiff = HEXAGON_R_sxth_R(expdiff) ; +        if (expdiff > 63) { expdiff = 62;} +        if (expa > expb) { +          exp = expa + 1; +          expa = 1; +          expb = expdiff + 1; +        } else { +          exp = expb + 1; +          expb = 1; +          expa = expdiff + 1; +        } +        mant = (manta>>expa) - (mantb>>expb); + +        hi = (int) (mant>>32); +        lo = (int) (mant); + +        k =  HEXAGON_R_normamt_R(hi); +        if(hi == 0 || hi == -1) k =  31+HEXAGON_R_normamt_R(lo); + +        mant = (mant << k); +        cn  = (mant == 0x8000000000000000LL); +        exp = exp - k + cn; + +        if (mant ==  0 || mant == -1)  exp = 0x8001; +        c = (mant & MANTMASK) | (((lint) exp) & EXP_MASK); +      return(c); + } + * ==================================================================== */ +        .text +        .global dsub_asm +        .type dsub_asm, @function +dsub_asm: + +#define manta      R0 +#define mantexpa   R1:0 +#define lmanta     R1:0 +#define mantb      R2 +#define mantexpb   R3:2 +#define lmantb     R3:2 +#define expa       R4 +#define expb       R5 +#define mantexpd   R7:6 +#define expd       R6 +#define exp        R8 +#define c63        R9 +#define lmant      R1:0 +#define manth      R1 +#define mantl      R0 +#define zero       R7:6 +#define zerol      R6 +#define minus      R3:2 +#define minusl     R2 +#define maxneg     R9 +#define minmin     R11:10  // exactly 0x800000000000000000LL +#define minminh    R11 +#define k          R4 +#define kl         R5 +#define ce         P0 +        .falign +      { +        mantexpd = VABSDIFFH(mantexpa, mantexpb) //represented as 0x08001LL +        c63 = #62 +        expa = SXTH(manta) +        expb = SXTH(mantb) +      } { +        expd = SXTH(expd) +        ce = CMP.GT(expa, expb); +        if ( ce.new) exp = add(expa, #1) +        if (!ce.new) exp = add(expb, #1) +      } { +        if ( ce) expa = #1 +        if (!ce) expb = #1 +        manta.L = #0 +        expd = MIN(expd, c63) +      } { +        if (!ce) expa = add(expd, #1) +        if ( ce) expb = add(expd, #1) +        mantb.L = #0 +        zero = #0 +      } { +        lmanta = ASR(lmanta, expa) +        lmantb = ASR(lmantb, expb) +        minmin = #0 +      } { +        lmant = sub(lmanta, lmantb) +        minus = #-1 +        minminh.H = #0x8000 +      } { +        k  = NORMAMT(manth) +        kl = NORMAMT(mantl) +        p0 = cmp.eq(manth, zerol) +        p1 = cmp.eq(manth, minusl) +      } { +        p0 = OR(p0, p1) +        if(p0.new) k = add(kl, #31) +        maxneg.H = #0 +      } { +        mantexpa = ASL(lmant, k) +        exp = SUB(exp, k) +        maxneg.L = #0x8001 +      } { +        p0 = cmp.eq(mantexpa, zero) +        p1 = cmp.eq(mantexpa, minus) +        manta.L = #0 +        exp = ZXTH(exp) +      } { +        p2 = cmp.eq(mantexpa, minmin)    //is result 0x80....0 +        if(p2.new) exp = add(exp, #1) +      } +#if (__HEXAGON_ARCH__ == 60) +      { +        p0 = OR(p0, p1) +        if( p0.new) manta = OR(manta,maxneg) +        if(!p0.new) manta = OR(manta,exp) +      } +        jumpr  r31 +#else +      { +        p0 = OR(p0, p1) +        if( p0.new) manta = OR(manta,maxneg) +        if(!p0.new) manta = OR(manta,exp) +        jumpr  r31 +      } +#endif +/* ==================================================================== * + QDOUBLE dmpy(QDOUBLE a,QDOUBLE b) { +        QDOUBLE c; +        lint manta = a & MANTMASK; +        int  expa  = HEXAGON_R_sxth_R(a) ; +        lint mantb = b & MANTMASK; +        int  expb  = HEXAGON_R_sxth_R(b) ; +        int exp, k; +        lint mant; +        int          hia, hib, hi, lo; +        unsigned int loa, lob; + +        hia = (int)(a >> 32); +        loa = HEXAGON_R_extractu_RII((int)manta, 31, 1); +        hib = (int)(b >> 32); +        lob = HEXAGON_R_extractu_RII((int)mantb, 31, 1); + +        mant = HEXAGON_P_mpy_RR(hia, lob); +        mant = HEXAGON_P_mpyacc_RR(mant,hib, loa); +        mant = (mant >> 30) + (HEXAGON_P_mpy_RR(hia, hib)<<1); + +        hi = (int) (mant>>32); +        lo = (int) (mant); + +        k =  HEXAGON_R_normamt_R(hi); +        if(hi == 0 || hi == -1) k =  31+HEXAGON_R_normamt_R(lo); +        mant = mant << k; +        exp = expa + expb - k; +        if (mant ==  0 || mant == -1)  exp = 0x8001; +        c = (mant & MANTMASK) | (((lint) exp) & EXP_MASK); +        return(c); + } + * ==================================================================== */ +        .text +        .global dmpy_asm +        .type dmpy_asm, @function +dmpy_asm: + +#define mantal     R0 +#define mantah     R1 +#define mantexpa   R1:0 +#define mantbl     R2 +#define mantbh     R3 +#define mantexpb   R3:2 +#define expa       R4 +#define expb       R5 +#define mantexpd   R7:6 +#define exp        R8 +#define lmantc     R11:10 +#define mantch     R11 +#define mantcl     R10 +#define zero0      R7:6 +#define zero0l     R6 +#define minus1     R3:2 +#define minus1l    R2 +#define maxneg     R9 +#define k          R4 +#define kl         R5 + +        .falign +      { +        mantbl = lsr(mantbl, #16) +        mantal = lsr(mantal, #16) +        expa = sxth(mantal) +        expb = sxth(mantbl) +      } +      { +        lmantc = mpy(mantah, mantbh) +        mantexpd = mpy(mantah, mantbl) +      } +      { +        lmantc = add(lmantc, lmantc) //<<1 +        mantexpd+= mpy(mantbh, mantal) +      } +      { +        lmantc += asr(mantexpd, #15) +        exp = add(expa, expb) +        zero0 = #0 +        minus1 = #-1 +      } +      { +        k  = normamt(mantch) +        kl = normamt(mantcl) +        p0 = cmp.eq(mantch, zero0l) +        p1 = cmp.eq(mantch, minus1l) +      } +      { +        p0 = or(p0, p1) +        if(p0.new) k = add(kl, #31) +        maxneg.H = #0 +      } +      { +        mantexpa = asl(lmantc, k) +        exp = sub(exp, k) +        maxneg.L = #0x8001 +      } +      { +        p0 = cmp.eq(mantexpa, zero0) +        p1 = cmp.eq(mantexpa, minus1) +        mantal.L = #0 +        exp = zxth(exp) +      } +#if (__HEXAGON_ARCH__ == 60) +      { +        p0 = or(p0, p1) +        if( p0.new) mantal = or(mantal,maxneg) +        if(!p0.new) mantal = or(mantal,exp) +      } +        jumpr  r31 +#else +      { +        p0 = or(p0, p1) +        if( p0.new) mantal = or(mantal,maxneg) +        if(!p0.new) mantal = or(mantal,exp) +        jumpr  r31 +      } +#endif diff --git a/lib/builtins/hexagon/fma_opt.S b/lib/builtins/hexagon/fma_opt.S new file mode 100644 index 0000000000000..12378f0da04e5 --- /dev/null +++ b/lib/builtins/hexagon/fma_opt.S @@ -0,0 +1,31 @@ +//===----------------------Hexagon builtin routine ------------------------===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +.macro FUNCTION_BEGIN name +.text +.p2align 5 +.globl \name +.type  \name, @function +\name: +.endm + +.macro FUNCTION_END name +.size  \name, . - \name +.endm + +FUNCTION_BEGIN fmaf +  r2 += sfmpy(r0, r1) +  { +    r0 = r2 +    jumpr r31 +  } +FUNCTION_END fmaf + +  .globl fmal +  .set fmal, fma diff --git a/lib/builtins/hexagon/fmax_opt.S b/lib/builtins/hexagon/fmax_opt.S new file mode 100644 index 0000000000000..f3a218c9769b3 --- /dev/null +++ b/lib/builtins/hexagon/fmax_opt.S @@ -0,0 +1,30 @@ +//===----------------------Hexagon builtin routine ------------------------===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +.macro FUNCTION_BEGIN name +.text +.p2align 5 +.globl \name +.type  \name, @function +\name: +.endm + +.macro FUNCTION_END name +.size  \name, . - \name +.endm + +FUNCTION_BEGIN fmaxf +  { +    r0 = sfmax(r0, r1) +    jumpr r31 +  } +FUNCTION_END fmaxf + +  .globl fmaxl +  .set fmaxl, fmax diff --git a/lib/builtins/hexagon/fmin_opt.S b/lib/builtins/hexagon/fmin_opt.S new file mode 100644 index 0000000000000..ef9b0ff854a21 --- /dev/null +++ b/lib/builtins/hexagon/fmin_opt.S @@ -0,0 +1,30 @@ +//===----------------------Hexagon builtin routine ------------------------===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +.macro FUNCTION_BEGIN name +.text +.p2align 5 +.globl \name +.type  \name, @function +\name: +.endm + +.macro FUNCTION_END name +.size  \name, . - \name +.endm + +FUNCTION_BEGIN fminf +  { +    r0 = sfmin(r0, r1) +    jumpr r31 +  } +FUNCTION_END fminf + +  .globl fminl +  .set fminl, fmin diff --git a/lib/builtins/hexagon/memcpy_forward_vp4cp4n2.S b/lib/builtins/hexagon/memcpy_forward_vp4cp4n2.S new file mode 100644 index 0000000000000..fbe09086cd338 --- /dev/null +++ b/lib/builtins/hexagon/memcpy_forward_vp4cp4n2.S @@ -0,0 +1,125 @@ +//===----------------------Hexagon builtin routine ------------------------===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// An optimized version of a memcpy which is equivalent to the following loop: +// +//   volatile unsigned *dest; +//   unsigned *src; +// +//   for (i = 0; i < num_words; ++i) +//     *dest++ = *src++; +// +// The corresponding C prototype for this function would be +// void hexagon_memcpy_forward_vp4cp4n2(volatile unsigned *dest, +//                                      const unsigned *src, +//                                      unsigned num_words); +// +// *** Both dest and src must be aligned to 32-bit boundaries. *** +// The code does not perform any runtime checks for this, and will fail +// in bad ways if this requirement is not met. +// +// The "forward" in the name refers to the fact that the function copies +// the words going forward in memory.  It is incorrect to use this function +// for cases where the original code copied words in any other order. +// +// *** This function is only for the use by the compiler. *** +// The only indended use is for the LLVM compiler to generate calls to +// this function, when a mem-copy loop, like the one above, is detected. + +  .text + +// Inputs: +//   r0: dest +//   r1: src +//   r2: num_words + +  .globl  hexagon_memcpy_forward_vp4cp4n2 +  .balign 32 +  .type   hexagon_memcpy_forward_vp4cp4n2,@function +hexagon_memcpy_forward_vp4cp4n2: + +    // Compute r3 to be the number of words remaining in the current page. +    // At the same time, compute r4 to be the number of 32-byte blocks +    // remaining in the page (for prefetch). +  { +    r3 = sub(##4096, r1) +    r5 = lsr(r2, #3) +  } +  { +    // The word count before end-of-page is in the 12 lowest bits of r3. +    // (If the address in r1 was already page-aligned, the bits are 0.) +    r3 = extractu(r3, #10, #2) +    r4 = extractu(r3, #7, #5) +  } +  { +    r3 = minu(r2, r3) +    r4 = minu(r5, r4) +  } +  { +    r4 = or(r4, ##2105344)      // 2105344 = 0x202000 +    p0 = cmp.eq(r3, #0) +    if (p0.new) jump:nt .Lskipprolog +  } +    l2fetch(r1, r4) +  { +    loop0(.Lprolog, r3) +    r2 = sub(r2, r3)            // r2 = number of words left after the prolog. +  } +  .falign +.Lprolog: +  { +    r4 = memw(r1++#4) +    memw(r0++#4) = r4.new +  } :endloop0 +.Lskipprolog: +  { +    // Let r3 = number of whole pages left (page = 1024 words). +    r3 = lsr(r2, #10) +    if (cmp.eq(r3.new, #0)) jump:nt .Lskipmain +  } +  { +    loop1(.Lout, r3) +    r2 = extractu(r2, #10, #0)  // r2 = r2 & 1023 +    r3 = ##2105472              // r3 = 0x202080 (prefetch info) +  } +    // Iterate over pages. +  .falign +.Lout: +    // Prefetch each individual page. +    l2fetch(r1, r3) +    loop0(.Lpage, #512) +  .falign +.Lpage: +    r5:4 = memd(r1++#8) +  { +    memw(r0++#8) = r4 +    memw(r0+#4) = r5 +  } :endloop0:endloop1 +.Lskipmain: +  { +    r3 = ##2105344              // r3 = 0x202000 (prefetch info) +    r4 = lsr(r2, #3)            // r4 = number of 32-byte blocks remaining. +    p0 = cmp.eq(r2, #0) +    if (p0.new) jumpr:nt r31 +  } +  { +    r3 = or(r3, r4) +    loop0(.Lepilog, r2) +  } +    l2fetch(r1, r3) +  .falign +.Lepilog: +  { +    r4 = memw(r1++#4) +    memw(r0++#4) = r4.new +  } :endloop0 + +    jumpr r31 + +.size hexagon_memcpy_forward_vp4cp4n2, . - hexagon_memcpy_forward_vp4cp4n2 diff --git a/lib/builtins/hexagon/memcpy_likely_aligned.S b/lib/builtins/hexagon/memcpy_likely_aligned.S new file mode 100644 index 0000000000000..bbc85c22db085 --- /dev/null +++ b/lib/builtins/hexagon/memcpy_likely_aligned.S @@ -0,0 +1,64 @@ +//===------------------------- memcopy routines ---------------------------===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + + +	.macro FUNCTION_BEGIN name +	.text +	.p2align 5 +	.globl \name +	.type  \name, @function +\name: +	.endm + +	.macro FUNCTION_END name +	.size  \name, . - \name +	.endm + +FUNCTION_BEGIN __hexagon_memcpy_likely_aligned_min32bytes_mult8bytes +	{ +		p0 = bitsclr(r1,#7) +		p0 = bitsclr(r0,#7) +		if (p0.new) r5:4 = memd(r1) +		r3 = #-3 +	} +	{ +		if (!p0) jump .Lmemcpy_call +		if (p0) memd(r0++#8) = r5:4 +		if (p0) r5:4 = memd(r1+#8) +		r3 += lsr(r2,#3) +	} +	{ +		memd(r0++#8) = r5:4 +		r5:4 = memd(r1+#16) +		r1 = add(r1,#24) +		loop0(1f,r3) +	} +	.falign +1: +	{ +		memd(r0++#8) = r5:4 +		r5:4 = memd(r1++#8) +	}:endloop0 +	{ +		memd(r0) = r5:4 +		r0 -= add(r2,#-8) +		jumpr r31 +	} +FUNCTION_END __hexagon_memcpy_likely_aligned_min32bytes_mult8bytes + +.Lmemcpy_call: +#ifdef __PIC__ +	jump memcpy@PLT +#else +	jump memcpy +#endif + +  .globl __qdsp_memcpy_likely_aligned_min32bytes_mult8bytes +  .set   __qdsp_memcpy_likely_aligned_min32bytes_mult8bytes, \ +         __hexagon_memcpy_likely_aligned_min32bytes_mult8bytes diff --git a/lib/builtins/hexagon/moddi3.S b/lib/builtins/hexagon/moddi3.S new file mode 100644 index 0000000000000..12a0595fe4650 --- /dev/null +++ b/lib/builtins/hexagon/moddi3.S @@ -0,0 +1,83 @@ +//===----------------------Hexagon builtin routine ------------------------===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +	.macro FUNCTION_BEGIN name +	.text +	.p2align 5 +	.globl \name +	.type  \name, @function +\name: +	.endm + +	.macro FUNCTION_END name +	.size  \name, . - \name +	.endm + + +FUNCTION_BEGIN __hexagon_moddi3 +	{ +		p3 = tstbit(r1,#31) +	} +	{ +		r1:0 = abs(r1:0) +		r3:2 = abs(r3:2) +	} +	{ +		r6 = cl0(r1:0)              // count leading 0's of dividend (numerator) +		r7 = cl0(r3:2)              // count leading 0's of divisor (denominator) +		r5:4 = r3:2                 // divisor moved into working registers +		r3:2 = r1:0                 // dividend is the initial remainder, r3:2 contains remainder +	} +	{ +		r10 = sub(r7,r6)            // left shift count for bit & divisor +		r1:0 = #0                   // initialize quotient to 0 +		r15:14 = #1                 // initialize bit to 1 +	} +	{ +		r11 = add(r10,#1)           // loop count is 1 more than shift count +		r13:12 = lsl(r5:4,r10)      // shift divisor msb into same bit position as dividend msb +		r15:14 = lsl(r15:14,r10)    // shift the bit left by same amount as divisor +	} +	{ +		p0 = cmp.gtu(r5:4,r3:2)     // check if divisor > dividend +		loop0(1f,r11)               // register loop +	} +	{ +		if (p0) jump .hexagon_moddi3_return          // if divisor > dividend, we're done, so return +	} +	.falign +1: +	{ +		p0 = cmp.gtu(r13:12,r3:2)   // set predicate reg if shifted divisor > current remainder +	} +	{ +		r7:6 = sub(r3:2, r13:12)    // subtract shifted divisor from current remainder +		r9:8 = add(r1:0, r15:14)    // save current quotient to temp (r9:8) +	} +	{ +		r1:0 = vmux(p0, r1:0, r9:8) // choose either current quotient or new quotient (r9:8) +		r3:2 = vmux(p0, r3:2, r7:6) // choose either current remainder or new remainder (r7:6) +	} +	{ +		r15:14 = lsr(r15:14, #1)    // shift bit right by 1 for next iteration +		r13:12 = lsr(r13:12, #1)    // shift "shifted divisor" right by 1 for next iteration +	}:endloop0 + +.hexagon_moddi3_return: +	{ +		r1:0 = neg(r3:2) +	} +	{ +		r1:0 = vmux(p3,r1:0,r3:2) +		jumpr r31 +	} +FUNCTION_END __hexagon_moddi3 + +  .globl __qdsp_moddi3 +  .set   __qdsp_moddi3, __hexagon_moddi3 diff --git a/lib/builtins/hexagon/modsi3.S b/lib/builtins/hexagon/modsi3.S new file mode 100644 index 0000000000000..5afda9e2978b8 --- /dev/null +++ b/lib/builtins/hexagon/modsi3.S @@ -0,0 +1,66 @@ +//===----------------------Hexagon builtin routine ------------------------===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + + + +	.macro FUNCTION_BEGIN name +	.text +	.p2align 5 +	.globl \name +	.type  \name, @function +\name: +	.endm + +	.macro FUNCTION_END name +	.size  \name, . - \name +	.endm + + +FUNCTION_BEGIN __hexagon_modsi3 +	{ +		p2 = cmp.ge(r0,#0) +		r2 = abs(r0) +		r1 = abs(r1) +	} +	{ +		r3 = cl0(r2) +		r4 = cl0(r1) +		p0 = cmp.gtu(r1,r2) +	} +	{ +		r3 = sub(r4,r3) +		if (p0) jumpr r31 +	} +	{ +		p1 = cmp.eq(r3,#0) +		loop0(1f,r3) +		r0 = r2 +		r2 = lsl(r1,r3) +	} +	.falign +1: +	{ +		p0 = cmp.gtu(r2,r0) +		if (!p0.new) r0 = sub(r0,r2) +		r2 = lsr(r2,#1) +		if (p1) r1 = #0 +	}:endloop0 +	{ +		p0 = cmp.gtu(r2,r0) +		if (!p0.new) r0 = sub(r0,r1) +		if (p2) jumpr r31 +	} +	{ +		r0 = neg(r0) +		jumpr r31 +	} +FUNCTION_END __hexagon_modsi3 + +  .globl __qdsp_modsi3 +  .set   __qdsp_modsi3, __hexagon_modsi3 diff --git a/lib/builtins/hexagon/sfdiv_opt.S b/lib/builtins/hexagon/sfdiv_opt.S new file mode 100644 index 0000000000000..6bdd4808c2b8c --- /dev/null +++ b/lib/builtins/hexagon/sfdiv_opt.S @@ -0,0 +1,66 @@ +//===----------------------Hexagon builtin routine ------------------------===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +	.macro FUNCTION_BEGIN name +	.text +	.p2align 5 +	.globl \name +	.type  \name, @function +\name: +	.endm + +	.macro FUNCTION_END name +	.size  \name, . - \name +	.endm + +#define Q6_ALIAS(TAG) .global __qdsp_##TAG ; .set __qdsp_##TAG, __hexagon_##TAG +#define FAST_ALIAS(TAG) .global __hexagon_fast_##TAG ; .set __hexagon_fast_##TAG, __hexagon_##TAG +#define FAST2_ALIAS(TAG) .global __hexagon_fast2_##TAG ; .set __hexagon_fast2_##TAG, __hexagon_##TAG + +FUNCTION_BEGIN __hexagon_divsf3 +  { +    r2,p0 = sfrecipa(r0,r1) +    r4 = sffixupd(r0,r1) +    r3 = ##0x3f800000   // 1.0 +  } +  { +    r5 = sffixupn(r0,r1) +    r3 -= sfmpy(r4,r2):lib  // 1-(den/recip) yields error? +    r6 = ##0x80000000 +    r7 = r3 +  } +  { +    r2 += sfmpy(r3,r2):lib +    r3 = r7 +    r6 = r5 +    r0 = and(r6,r5) +  } +  { +    r3 -= sfmpy(r4,r2):lib +    r0 += sfmpy(r5,r2):lib +  } +  { +    r2 += sfmpy(r3,r2):lib +    r6 -= sfmpy(r0,r4):lib +  } +  { +    r0 += sfmpy(r6,r2):lib +  } +  { +    r5 -= sfmpy(r0,r4):lib +  } +  { +    r0 += sfmpy(r5,r2,p0):scale +    jumpr r31 +  } +FUNCTION_END __hexagon_divsf3 + +Q6_ALIAS(divsf3) +FAST_ALIAS(divsf3) +FAST2_ALIAS(divsf3) diff --git a/lib/builtins/hexagon/sfsqrt_opt.S b/lib/builtins/hexagon/sfsqrt_opt.S new file mode 100644 index 0000000000000..7f619002774f9 --- /dev/null +++ b/lib/builtins/hexagon/sfsqrt_opt.S @@ -0,0 +1,82 @@ +//===----------------------Hexagon builtin routine ------------------------===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +	.macro FUNCTION_BEGIN name +	.text +	.p2align 5 +	.globl \name +	.type  \name, @function +\name: +	.endm + +	.macro FUNCTION_END name +	.size  \name, . - \name +	.endm + +#define RIN r0 +#define S r0 +#define H r1 +#define D r2 +#define E r3 +#define HALF r4 +#define R r5 + +#define Q6_ALIAS(TAG) .global __qdsp_##TAG ; .set __qdsp_##TAG, __hexagon_##TAG +#define FAST_ALIAS(TAG) .global __hexagon_fast_##TAG ; .set __hexagon_fast_##TAG, __hexagon_##TAG +#define FAST2_ALIAS(TAG) .global __hexagon_fast2_##TAG ; .set __hexagon_fast2_##TAG, __hexagon_##TAG + +FUNCTION_BEGIN __hexagon_sqrtf +  { +    E,p0 = sfinvsqrta(RIN) +    R = sffixupr(RIN) +    HALF = ##0x3f000000   // 0.5 +    r1:0 = combine(#0,#0)   // clear S/H +  } +  { +    S += sfmpy(E,R):lib   // S0 +    H += sfmpy(E,HALF):lib    // H0 +    D = HALF +    E = R +  } +  { +    D -= sfmpy(S,H):lib   // d0 +    p1 = sfclass(R,#1)    // is zero? +    //E -= sfmpy(S,S):lib   // e0 +  } +  { +    S += sfmpy(S,D):lib   // S1 +    H += sfmpy(H,D):lib   // H1 +    D = HALF +    E = R +  } +  { +    D -= sfmpy(S,H):lib   // d0 +    E -= sfmpy(S,S):lib   // e0 +  } +  { +    S += sfmpy(H,E):lib   // S2 +    H += sfmpy(H,D):lib   // H2 +    D = HALF +    E = R +  } +  { +    //D -= sfmpy(S,H):lib   // d2 +    E -= sfmpy(S,S):lib   // e2 +    if (p1) r0 = or(r0,R)     // sqrt(-0.0) = -0.0 +  } +  { +    S += sfmpy(H,E,p0):scale  // S3 +    jumpr r31 +  } + +FUNCTION_END __hexagon_sqrtf + +Q6_ALIAS(sqrtf) +FAST_ALIAS(sqrtf) +FAST2_ALIAS(sqrtf) diff --git a/lib/builtins/hexagon/udivdi3.S b/lib/builtins/hexagon/udivdi3.S new file mode 100644 index 0000000000000..1ca326b752086 --- /dev/null +++ b/lib/builtins/hexagon/udivdi3.S @@ -0,0 +1,71 @@ +//===----------------------Hexagon builtin routine ------------------------===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + + +	.macro FUNCTION_BEGIN name +	.text +        .p2align 5 +	.globl \name +	.type  \name, @function +\name: +	.endm + +	.macro FUNCTION_END name +	.size  \name, . - \name +	.endm + + +FUNCTION_BEGIN __hexagon_udivdi3 +	{ +		r6 = cl0(r1:0)              // count leading 0's of dividend (numerator) +		r7 = cl0(r3:2)              // count leading 0's of divisor (denominator) +		r5:4 = r3:2                 // divisor moved into working registers +		r3:2 = r1:0                 // dividend is the initial remainder, r3:2 contains remainder +	} +	{ +		r10 = sub(r7,r6)            // left shift count for bit & divisor +		r1:0 = #0                   // initialize quotient to 0 +		r15:14 = #1                 // initialize bit to 1 +	} +	{ +		r11 = add(r10,#1)           // loop count is 1 more than shift count +		r13:12 = lsl(r5:4,r10)      // shift divisor msb into same bit position as dividend msb +		r15:14 = lsl(r15:14,r10)    // shift the bit left by same amount as divisor +	} +	{ +		p0 = cmp.gtu(r5:4,r3:2)     // check if divisor > dividend +		loop0(1f,r11)               // register loop +	} +	{ +		if (p0) jumpr r31           // if divisor > dividend, we're done, so return +	} +	.falign +1: +	{ +		p0 = cmp.gtu(r13:12,r3:2)   // set predicate reg if shifted divisor > current remainder +	} +	{ +		r7:6 = sub(r3:2, r13:12)    // subtract shifted divisor from current remainder +		r9:8 = add(r1:0, r15:14)    // save current quotient to temp (r9:8) +	} +	{ +		r1:0 = vmux(p0, r1:0, r9:8) // choose either current quotient or new quotient (r9:8) +		r3:2 = vmux(p0, r3:2, r7:6) // choose either current remainder or new remainder (r7:6) +	} +	{ +		r15:14 = lsr(r15:14, #1)    // shift bit right by 1 for next iteration +		r13:12 = lsr(r13:12, #1)    // shift "shifted divisor" right by 1 for next iteration +	}:endloop0 +	{ +		jumpr r31                   // return +	} +FUNCTION_END __hexagon_udivdi3 + +  .globl __qdsp_udivdi3 +  .set   __qdsp_udivdi3, __hexagon_udivdi3 diff --git a/lib/builtins/hexagon/udivmoddi4.S b/lib/builtins/hexagon/udivmoddi4.S new file mode 100644 index 0000000000000..deb5aae0924d9 --- /dev/null +++ b/lib/builtins/hexagon/udivmoddi4.S @@ -0,0 +1,71 @@ +//===----------------------Hexagon builtin routine ------------------------===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + + +	.macro FUNCTION_BEGIN name +	.text +	.p2align 5 +	.globl \name +	.type  \name, @function +\name: +	.endm + +	.macro FUNCTION_END name +	.size  \name, . - \name +	.endm + + +FUNCTION_BEGIN __hexagon_udivmoddi4 +	{ +		r6 = cl0(r1:0)              // count leading 0's of dividend (numerator) +		r7 = cl0(r3:2)              // count leading 0's of divisor (denominator) +		r5:4 = r3:2                 // divisor moved into working registers +		r3:2 = r1:0                 // dividend is the initial remainder, r3:2 contains remainder +	} +	{ +		r10 = sub(r7,r6)            // left shift count for bit & divisor +		r1:0 = #0                   // initialize quotient to 0 +		r15:14 = #1                 // initialize bit to 1 +	} +	{ +		r11 = add(r10,#1)           // loop count is 1 more than shift count +		r13:12 = lsl(r5:4,r10)      // shift divisor msb into same bit position as dividend msb +		r15:14 = lsl(r15:14,r10)    // shift the bit left by same amount as divisor +	} +	{ +		p0 = cmp.gtu(r5:4,r3:2)     // check if divisor > dividend +		loop0(1f,r11)               // register loop +	} +	{ +		if (p0) jumpr r31           // if divisor > dividend, we're done, so return +	} +	.falign +1: +	{ +		p0 = cmp.gtu(r13:12,r3:2)   // set predicate reg if shifted divisor > current remainder +	} +	{ +		r7:6 = sub(r3:2, r13:12)    // subtract shifted divisor from current remainder +		r9:8 = add(r1:0, r15:14)    // save current quotient to temp (r9:8) +	} +	{ +		r1:0 = vmux(p0, r1:0, r9:8) // choose either current quotient or new quotient (r9:8) +		r3:2 = vmux(p0, r3:2, r7:6) // choose either current remainder or new remainder (r7:6) +	} +	{ +		r15:14 = lsr(r15:14, #1)    // shift bit right by 1 for next iteration +		r13:12 = lsr(r13:12, #1)    // shift "shifted divisor" right by 1 for next iteration +	}:endloop0 +	{ +		jumpr r31                   // return +	} +FUNCTION_END __hexagon_udivmoddi4 + +  .globl __qdsp_udivmoddi4 +  .set   __qdsp_udivmoddi4, __hexagon_udivmoddi4 diff --git a/lib/builtins/hexagon/udivmodsi4.S b/lib/builtins/hexagon/udivmodsi4.S new file mode 100644 index 0000000000000..25bbe7cd5925c --- /dev/null +++ b/lib/builtins/hexagon/udivmodsi4.S @@ -0,0 +1,60 @@ +//===----------------------Hexagon builtin routine ------------------------===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + + +	.macro FUNCTION_BEGIN name +	.text +	.p2align 5 +	.globl \name +	.type  \name, @function +\name: +	.endm + +	.macro FUNCTION_END name +	.size  \name, . - \name +	.endm + + +FUNCTION_BEGIN __hexagon_udivmodsi4 +	{ +		r2 = cl0(r0) +		r3 = cl0(r1) +		r5:4 = combine(#1,#0) +		p0 = cmp.gtu(r1,r0) +	} +	{ +		r6 = sub(r3,r2) +		r4 = r1 +		r1:0 = combine(r0,r4) +		if (p0) jumpr r31 +	} +	{ +		r3:2 = vlslw(r5:4,r6) +		loop0(1f,r6) +		p0 = cmp.eq(r6,#0) +		if (p0.new) r4 = #0 +	} +	.falign +1: +	{ +		p0 = cmp.gtu(r2,r1) +		if (!p0.new) r1 = sub(r1,r2) +		if (!p0.new) r0 = add(r0,r3) +		r3:2 = vlsrw(r3:2,#1) +	}:endloop0 +	{ +		p0 = cmp.gtu(r2,r1) +		if (!p0.new) r1 = sub(r1,r4) +		if (!p0.new) r0 = add(r0,r3) +		jumpr r31 +	} +FUNCTION_END __hexagon_udivmodsi4 + +  .globl __qdsp_udivmodsi4 +  .set   __qdsp_udivmodsi4, __hexagon_udivmodsi4 diff --git a/lib/builtins/hexagon/udivsi3.S b/lib/builtins/hexagon/udivsi3.S new file mode 100644 index 0000000000000..54f0aa409f932 --- /dev/null +++ b/lib/builtins/hexagon/udivsi3.S @@ -0,0 +1,56 @@ +//===----------------------Hexagon builtin routine ------------------------===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +	.macro FUNCTION_BEGIN name +	.text +        .p2align 5 +	.globl \name +	.type  \name, @function +\name: +	.endm + +	.macro FUNCTION_END name +	.size  \name, . - \name +	.endm + + +FUNCTION_BEGIN __hexagon_udivsi3 +	{ +		r2 = cl0(r0) +		r3 = cl0(r1) +		r5:4 = combine(#1,#0) +		p0 = cmp.gtu(r1,r0) +	} +	{ +		r6 = sub(r3,r2) +		r4 = r1 +		r1:0 = combine(r0,r4) +		if (p0) jumpr r31 +	} +	{ +		r3:2 = vlslw(r5:4,r6) +		loop0(1f,r6) +	} +	.falign +1: +	{ +		p0 = cmp.gtu(r2,r1) +		if (!p0.new) r1 = sub(r1,r2) +		if (!p0.new) r0 = add(r0,r3) +		r3:2 = vlsrw(r3:2,#1) +	}:endloop0 +	{ +		p0 = cmp.gtu(r2,r1) +		if (!p0.new) r0 = add(r0,r3) +		jumpr r31 +	} +FUNCTION_END __hexagon_udivsi3 + +  .globl __qdsp_udivsi3 +  .set   __qdsp_udivsi3, __hexagon_udivsi3 diff --git a/lib/builtins/hexagon/umoddi3.S b/lib/builtins/hexagon/umoddi3.S new file mode 100644 index 0000000000000..f091521414afd --- /dev/null +++ b/lib/builtins/hexagon/umoddi3.S @@ -0,0 +1,74 @@ +//===----------------------Hexagon builtin routine ------------------------===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + + +	.macro FUNCTION_BEGIN name +	.text +	.p2align 5 +	.globl \name +	.type  \name, @function +\name: +	.endm + +	.macro FUNCTION_END name +	.size  \name, . - \name +	.endm + + +FUNCTION_BEGIN __hexagon_umoddi3 +	{ +		r6 = cl0(r1:0)              // count leading 0's of dividend (numerator) +		r7 = cl0(r3:2)              // count leading 0's of divisor (denominator) +		r5:4 = r3:2                 // divisor moved into working registers +		r3:2 = r1:0                 // dividend is the initial remainder, r3:2 contains remainder +	} +	{ +		r10 = sub(r7,r6)            // left shift count for bit & divisor +		r1:0 = #0                   // initialize quotient to 0 +		r15:14 = #1                 // initialize bit to 1 +	} +	{ +		r11 = add(r10,#1)           // loop count is 1 more than shift count +		r13:12 = lsl(r5:4,r10)      // shift divisor msb into same bit position as dividend msb +		r15:14 = lsl(r15:14,r10)    // shift the bit left by same amount as divisor +	} +	{ +		p0 = cmp.gtu(r5:4,r3:2)     // check if divisor > dividend +		loop0(1f,r11)               // register loop +	} +	{ +		if (p0) jump .hexagon_umoddi3_return           // if divisor > dividend, we're done, so return +	} +	.falign +1: +	{ +		p0 = cmp.gtu(r13:12,r3:2)   // set predicate reg if shifted divisor > current remainder +	} +	{ +		r7:6 = sub(r3:2, r13:12)    // subtract shifted divisor from current remainder +		r9:8 = add(r1:0, r15:14)    // save current quotient to temp (r9:8) +	} +	{ +		r1:0 = vmux(p0, r1:0, r9:8) // choose either current quotient or new quotient (r9:8) +		r3:2 = vmux(p0, r3:2, r7:6) // choose either current remainder or new remainder (r7:6) +	} +	{ +		r15:14 = lsr(r15:14, #1)    // shift bit right by 1 for next iteration +		r13:12 = lsr(r13:12, #1)    // shift "shifted divisor" right by 1 for next iteration +	}:endloop0 + +.hexagon_umoddi3_return: +	{ +		r1:0 = r3:2 +		jumpr r31 +	} +FUNCTION_END __hexagon_umoddi3 + +  .globl __qdsp_umoddi3 +  .set   __qdsp_umoddi3, __hexagon_umoddi3 diff --git a/lib/builtins/hexagon/umodsi3.S b/lib/builtins/hexagon/umodsi3.S new file mode 100644 index 0000000000000..a8270c2030d5e --- /dev/null +++ b/lib/builtins/hexagon/umodsi3.S @@ -0,0 +1,55 @@ +//===----------------------Hexagon builtin routine ------------------------===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + + +	.macro FUNCTION_BEGIN name +	.text +	.p2align 5 +	.globl \name +	.type  \name, @function +\name: +	.endm + +	.macro FUNCTION_END name +	.size  \name, . - \name +	.endm + + +FUNCTION_BEGIN __hexagon_umodsi3 +	{ +		r2 = cl0(r0) +		r3 = cl0(r1) +		p0 = cmp.gtu(r1,r0) +	} +	{ +		r2 = sub(r3,r2) +		if (p0) jumpr r31 +	} +	{ +		loop0(1f,r2) +		p1 = cmp.eq(r2,#0) +		r2 = lsl(r1,r2) +	} +	.falign +1: +	{ +		p0 = cmp.gtu(r2,r0) +		if (!p0.new) r0 = sub(r0,r2) +		r2 = lsr(r2,#1) +		if (p1) r1 = #0 +	}:endloop0 +	{ +		p0 = cmp.gtu(r2,r0) +		if (!p0.new) r0 = sub(r0,r1) +		jumpr r31 +	} +FUNCTION_END __hexagon_umodsi3 + +  .globl __qdsp_umodsi3 +  .set   __qdsp_umodsi3, __hexagon_umodsi3 diff --git a/lib/builtins/int_types.h b/lib/builtins/int_types.h index a92238c5b7302..f53f343d35d5c 100644 --- a/lib/builtins/int_types.h +++ b/lib/builtins/int_types.h @@ -60,7 +60,7 @@ typedef union      }s;  } udwords; -#if (defined(__LP64__) || defined(__wasm__) || defined(__mips64)) +#if (defined(__LP64__) || defined(__wasm__) || defined(__mips64)) || defined(__riscv)  #define CRT_HAS_128BIT  #endif diff --git a/lib/builtins/os_version_check.c b/lib/builtins/os_version_check.c index 74ade2f5b9669..772e33333c0f4 100644 --- a/lib/builtins/os_version_check.c +++ b/lib/builtins/os_version_check.c @@ -16,8 +16,8 @@  #ifdef __APPLE__  #include <CoreFoundation/CoreFoundation.h> -#include <dispatch/dispatch.h>  #include <TargetConditionals.h> +#include <dispatch/dispatch.h>  #include <dlfcn.h>  #include <stdint.h>  #include <stdio.h> @@ -28,6 +28,26 @@  static int32_t GlobalMajor, GlobalMinor, GlobalSubminor;  static dispatch_once_t DispatchOnceCounter; +typedef CFDataRef (*CFDataCreateWithBytesNoCopyFuncTy)(CFAllocatorRef, +                                                       const UInt8 *, CFIndex, +                                                       CFAllocatorRef); +typedef CFPropertyListRef (*CFPropertyListCreateWithDataFuncTy)( +    CFAllocatorRef, CFDataRef, CFOptionFlags, CFPropertyListFormat *, +    CFErrorRef *); +typedef CFPropertyListRef (*CFPropertyListCreateFromXMLDataFuncTy)( +    CFAllocatorRef, CFDataRef, CFOptionFlags, CFStringRef *); +typedef CFStringRef (*CFStringCreateWithCStringNoCopyFuncTy)(CFAllocatorRef, +                                                             const char *, +                                                             CFStringEncoding, +                                                             CFAllocatorRef); +typedef const void *(*CFDictionaryGetValueFuncTy)(CFDictionaryRef, +                                                  const void *); +typedef CFTypeID (*CFGetTypeIDFuncTy)(CFTypeRef); +typedef CFTypeID (*CFStringGetTypeIDFuncTy)(void); +typedef Boolean (*CFStringGetCStringFuncTy)(CFStringRef, char *, CFIndex, +                                            CFStringEncoding); +typedef void (*CFReleaseFuncTy)(CFTypeRef); +  /* Find and parse the SystemVersion.plist file. */  static void parseSystemVersionPList(void *Unused) {    (void)Unused; @@ -37,50 +57,49 @@ static void parseSystemVersionPList(void *Unused) {      return;    const CFAllocatorRef kCFAllocatorNull =        *(const CFAllocatorRef *)NullAllocator; -  typeof(CFDataCreateWithBytesNoCopy) *CFDataCreateWithBytesNoCopyFunc = -      (typeof(CFDataCreateWithBytesNoCopy) *)dlsym( -          RTLD_DEFAULT, "CFDataCreateWithBytesNoCopy"); +  CFDataCreateWithBytesNoCopyFuncTy CFDataCreateWithBytesNoCopyFunc = +      (CFDataCreateWithBytesNoCopyFuncTy)dlsym(RTLD_DEFAULT, +                                               "CFDataCreateWithBytesNoCopy");    if (!CFDataCreateWithBytesNoCopyFunc)      return; -  typeof(CFPropertyListCreateWithData) *CFPropertyListCreateWithDataFunc = -      (typeof(CFPropertyListCreateWithData) *)dlsym( +  CFPropertyListCreateWithDataFuncTy CFPropertyListCreateWithDataFunc = +      (CFPropertyListCreateWithDataFuncTy)dlsym(            RTLD_DEFAULT, "CFPropertyListCreateWithData"); -  /* CFPropertyListCreateWithData was introduced only in macOS 10.6+, so it -   * will be NULL on earlier OS versions. */ +/* CFPropertyListCreateWithData was introduced only in macOS 10.6+, so it + * will be NULL on earlier OS versions. */  #pragma clang diagnostic push  #pragma clang diagnostic ignored "-Wdeprecated-declarations" -  typeof(CFPropertyListCreateFromXMLData) *CFPropertyListCreateFromXMLDataFunc = -      (typeof(CFPropertyListCreateFromXMLData) *)dlsym( +  CFPropertyListCreateFromXMLDataFuncTy CFPropertyListCreateFromXMLDataFunc = +      (CFPropertyListCreateFromXMLDataFuncTy)dlsym(            RTLD_DEFAULT, "CFPropertyListCreateFromXMLData");  #pragma clang diagnostic pop    /* CFPropertyListCreateFromXMLDataFunc is deprecated in macOS 10.10, so it     * might be NULL in future OS versions. */    if (!CFPropertyListCreateWithDataFunc && !CFPropertyListCreateFromXMLDataFunc)      return; -  typeof(CFStringCreateWithCStringNoCopy) *CFStringCreateWithCStringNoCopyFunc = -      (typeof(CFStringCreateWithCStringNoCopy) *)dlsym( +  CFStringCreateWithCStringNoCopyFuncTy CFStringCreateWithCStringNoCopyFunc = +      (CFStringCreateWithCStringNoCopyFuncTy)dlsym(            RTLD_DEFAULT, "CFStringCreateWithCStringNoCopy");    if (!CFStringCreateWithCStringNoCopyFunc)      return; -  typeof(CFDictionaryGetValue) *CFDictionaryGetValueFunc = -      (typeof(CFDictionaryGetValue) *)dlsym(RTLD_DEFAULT, -                                            "CFDictionaryGetValue"); +  CFDictionaryGetValueFuncTy CFDictionaryGetValueFunc = +      (CFDictionaryGetValueFuncTy)dlsym(RTLD_DEFAULT, "CFDictionaryGetValue");    if (!CFDictionaryGetValueFunc)      return; -  typeof(CFGetTypeID) *CFGetTypeIDFunc = -      (typeof(CFGetTypeID) *)dlsym(RTLD_DEFAULT, "CFGetTypeID"); +  CFGetTypeIDFuncTy CFGetTypeIDFunc = +      (CFGetTypeIDFuncTy)dlsym(RTLD_DEFAULT, "CFGetTypeID");    if (!CFGetTypeIDFunc)      return; -  typeof(CFStringGetTypeID) *CFStringGetTypeIDFunc = -      (typeof(CFStringGetTypeID) *)dlsym(RTLD_DEFAULT, "CFStringGetTypeID"); +  CFStringGetTypeIDFuncTy CFStringGetTypeIDFunc = +      (CFStringGetTypeIDFuncTy)dlsym(RTLD_DEFAULT, "CFStringGetTypeID");    if (!CFStringGetTypeIDFunc)      return; -  typeof(CFStringGetCString) *CFStringGetCStringFunc = -      (typeof(CFStringGetCString) *)dlsym(RTLD_DEFAULT, "CFStringGetCString"); +  CFStringGetCStringFuncTy CFStringGetCStringFunc = +      (CFStringGetCStringFuncTy)dlsym(RTLD_DEFAULT, "CFStringGetCString");    if (!CFStringGetCStringFunc)      return; -  typeof(CFRelease) *CFReleaseFunc = -      (typeof(CFRelease) *)dlsym(RTLD_DEFAULT, "CFRelease"); +  CFReleaseFuncTy CFReleaseFunc = +      (CFReleaseFuncTy)dlsym(RTLD_DEFAULT, "CFRelease");    if (!CFReleaseFunc)      return; @@ -163,10 +182,14 @@ int32_t __isOSVersionAtLeast(int32_t Major, int32_t Minor, int32_t Subminor) {    /* Populate the global version variables, if they haven't already. */    dispatch_once_f(&DispatchOnceCounter, NULL, parseSystemVersionPList); -  if (Major < GlobalMajor) return 1; -  if (Major > GlobalMajor) return 0; -  if (Minor < GlobalMinor) return 1; -  if (Minor > GlobalMinor) return 0; +  if (Major < GlobalMajor) +    return 1; +  if (Major > GlobalMajor) +    return 0; +  if (Minor < GlobalMinor) +    return 1; +  if (Minor > GlobalMinor) +    return 0;    return Subminor <= GlobalSubminor;  } diff --git a/lib/builtins/riscv/mulsi3.S b/lib/builtins/riscv/mulsi3.S new file mode 100644 index 0000000000000..a58d237040b64 --- /dev/null +++ b/lib/builtins/riscv/mulsi3.S @@ -0,0 +1,28 @@ +//===--- mulsi3.S - Integer multiplication routines routines ---===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#if !defined(__riscv_mul) && __riscv_xlen == 32 +	.text +	.align 2 + +	.globl __mulsi3 +	.type  __mulsi3, @function +__mulsi3: +	mv     a2, a0 +	mv     a0, zero +.L1: +	andi   a3, a1, 1 +	beqz   a3, .L2 +	add    a0, a0, a2 +.L2: +	srli   a1, a1, 1 +	slli   a2, a2, 1 +	bnez   a1, .L1 +	ret +#endif diff --git a/lib/cfi/CMakeLists.txt b/lib/cfi/CMakeLists.txt index 6c531445626a6..7ed72bca5d23d 100644 --- a/lib/cfi/CMakeLists.txt +++ b/lib/cfi/CMakeLists.txt @@ -30,6 +30,8 @@ if(OS_NAME MATCHES "Linux")        OBJECT_LIBS RTInterception                    RTSanitizerCommon                    RTSanitizerCommonLibc +                  RTSanitizerCommonCoverage +                  RTSanitizerCommonSymbolizer                    RTUbsan        CFLAGS ${CFI_CFLAGS} ${CFI_DIAG_CFLAGS}        PARENT_TARGET cfi) diff --git a/lib/cfi/cfi.cc b/lib/cfi/cfi.cc index f7693b37d29c0..a2f127f93cda0 100644 --- a/lib/cfi/cfi.cc +++ b/lib/cfi/cfi.cc @@ -132,7 +132,11 @@ void ShadowBuilder::Start() {  void ShadowBuilder::AddUnchecked(uptr begin, uptr end) {    uint16_t *shadow_begin = MemToShadow(begin, shadow_);    uint16_t *shadow_end = MemToShadow(end - 1, shadow_) + 1; -  memset(shadow_begin, kUncheckedShadow, +  // memset takes a byte, so our unchecked shadow value requires both bytes to +  // be the same. Make sure we're ok during compilation. +  static_assert((kUncheckedShadow & 0xff) == ((kUncheckedShadow >> 8) & 0xff), +                "Both bytes of the 16-bit value must be the same!"); +  memset(shadow_begin, kUncheckedShadow & 0xff,           (shadow_end - shadow_begin) * sizeof(*shadow_begin));  } @@ -379,6 +383,8 @@ __cfi_slowpath_diag(u64 CallSiteTypeId, void *Ptr, void *DiagData) {  }  #endif +static void EnsureInterceptorsInitialized(); +  // Setup shadow for dlopen()ed libraries.  // The actual shadow setup happens after dlopen() returns, which means that  // a library can not be a target of any CFI checks while its constructors are @@ -388,6 +394,7 @@ __cfi_slowpath_diag(u64 CallSiteTypeId, void *Ptr, void *DiagData) {  // We could insert a high-priority constructor into the library, but that would  // not help with the uninstrumented libraries.  INTERCEPTOR(void*, dlopen, const char *filename, int flag) { +  EnsureInterceptorsInitialized();    EnterLoader();    void *handle = REAL(dlopen)(filename, flag);    ExitLoader(); @@ -395,12 +402,27 @@ INTERCEPTOR(void*, dlopen, const char *filename, int flag) {  }  INTERCEPTOR(int, dlclose, void *handle) { +  EnsureInterceptorsInitialized();    EnterLoader();    int res = REAL(dlclose)(handle);    ExitLoader();    return res;  } +static BlockingMutex interceptor_init_lock(LINKER_INITIALIZED); +static bool interceptors_inited = false; + +static void EnsureInterceptorsInitialized() { +  BlockingMutexLock lock(&interceptor_init_lock); +  if (interceptors_inited) +    return; + +  INTERCEPT_FUNCTION(dlopen); +  INTERCEPT_FUNCTION(dlclose); + +  interceptors_inited = true; +} +  extern "C" SANITIZER_INTERFACE_ATTRIBUTE  #if !SANITIZER_CAN_USE_PREINIT_ARRAY  // On ELF platforms, the constructor is invoked using .preinit_array (see below) @@ -411,9 +433,6 @@ void __cfi_init() {    InitializeFlags();    InitShadow(); -  INTERCEPT_FUNCTION(dlopen); -  INTERCEPT_FUNCTION(dlclose); -  #ifdef CFI_ENABLE_DIAG    __ubsan::InitAsPlugin();  #endif diff --git a/lib/cfi/cfi_blacklist.txt b/lib/cfi/cfi_blacklist.txt index d8c9d49e3cdd7..3d73508f57072 100644 --- a/lib/cfi/cfi_blacklist.txt +++ b/lib/cfi/cfi_blacklist.txt @@ -1,7 +1,9 @@  [cfi-unrelated-cast] -# std::get_temporary_buffer, likewise (libstdc++, libc++). +# The specification of std::get_temporary_buffer mandates a cast to +# uninitialized T* (libstdc++, libc++, MSVC stdlib).  fun:_ZSt20get_temporary_buffer*  fun:_ZNSt3__120get_temporary_buffer* +fun:*get_temporary_buffer@.*@std@@*  # STL address-of magic (libstdc++, libc++).  fun:*__addressof* diff --git a/lib/dfsan/.clang-format b/lib/dfsan/.clang-format index f6cb8ad931f54..560308c91deec 100644 --- a/lib/dfsan/.clang-format +++ b/lib/dfsan/.clang-format @@ -1 +1,2 @@  BasedOnStyle: Google +AllowShortIfStatementsOnASingleLine: false diff --git a/lib/dfsan/CMakeLists.txt b/lib/dfsan/CMakeLists.txt index 2c486bff821bb..b3ae713cf02c5 100644 --- a/lib/dfsan/CMakeLists.txt +++ b/lib/dfsan/CMakeLists.txt @@ -5,6 +5,12 @@ set(DFSAN_RTL_SOURCES    dfsan.cc    dfsan_custom.cc    dfsan_interceptors.cc) + +set(DFSAN_RTL_HEADERS +  dfsan.h +  dfsan_flags.inc +  dfsan_platform.h) +  set(DFSAN_COMMON_CFLAGS ${SANITIZER_COMMON_CFLAGS})  append_rtti_flag(OFF DFSAN_COMMON_CFLAGS)  # Prevent clang from generating libc calls. @@ -23,6 +29,7 @@ foreach(arch ${DFSAN_SUPPORTED_ARCH})              $<TARGET_OBJECTS:RTInterception.${arch}>              $<TARGET_OBJECTS:RTSanitizerCommon.${arch}>              $<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}> +    ADDITIONAL_HEADERS ${DFSAN_RTL_HEADERS}      CFLAGS ${DFSAN_CFLAGS}      PARENT_TARGET dfsan)    add_sanitizer_rt_symbols(clang_rt.dfsan @@ -32,16 +39,19 @@ foreach(arch ${DFSAN_SUPPORTED_ARCH})      clang_rt.dfsan-${arch}-symbols)  endforeach() -set(dfsan_abilist_filename ${COMPILER_RT_OUTPUT_DIR}/dfsan_abilist.txt) +set(dfsan_abilist_dir ${COMPILER_RT_OUTPUT_DIR}/share) +set(dfsan_abilist_filename ${dfsan_abilist_dir}/dfsan_abilist.txt)  add_custom_target(dfsan_abilist ALL    DEPENDS ${dfsan_abilist_filename})  add_custom_command(OUTPUT ${dfsan_abilist_filename}                     VERBATIM                     COMMAND +                    ${CMAKE_COMMAND} -E make_directory ${dfsan_abilist_dir} +                   COMMAND                       cat ${CMAKE_CURRENT_SOURCE_DIR}/done_abilist.txt                           ${CMAKE_CURRENT_SOURCE_DIR}/libc_ubuntu1404_abilist.txt                           > ${dfsan_abilist_filename}                     DEPENDS done_abilist.txt libc_ubuntu1404_abilist.txt)  add_dependencies(dfsan dfsan_abilist)  install(FILES ${dfsan_abilist_filename} -        DESTINATION ${COMPILER_RT_INSTALL_PATH}) +        DESTINATION ${COMPILER_RT_INSTALL_PATH}/share) diff --git a/lib/dfsan/dfsan.cc b/lib/dfsan/dfsan.cc index 9e360c959fa73..d4dbebc43a78d 100644 --- a/lib/dfsan/dfsan.cc +++ b/lib/dfsan/dfsan.cc @@ -425,7 +425,8 @@ static void dfsan_init(int argc, char **argv, char **envp) {    InitializePlatformEarly(); -  MmapFixedNoReserve(ShadowAddr(), UnusedAddr() - ShadowAddr()); +  if (!MmapFixedNoReserve(ShadowAddr(), UnusedAddr() - ShadowAddr())) +    Die();    // Protect the region of memory we don't use, to preserve the one-to-one    // mapping from application to shadow memory. But if ASLR is disabled, Linux diff --git a/lib/dfsan/dfsan_custom.cc b/lib/dfsan/dfsan_custom.cc index e0cd16ab695cc..022aa9a9ab8e8 100644 --- a/lib/dfsan/dfsan_custom.cc +++ b/lib/dfsan/dfsan_custom.cc @@ -1132,4 +1132,26 @@ int __dfsw_snprintf(char *str, size_t size, const char *format,    va_end(ap);    return ret;  } -} // extern "C" + +// Default empty implementations (weak). Users should redefine them. +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_guard, u32 *) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_guard_init, u32 *, +                             u32 *) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_pcs_init, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_indir, void) {} + +SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_cmp, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_cmp1, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_cmp2, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_cmp4, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_cmp8, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_const_cmp1, +                             void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_const_cmp2, +                             void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_const_cmp4, +                             void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_const_cmp8, +                             void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_switch, void) {} +}  // extern "C" diff --git a/lib/dfsan/done_abilist.txt b/lib/dfsan/done_abilist.txt index a560cd7b477cc..9765626ad3ff1 100644 --- a/lib/dfsan/done_abilist.txt +++ b/lib/dfsan/done_abilist.txt @@ -264,8 +264,6 @@ fun:reflect.makeFuncStub=discard  # lib/Fuzzer  ###############################################################################  # Replaces __sanitizer_cov_trace_cmp with __dfsw___sanitizer_cov_trace_cmp -fun:__sanitizer_cov_trace_cmp=custom -fun:__sanitizer_cov_trace_cmp=uninstrumented  fun:__sanitizer_cov_trace_cmp1=custom  fun:__sanitizer_cov_trace_cmp1=uninstrumented  fun:__sanitizer_cov_trace_cmp2=custom @@ -274,6 +272,14 @@ fun:__sanitizer_cov_trace_cmp4=custom  fun:__sanitizer_cov_trace_cmp4=uninstrumented  fun:__sanitizer_cov_trace_cmp8=custom  fun:__sanitizer_cov_trace_cmp8=uninstrumented +fun:__sanitizer_cov_trace_const_cmp1=custom +fun:__sanitizer_cov_trace_const_cmp1=uninstrumented +fun:__sanitizer_cov_trace_const_cmp2=custom +fun:__sanitizer_cov_trace_const_cmp2=uninstrumented +fun:__sanitizer_cov_trace_const_cmp4=custom +fun:__sanitizer_cov_trace_const_cmp4=uninstrumented +fun:__sanitizer_cov_trace_const_cmp8=custom +fun:__sanitizer_cov_trace_const_cmp8=uninstrumented  # Similar for __sanitizer_cov_trace_switch  fun:__sanitizer_cov_trace_switch=custom  fun:__sanitizer_cov_trace_switch=uninstrumented @@ -289,10 +295,11 @@ fun:__sanitizer_set_death_callback=uninstrumented  fun:__sanitizer_set_death_callback=discard  fun:__sanitizer_update_counter_bitset_and_clear_counters=uninstrumented  fun:__sanitizer_update_counter_bitset_and_clear_counters=discard +fun:__sanitizer_cov_trace_pc*=uninstrumented +fun:__sanitizer_cov_trace_pc*=discard +fun:__sanitizer_cov_pcs_init=uninstrumented +fun:__sanitizer_cov_pcs_init=discard  # Ignores the dfsan wrappers.  fun:__dfsw_*=uninstrumented  fun:__dfsw_*=discard - -# Don't add extra parameters to the Fuzzer callback. -fun:LLVMFuzzerTestOneInput=uninstrumented diff --git a/lib/dfsan/scripts/check_custom_wrappers.sh b/lib/dfsan/scripts/check_custom_wrappers.sh index 99bf50cbbd088..9a80cb9c6ffd6 100755 --- a/lib/dfsan/scripts/check_custom_wrappers.sh +++ b/lib/dfsan/scripts/check_custom_wrappers.sh @@ -23,6 +23,7 @@ grep -E "^fun:.*=custom" ${DFSAN_ABI_LIST} \    | grep -v "dfsan_get_label\|__sanitizer_cov_trace" \    | sed "s/^fun:\(.*\)=custom.*/\1/" | sort > $DIFF_A  grep -E "__dfsw.*\(" ${DFSAN_CUSTOM_WRAPPERS} \ +  | grep -v "__sanitizer_cov_trace" \    | sed "s/.*__dfsw_\(.*\)(.*/\1/" | sort > $DIFF_B  diff -u $DIFF_A $DIFF_B > ${DIFFOUT}  if [ $? -ne 0 ] @@ -33,6 +34,7 @@ then  fi  grep -E __dfsw_ ${DFSAN_CUSTOM_WRAPPERS} \ +  | grep -v "__sanitizer_cov_trace" \    | sed "s/.*__dfsw_\([^(]*\).*/\1/" | sort > $DIFF_A  grep -E "^[[:space:]]*test_.*\(\);" ${DFSAN_CUSTOM_TESTS} \    | sed "s/.*test_\(.*\)();/\1/" | sort > $DIFF_B diff --git a/lib/esan/CMakeLists.txt b/lib/esan/CMakeLists.txt index 2012ab642bf1c..4de5c0205c1d2 100644 --- a/lib/esan/CMakeLists.txt +++ b/lib/esan/CMakeLists.txt @@ -18,6 +18,18 @@ set(ESAN_SOURCES    working_set.cpp    working_set_posix.cpp) +set(ESAN_HEADERS +  cache_frag.h +  esan.h +  esan_circular_buffer.h +  esan_flags.h +  esan_flags.inc +  esan_hashtable.h +  esan_interface_internal.h +  esan_shadow.h +  esan_sideline.h +  working_set.h) +  foreach (arch ${ESAN_SUPPORTED_ARCH})    add_compiler_rt_runtime(clang_rt.esan      STATIC @@ -26,6 +38,8 @@ foreach (arch ${ESAN_SUPPORTED_ARCH})              $<TARGET_OBJECTS:RTInterception.${arch}>              $<TARGET_OBJECTS:RTSanitizerCommon.${arch}>              $<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}> +            $<TARGET_OBJECTS:RTSanitizerCommonSymbolizer.${arch}> +    ADDITIONAL_HEADERS ${ESAN_HEADERS}      CFLAGS ${ESAN_RTL_CFLAGS})    add_sanitizer_rt_symbols(clang_rt.esan      ARCHS ${arch} diff --git a/lib/esan/esan.cpp b/lib/esan/esan.cpp index 09b530b6645f6..44b8032caa1a4 100644 --- a/lib/esan/esan.cpp +++ b/lib/esan/esan.cpp @@ -163,15 +163,15 @@ static void initializeShadow() {      VPrintf(1, "Shadow #%d: [%zx-%zx) (%zuGB)\n", i, ShadowStart, ShadowEnd,              (ShadowEnd - ShadowStart) >> 30); -    uptr Map; +    uptr Map = 0;      if (__esan_which_tool == ESAN_WorkingSet) {        // We want to identify all shadow pages that are touched so we start        // out inaccessible.        Map = (uptr)MmapFixedNoAccess(ShadowStart, ShadowEnd- ShadowStart,                                      "shadow");      } else { -      Map = (uptr)MmapFixedNoReserve(ShadowStart, ShadowEnd - ShadowStart, -                                     "shadow"); +      if (MmapFixedNoReserve(ShadowStart, ShadowEnd - ShadowStart, "shadow")) +        Map = ShadowStart;      }      if (Map != ShadowStart) {        Printf("FATAL: EfficiencySanitizer failed to map its shadow memory.\n"); diff --git a/lib/esan/esan_interceptors.cpp b/lib/esan/esan_interceptors.cpp index 62fa13c838220..0c596f1cf37ec 100644 --- a/lib/esan/esan_interceptors.cpp +++ b/lib/esan/esan_interceptors.cpp @@ -175,6 +175,15 @@ DECLARE_REAL_AND_INTERCEPTOR(void *, malloc, uptr)    do {                                                                         \    } while (false) +#define COMMON_INTERCEPTOR_MMAP_IMPL(ctx, mmap, addr, sz, prot, flags, fd,     \ +                                     off)                                      \ +  do {                                                                         \ +    if (!fixMmapAddr(&addr, sz, flags))                                        \ +      return (void *)-1;                                                       \ +    void *result = REAL(mmap)(addr, sz, prot, flags, fd, off);                 \ +    return (void *)checkMmapResult((uptr)result, sz);                          \ +  } while (false) +  #include "sanitizer_common/sanitizer_common_interceptors.inc"  //===----------------------------------------------------------------------===// @@ -232,6 +241,7 @@ DECLARE_REAL_AND_INTERCEPTOR(void *, malloc, uptr)    } while (false)  #include "sanitizer_common/sanitizer_common_syscalls.inc" +#include "sanitizer_common/sanitizer_syscalls_netbsd.inc"  //===----------------------------------------------------------------------===//  // Custom interceptors @@ -306,13 +316,6 @@ INTERCEPTOR(int, unlink, char *path) {    return REAL(unlink)(path);  } -INTERCEPTOR(int, puts, const char *s) { -  void *ctx; -  COMMON_INTERCEPTOR_ENTER(ctx, puts, s); -  COMMON_INTERCEPTOR_READ_RANGE(ctx, s, internal_strlen(s)); -  return REAL(puts)(s); -} -  INTERCEPTOR(int, rmdir, char *path) {    void *ctx;    COMMON_INTERCEPTOR_ENTER(ctx, rmdir, path); @@ -321,44 +324,6 @@ INTERCEPTOR(int, rmdir, char *path) {  }  //===----------------------------------------------------------------------===// -// Shadow-related interceptors -//===----------------------------------------------------------------------===// - -// These are candidates for sharing with all sanitizers if shadow memory -// support is also standardized. - -INTERCEPTOR(void *, mmap, void *addr, SIZE_T sz, int prot, int flags, -                 int fd, OFF_T off) { -  if (UNLIKELY(REAL(mmap) == nullptr)) { -    // With esan init during interceptor init and a static libc preventing -    // our early-calloc from triggering, we can end up here before our -    // REAL pointer is set up. -    return (void *)internal_mmap(addr, sz, prot, flags, fd, off); -  } -  void *ctx; -  COMMON_INTERCEPTOR_ENTER(ctx, mmap, addr, sz, prot, flags, fd, off); -  if (!fixMmapAddr(&addr, sz, flags)) -    return (void *)-1; -  void *result = REAL(mmap)(addr, sz, prot, flags, fd, off); -  return (void *)checkMmapResult((uptr)result, sz); -} - -#if SANITIZER_LINUX -INTERCEPTOR(void *, mmap64, void *addr, SIZE_T sz, int prot, int flags, -                 int fd, OFF64_T off) { -  void *ctx; -  COMMON_INTERCEPTOR_ENTER(ctx, mmap64, addr, sz, prot, flags, fd, off); -  if (!fixMmapAddr(&addr, sz, flags)) -    return (void *)-1; -  void *result = REAL(mmap64)(addr, sz, prot, flags, fd, off); -  return (void *)checkMmapResult((uptr)result, sz); -} -#define ESAN_MAYBE_INTERCEPT_MMAP64 INTERCEPT_FUNCTION(mmap64) -#else -#define ESAN_MAYBE_INTERCEPT_MMAP64 -#endif - -//===----------------------------------------------------------------------===//  // Signal-related interceptors  //===----------------------------------------------------------------------===// @@ -521,14 +486,8 @@ void initializeInterceptors() {    INTERCEPT_FUNCTION(creat);    ESAN_MAYBE_INTERCEPT_CREAT64;    INTERCEPT_FUNCTION(unlink); -  INTERCEPT_FUNCTION(fread); -  INTERCEPT_FUNCTION(fwrite); -  INTERCEPT_FUNCTION(puts);    INTERCEPT_FUNCTION(rmdir); -  INTERCEPT_FUNCTION(mmap); -  ESAN_MAYBE_INTERCEPT_MMAP64; -    ESAN_MAYBE_INTERCEPT_SIGNAL;    ESAN_MAYBE_INTERCEPT_SIGACTION;    ESAN_MAYBE_INTERCEPT_SIGPROCMASK; diff --git a/lib/esan/esan_sideline_linux.cpp b/lib/esan/esan_sideline_linux.cpp index 4a96910ece351..2de25fba700dd 100644 --- a/lib/esan/esan_sideline_linux.cpp +++ b/lib/esan/esan_sideline_linux.cpp @@ -70,7 +70,7 @@ int SidelineThread::runSideline(void *Arg) {    internal_prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);    // Set up a signal handler on an alternate stack for safety. -  InternalScopedBuffer<char> StackMap(SigAltStackSize); +  InternalMmapVector<char> StackMap(SigAltStackSize);    stack_t SigAltStack;    SigAltStack.ss_sp = StackMap.data();    SigAltStack.ss_size = SigAltStackSize; diff --git a/lib/fuzzer/CMakeLists.txt b/lib/fuzzer/CMakeLists.txt index 9769be52ae014..679318e460b5d 100644 --- a/lib/fuzzer/CMakeLists.txt +++ b/lib/fuzzer/CMakeLists.txt @@ -1,6 +1,6 @@  set(LIBFUZZER_SOURCES -  FuzzerClangCounters.cpp    FuzzerCrossOver.cpp +  FuzzerDataFlowTrace.cpp    FuzzerDriver.cpp    FuzzerExtFunctionsDlsym.cpp    FuzzerExtFunctionsDlsymWin.cpp @@ -13,6 +13,7 @@ set(LIBFUZZER_SOURCES    FuzzerMerge.cpp    FuzzerMutate.cpp    FuzzerSHA1.cpp +  FuzzerShmemFuchsia.cpp    FuzzerShmemPosix.cpp    FuzzerShmemWindows.cpp    FuzzerTracePC.cpp @@ -21,8 +22,29 @@ set(LIBFUZZER_SOURCES    FuzzerUtilFuchsia.cpp    FuzzerUtilLinux.cpp    FuzzerUtilPosix.cpp -  FuzzerUtilWindows.cpp -  ) +  FuzzerUtilWindows.cpp) + +set(LIBFUZZER_HEADERS +  FuzzerCommand.h +  FuzzerCorpus.h +  FuzzerDataFlowTrace.h +  FuzzerDefs.h +  FuzzerDictionary.h +  FuzzerExtFunctions.def +  FuzzerExtFunctions.h +  FuzzerFlags.def +  FuzzerIO.h +  FuzzerInterface.h +  FuzzerInternal.h +  FuzzerMerge.h +  FuzzerMutate.h +  FuzzerOptions.h +  FuzzerRandom.h +  FuzzerSHA1.h +  FuzzerShmem.h +  FuzzerTracePC.h +  FuzzerUtil.h +  FuzzerValueBitMap.h)  CHECK_CXX_SOURCE_COMPILES("    static thread_local int blah; @@ -33,6 +55,14 @@ CHECK_CXX_SOURCE_COMPILES("  set(LIBFUZZER_CFLAGS ${SANITIZER_COMMON_CFLAGS}) +if(OS_NAME MATCHES "Linux|Fuchsia" AND COMPILER_RT_LIBCXX_PATH) +  list(APPEND LIBFUZZER_CFLAGS -nostdinc++ -D_LIBCPP_ABI_VERSION=Fuzzer) +  # Remove -stdlib= which is unused when passing -nostdinc++. +  string(REGEX REPLACE "-stdlib=[a-zA-Z+]*" "" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS}) +elseif(TARGET cxx-headers OR HAVE_LIBCXX) +  set(LIBFUZZER_DEPS cxx-headers) +endif() +  append_list_if(COMPILER_RT_HAS_OMIT_FRAME_POINTER_FLAG -fno-omit-frame-pointer LIBFUZZER_CFLAGS)  if (CMAKE_CXX_FLAGS MATCHES "fsanitize-coverage") @@ -43,21 +73,22 @@ if(NOT HAS_THREAD_LOCAL)    list(APPEND LIBFUZZER_CFLAGS -Dthread_local=__thread)  endif() -if(APPLE) -  set(FUZZER_SUPPORTED_OS osx) -endif() +set(FUZZER_SUPPORTED_OS ${SANITIZER_COMMON_SUPPORTED_OS})  add_compiler_rt_object_libraries(RTfuzzer    OS ${FUZZER_SUPPORTED_OS}    ARCHS ${FUZZER_SUPPORTED_ARCH}    SOURCES ${LIBFUZZER_SOURCES} -  CFLAGS ${LIBFUZZER_CFLAGS}) +  ADDITIONAL_HEADERS ${LIBFUZZER_HEADERS} +  CFLAGS ${LIBFUZZER_CFLAGS} +  DEPS ${LIBFUZZER_DEPS})  add_compiler_rt_object_libraries(RTfuzzer_main    OS ${FUZZER_SUPPORTED_OS}    ARCHS ${FUZZER_SUPPORTED_ARCH}    SOURCES FuzzerMain.cpp -  CFLAGS ${LIBFUZZER_CFLAGS}) +  CFLAGS ${LIBFUZZER_CFLAGS} +  DEPS ${LIBFUZZER_DEPS})  add_compiler_rt_runtime(clang_rt.fuzzer    STATIC @@ -75,6 +106,40 @@ add_compiler_rt_runtime(clang_rt.fuzzer_no_main    CFLAGS ${LIBFUZZER_CFLAGS}    PARENT_TARGET fuzzer) +if(OS_NAME MATCHES "Linux|Fuchsia" AND COMPILER_RT_LIBCXX_PATH) +  macro(partially_link_libcxx name dir arch) +    set(cxx_${arch}_merge_dir "${CMAKE_CURRENT_BINARY_DIR}/cxx_${arch}_merge.dir") +    file(MAKE_DIRECTORY ${cxx_${arch}_merge_dir}) +    add_custom_command(TARGET clang_rt.${name}-${arch} POST_BUILD +      COMMAND ${CMAKE_LINKER} --whole-archive "$<TARGET_LINKER_FILE:clang_rt.${name}-${arch}>" --no-whole-archive ${dir}/lib/libc++.a -r -o ${name}.o +      COMMAND ${CMAKE_OBJCOPY} --localize-hidden ${name}.o +      COMMAND ${CMAKE_COMMAND} -E remove "$<TARGET_LINKER_FILE:clang_rt.${name}-${arch}>" +      COMMAND ${CMAKE_AR} qcs "$<TARGET_LINKER_FILE:clang_rt.${name}-${arch}>" ${name}.o +      WORKING_DIRECTORY ${cxx_${arch}_merge_dir} +    ) +  endmacro() + +  foreach(arch ${FUZZER_SUPPORTED_ARCH}) +    get_target_flags_for_arch(${arch} TARGET_CFLAGS) +    set(LIBCXX_${arch}_PREFIX ${CMAKE_CURRENT_BINARY_DIR}/libcxx_fuzzer_${arch}) +    add_custom_libcxx(libcxx_fuzzer_${arch} ${LIBCXX_${arch}_PREFIX} +      CFLAGS ${TARGET_CFLAGS} +             -D_LIBCPP_ABI_VERSION=Fuzzer +             -D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS=1 +             -fvisibility=hidden +      CMAKE_ARGS -DCMAKE_CXX_COMPILER_WORKS=ON +                 -DLIBCXX_ENABLE_EXCEPTIONS=OFF +                 -DLIBCXX_ENABLE_SHARED=OFF +                 -DLIBCXX_CXX_ABI=none) +    target_compile_options(RTfuzzer.${arch} PRIVATE -isystem ${LIBCXX_${arch}_PREFIX}/include/c++/v1) +    add_dependencies(RTfuzzer.${arch} libcxx_fuzzer_${arch}-build) +    target_compile_options(RTfuzzer_main.${arch} PRIVATE -isystem ${LIBCXX_${arch}_PREFIX}/include/c++/v1) +    add_dependencies(RTfuzzer_main.${arch} libcxx_fuzzer_${arch}-build) +    partially_link_libcxx(fuzzer_no_main ${LIBCXX_${arch}_PREFIX} ${arch}) +    partially_link_libcxx(fuzzer ${LIBCXX_${arch}_PREFIX} ${arch}) +  endforeach() +endif() +  if(COMPILER_RT_INCLUDE_TESTS)    add_subdirectory(tests)  endif() diff --git a/lib/fuzzer/FuzzerClangCounters.cpp b/lib/fuzzer/FuzzerClangCounters.cpp deleted file mode 100644 index f69e922cf0042..0000000000000 --- a/lib/fuzzer/FuzzerClangCounters.cpp +++ /dev/null @@ -1,49 +0,0 @@ -//===- FuzzerExtraCounters.cpp - Extra coverage counters ------------------===// -// -//                     The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// Coverage counters from Clang's SourceBasedCodeCoverage. -//===----------------------------------------------------------------------===// - -// Support for SourceBasedCodeCoverage is experimental: -// * Works only for the main binary, not DSOs yet. -// * Works only on Linux. -// * Does not implement print_pcs/print_coverage yet. -// * Is not fully evaluated for performance and sensitivity. -//   We expect large performance drop due to 64-bit counters, -//   and *maybe* better sensitivity due to more fine-grained counters. -//   Preliminary comparison on a single benchmark (RE2) shows -//   a bit worse sensitivity though. - -#include "FuzzerDefs.h" - -#if LIBFUZZER_LINUX -__attribute__((weak)) extern uint64_t __start___llvm_prf_cnts; -__attribute__((weak)) extern uint64_t __stop___llvm_prf_cnts; -namespace fuzzer { -uint64_t *ClangCountersBegin() { return &__start___llvm_prf_cnts; } -uint64_t *ClangCountersEnd() { return &__stop___llvm_prf_cnts; } -}  // namespace fuzzer -#else -// TODO: Implement on Mac (if the data shows it's worth it). -//__attribute__((visibility("hidden"))) -//extern uint64_t CountersStart __asm("section$start$__DATA$__llvm_prf_cnts"); -//__attribute__((visibility("hidden"))) -//extern uint64_t CountersEnd __asm("section$end$__DATA$__llvm_prf_cnts"); -namespace fuzzer { -uint64_t *ClangCountersBegin() { return nullptr; } -uint64_t *ClangCountersEnd() { return  nullptr; } -}  // namespace fuzzer -#endif - -namespace fuzzer { -ATTRIBUTE_NO_SANITIZE_ALL -void ClearClangCounters() {  // hand-written memset, don't asan-ify. -  for (auto P = ClangCountersBegin(); P < ClangCountersEnd(); P++) -    *P = 0; -} -} diff --git a/lib/fuzzer/FuzzerCommand.h b/lib/fuzzer/FuzzerCommand.h index c5500ed21fc1c..255f571ecf314 100644 --- a/lib/fuzzer/FuzzerCommand.h +++ b/lib/fuzzer/FuzzerCommand.h @@ -29,8 +29,7 @@ public:    // is immutable, meaning this flag effectively marks the end of the mutable    // argument list.    static inline const char *ignoreRemainingArgs() { -    static const char *kIgnoreRemaining = "-ignore_remaining_args=1"; -    return kIgnoreRemaining; +    return "-ignore_remaining_args=1";    }    Command() : CombinedOutAndErr(false) {} diff --git a/lib/fuzzer/FuzzerCorpus.h b/lib/fuzzer/FuzzerCorpus.h index 2da929835f45d..8ad14656cffc9 100644 --- a/lib/fuzzer/FuzzerCorpus.h +++ b/lib/fuzzer/FuzzerCorpus.h @@ -12,6 +12,7 @@  #ifndef LLVM_FUZZER_CORPUS  #define LLVM_FUZZER_CORPUS +#include "FuzzerDataFlowTrace.h"  #include "FuzzerDefs.h"  #include "FuzzerIO.h"  #include "FuzzerRandom.h" @@ -35,8 +36,9 @@ struct InputInfo {    size_t NumSuccessfullMutations = 0;    bool MayDeleteFile = false;    bool Reduced = false; +  bool HasFocusFunction = false;    Vector<uint32_t> UniqFeatureSet; -  float FeatureFrequencyScore = 1.0; +  Vector<uint8_t> DataFlowTraceForFocusFunction;  };  class InputCorpus { @@ -45,7 +47,6 @@ class InputCorpus {    InputCorpus(const std::string &OutputCorpus) : OutputCorpus(OutputCorpus) {      memset(InputSizesPerFeature, 0, sizeof(InputSizesPerFeature));      memset(SmallestElementPerFeature, 0, sizeof(SmallestElementPerFeature)); -    memset(FeatureFrequency, 0, sizeof(FeatureFrequency));    }    ~InputCorpus() {      for (auto II : Inputs) @@ -70,10 +71,24 @@ class InputCorpus {          Res = std::max(Res, II->U.size());      return Res;    } + +  size_t NumInputsThatTouchFocusFunction() { +    return std::count_if(Inputs.begin(), Inputs.end(), [](const InputInfo *II) { +      return II->HasFocusFunction; +    }); +  } + +  size_t NumInputsWithDataFlowTrace() { +    return std::count_if(Inputs.begin(), Inputs.end(), [](const InputInfo *II) { +      return !II->DataFlowTraceForFocusFunction.empty(); +    }); +  } +    bool empty() const { return Inputs.empty(); }    const Unit &operator[] (size_t Idx) const { return Inputs[Idx]->U; }    void AddToCorpus(const Unit &U, size_t NumFeatures, bool MayDeleteFile, -                   const Vector<uint32_t> &FeatureSet) { +                   bool HasFocusFunction, const Vector<uint32_t> &FeatureSet, +                   const DataFlowTrace &DFT, const InputInfo *BaseII) {      assert(!U.empty());      if (FeatureDebug)        Printf("ADD_TO_CORPUS %zd NF %zd\n", Inputs.size(), NumFeatures); @@ -83,9 +98,19 @@ class InputCorpus {      II.NumFeatures = NumFeatures;      II.MayDeleteFile = MayDeleteFile;      II.UniqFeatureSet = FeatureSet; +    II.HasFocusFunction = HasFocusFunction;      std::sort(II.UniqFeatureSet.begin(), II.UniqFeatureSet.end());      ComputeSHA1(U.data(), U.size(), II.Sha1); -    Hashes.insert(Sha1ToString(II.Sha1)); +    auto Sha1Str = Sha1ToString(II.Sha1); +    Hashes.insert(Sha1Str); +    if (HasFocusFunction) +      if (auto V = DFT.Get(Sha1Str)) +        II.DataFlowTraceForFocusFunction = *V; +    // This is a gross heuristic. +    // Ideally, when we add an element to a corpus we need to know its DFT. +    // But if we don't, we'll use the DFT of its base input. +    if (II.DataFlowTraceForFocusFunction.empty() && BaseII) +      II.DataFlowTraceForFocusFunction = BaseII->DataFlowTraceForFocusFunction;      UpdateCorpusDistribution();      PrintCorpus();      // ValidateFeatureSet(); @@ -157,9 +182,9 @@ class InputCorpus {    void PrintStats() {      for (size_t i = 0; i < Inputs.size(); i++) {        const auto &II = *Inputs[i]; -      Printf("  [%zd %s]\tsz: %zd\truns: %zd\tsucc: %zd\n", i, +      Printf("  [% 3zd %s] sz: % 5zd runs: % 5zd succ: % 5zd focus: %d\n", i,               Sha1ToString(II.Sha1).c_str(), II.U.size(), -             II.NumExecutedMutations, II.NumSuccessfullMutations); +             II.NumExecutedMutations, II.NumSuccessfullMutations, II.HasFocusFunction);      }    } @@ -213,18 +238,10 @@ class InputCorpus {      return false;    } -  void UpdateFeatureFrequency(size_t Idx) { -    FeatureFrequency[Idx % kFeatureSetSize]++; -  } -  float GetFeatureFrequency(size_t Idx) const { -    return FeatureFrequency[Idx % kFeatureSetSize]; -  } -  void UpdateFeatureFrequencyScore(InputInfo *II) { -    const float kMin = 0.01, kMax = 100.; -    II->FeatureFrequencyScore = kMin; -    for (auto Idx : II->UniqFeatureSet) -      II->FeatureFrequencyScore += 1. / (GetFeatureFrequency(Idx) + 1.); -    II->FeatureFrequencyScore = Min(II->FeatureFrequencyScore, kMax); +  bool IsFeatureNew(size_t Idx, uint32_t NewSize, bool Shrink) { +    assert(NewSize); +    uint32_t OldSize = GetFeature(Idx % kFeatureSetSize); +    return OldSize == 0 || (Shrink && OldSize > NewSize);    }    size_t NumFeatures() const { return NumAddedFeatures; } @@ -264,14 +281,11 @@ private:      std::iota(Intervals.begin(), Intervals.end(), 0);      for (size_t i = 0; i < N; i++)        Weights[i] = Inputs[i]->NumFeatures -                       ? (i + 1) * Inputs[i]->FeatureFrequencyScore +                       ? (i + 1) * (Inputs[i]->HasFocusFunction ? 1000 : 1)                         : 0.;      if (FeatureDebug) {        for (size_t i = 0; i < N; i++)          Printf("%zd ", Inputs[i]->NumFeatures); -      Printf("NUM\n"); -      for (size_t i = 0; i < N; i++) -        Printf("%f ", Inputs[i]->FeatureFrequencyScore);        Printf("SCORE\n");        for (size_t i = 0; i < N; i++)          Printf("%f ", Weights[i]); @@ -292,7 +306,6 @@ private:    size_t NumUpdatedFeatures = 0;    uint32_t InputSizesPerFeature[kFeatureSetSize];    uint32_t SmallestElementPerFeature[kFeatureSetSize]; -  float FeatureFrequency[kFeatureSetSize];    std::string OutputCorpus;  }; diff --git a/lib/fuzzer/FuzzerDataFlowTrace.cpp b/lib/fuzzer/FuzzerDataFlowTrace.cpp new file mode 100644 index 0000000000000..764f3e49fd2d3 --- /dev/null +++ b/lib/fuzzer/FuzzerDataFlowTrace.cpp @@ -0,0 +1,91 @@ +//===- FuzzerDataFlowTrace.cpp - DataFlowTrace                ---*- C++ -* ===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// fuzzer::DataFlowTrace +//===----------------------------------------------------------------------===// + +#include "FuzzerDataFlowTrace.h" +#include "FuzzerIO.h" + +#include <cstdlib> +#include <fstream> +#include <string> +#include <vector> + +namespace fuzzer { + +void DataFlowTrace::Init(const std::string &DirPath, +                         const std::string &FocusFunction) { +  if (DirPath.empty()) return; +  const char *kFunctionsTxt = "functions.txt"; +  Printf("INFO: DataFlowTrace: reading from '%s'\n", DirPath.c_str()); +  Vector<SizedFile> Files; +  GetSizedFilesFromDir(DirPath, &Files); +  std::string L; + +  // Read functions.txt +  std::ifstream IF(DirPlusFile(DirPath, kFunctionsTxt)); +  size_t FocusFuncIdx = SIZE_MAX; +  size_t NumFunctions = 0; +  while (std::getline(IF, L, '\n')) { +    NumFunctions++; +    if (FocusFunction == L) +      FocusFuncIdx = NumFunctions - 1; +  } +  if (!NumFunctions || FocusFuncIdx == SIZE_MAX || Files.size() <= 1) +    return; +  // Read traces. +  size_t NumTraceFiles = 0; +  size_t NumTracesWithFocusFunction = 0; +  for (auto &SF : Files) { +    auto Name = Basename(SF.File); +    if (Name == kFunctionsTxt) continue; +    auto ParseError = [&](const char *Err) { +      Printf("DataFlowTrace: parse error: %s\n  File: %s\n  Line: %s\n", Err, +             Name.c_str(), L.c_str()); +    }; +    NumTraceFiles++; +    // Printf("=== %s\n", Name.c_str()); +    std::ifstream IF(SF.File); +    while (std::getline(IF, L, '\n')) { +      size_t SpacePos = L.find(' '); +      if (SpacePos == std::string::npos) +        return ParseError("no space in the trace line"); +      if (L.empty() || L[0] != 'F') +        return ParseError("the trace line doesn't start with 'F'"); +      size_t N = std::atol(L.c_str() + 1); +      if (N >= NumFunctions) +        return ParseError("N is greater than the number of functions"); +      if (N == FocusFuncIdx) { +        NumTracesWithFocusFunction++; +        const char *Beg = L.c_str() + SpacePos + 1; +        const char *End = L.c_str() + L.size(); +        assert(Beg < End); +        size_t Len = End - Beg; +        Vector<uint8_t> V(Len); +        for (size_t I = 0; I < Len; I++) { +          if (Beg[I] != '0' && Beg[I] != '1') +            ParseError("the trace should contain only 0 or 1"); +          V[I] = Beg[I] == '1'; +        } +        Traces[Name] = V; +        // Print just a few small traces. +        if (NumTracesWithFocusFunction <= 3 && Len <= 16) +          Printf("%s => |%s|\n", Name.c_str(), L.c_str() + SpacePos + 1); +        break;  // No need to parse the following lines. +      } +    } +  } +  assert(NumTraceFiles == Files.size() - 1); +  Printf("INFO: DataFlowTrace: %zd trace files, %zd functions, " +         "%zd traces with focus function\n", +         NumTraceFiles, NumFunctions, NumTracesWithFocusFunction); +} + +}  // namespace fuzzer + diff --git a/lib/fuzzer/FuzzerDataFlowTrace.h b/lib/fuzzer/FuzzerDataFlowTrace.h new file mode 100644 index 0000000000000..ad4faeab7b2fe --- /dev/null +++ b/lib/fuzzer/FuzzerDataFlowTrace.h @@ -0,0 +1,56 @@ +//===- FuzzerDataFlowTrace.h - Internal header for the Fuzzer ---*- C++ -* ===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// fuzzer::DataFlowTrace; reads and handles a data-flow trace. +// +// A data flow trace is generated by e.g. dataflow/DataFlow.cpp +// and is stored on disk in a separate directory. +// +// The trace dir contains a file 'functions.txt' which lists function names, +// oner per line, e.g. +// ==> functions.txt <== +// Func2 +// LLVMFuzzerTestOneInput +// Func1 +// +// All other files in the dir are the traces, see dataflow/DataFlow.cpp. +// The name of the file is sha1 of the input used to generate the trace. +// +// Current status: +//   the data is parsed and the summary is printed, but the data is not yet +//   used in any other way. +//===----------------------------------------------------------------------===// + +#ifndef LLVM_FUZZER_DATA_FLOW_TRACE +#define LLVM_FUZZER_DATA_FLOW_TRACE + +#include "FuzzerDefs.h" + +#include <unordered_map> +#include <vector> +#include <string> + +namespace fuzzer { +class DataFlowTrace { + public: +  void Init(const std::string &DirPath, const std::string &FocusFunction); +  void Clear() { Traces.clear(); } +  const Vector<uint8_t> *Get(const std::string &InputSha1) const { +    auto It = Traces.find(InputSha1); +    if (It != Traces.end()) +      return &It->second; +    return nullptr; +  } + + private: +  // Input's sha1 => DFT for the FocusFunction. +  std::unordered_map<std::string, Vector<uint8_t> > Traces; +}; +}  // namespace fuzzer + +#endif // LLVM_FUZZER_DATA_FLOW_TRACE diff --git a/lib/fuzzer/FuzzerDefs.h b/lib/fuzzer/FuzzerDefs.h index 5942efc47a4a1..a35c7a181b74f 100644 --- a/lib/fuzzer/FuzzerDefs.h +++ b/lib/fuzzer/FuzzerDefs.h @@ -27,30 +27,56 @@  #define LIBFUZZER_FUCHSIA 0  #define LIBFUZZER_LINUX 1  #define LIBFUZZER_NETBSD 0 +#define LIBFUZZER_FREEBSD 0 +#define LIBFUZZER_OPENBSD 0  #define LIBFUZZER_WINDOWS 0  #elif __APPLE__  #define LIBFUZZER_APPLE 1  #define LIBFUZZER_FUCHSIA 0  #define LIBFUZZER_LINUX 0  #define LIBFUZZER_NETBSD 0 +#define LIBFUZZER_FREEBSD 0 +#define LIBFUZZER_OPENBSD 0  #define LIBFUZZER_WINDOWS 0  #elif __NetBSD__  #define LIBFUZZER_APPLE 0  #define LIBFUZZER_FUCHSIA 0  #define LIBFUZZER_LINUX 0  #define LIBFUZZER_NETBSD 1 +#define LIBFUZZER_FREEBSD 0 +#define LIBFUZZER_OPENBSD 0 +#define LIBFUZZER_WINDOWS 0 +#elif __FreeBSD__ +#define LIBFUZZER_APPLE 0 +#define LIBFUZZER_FUCHSIA 0 +#define LIBFUZZER_LINUX 0 +#define LIBFUZZER_NETBSD 0 +#define LIBFUZZER_FREEBSD 1 +#define LIBFUZZER_OPENBSD 0 +#define LIBFUZZER_WINDOWS 0 +#elif __OpenBSD__ +#define LIBFUZZER_APPLE 0 +#define LIBFUZZER_FUCHSIA 0 +#define LIBFUZZER_LINUX 0 +#define LIBFUZZER_NETBSD 0 +#define LIBFUZZER_FREEBSD 0 +#define LIBFUZZER_OPENBSD 1  #define LIBFUZZER_WINDOWS 0  #elif _WIN32  #define LIBFUZZER_APPLE 0  #define LIBFUZZER_FUCHSIA 0  #define LIBFUZZER_LINUX 0  #define LIBFUZZER_NETBSD 0 +#define LIBFUZZER_FREEBSD 0 +#define LIBFUZZER_OPENBSD 0  #define LIBFUZZER_WINDOWS 1  #elif __Fuchsia__  #define LIBFUZZER_APPLE 0  #define LIBFUZZER_FUCHSIA 1  #define LIBFUZZER_LINUX 0  #define LIBFUZZER_NETBSD 0 +#define LIBFUZZER_FREEBSD 0 +#define LIBFUZZER_OPENBSD 0  #define LIBFUZZER_WINDOWS 0  #else  #error "Support for your platform has not been implemented" @@ -60,7 +86,9 @@  #  define __has_attribute(x) 0  #endif -#define LIBFUZZER_POSIX (LIBFUZZER_APPLE || LIBFUZZER_LINUX || LIBFUZZER_NETBSD) +#define LIBFUZZER_POSIX                                                        \ +  (LIBFUZZER_APPLE || LIBFUZZER_LINUX || LIBFUZZER_NETBSD ||                   \ +   LIBFUZZER_FREEBSD || LIBFUZZER_OPENBSD)  #ifdef __x86_64  #  if __has_attribute(target) @@ -127,6 +155,11 @@ extern ExternalFunctions *EF;  template<typename T>    class fuzzer_allocator: public std::allocator<T> {      public: +      fuzzer_allocator() = default; + +      template<class U> +      fuzzer_allocator(const fuzzer_allocator<U>&) {} +        template<class Other>        struct rebind { typedef fuzzer_allocator<Other> other;  };    }; @@ -143,12 +176,6 @@ typedef int (*UserCallback)(const uint8_t *Data, size_t Size);  int FuzzerDriver(int *argc, char ***argv, UserCallback Callback); -struct ScopedDoingMyOwnMemOrStr { -  ScopedDoingMyOwnMemOrStr() { DoingMyOwnMemOrStr++; } -  ~ScopedDoingMyOwnMemOrStr() { DoingMyOwnMemOrStr--; } -  static int DoingMyOwnMemOrStr; -}; -  inline uint8_t  Bswap(uint8_t x)  { return x; }  inline uint16_t Bswap(uint16_t x) { return __builtin_bswap16(x); }  inline uint32_t Bswap(uint32_t x) { return __builtin_bswap32(x); } @@ -158,9 +185,7 @@ uint8_t *ExtraCountersBegin();  uint8_t *ExtraCountersEnd();  void ClearExtraCounters(); -uint64_t *ClangCountersBegin(); -uint64_t *ClangCountersEnd(); -void ClearClangCounters(); +extern bool RunningUserCallback;  }  // namespace fuzzer diff --git a/lib/fuzzer/FuzzerDictionary.h b/lib/fuzzer/FuzzerDictionary.h index daf7d003ea915..0d9d91bcd2f15 100644 --- a/lib/fuzzer/FuzzerDictionary.h +++ b/lib/fuzzer/FuzzerDictionary.h @@ -33,17 +33,9 @@ public:    }    bool operator==(const FixedWord<kMaxSize> &w) const { -    ScopedDoingMyOwnMemOrStr scoped_doing_my_own_mem_os_str;      return Size == w.Size && 0 == memcmp(Data, w.Data, Size);    } -  bool operator<(const FixedWord<kMaxSize> &w) const { -    ScopedDoingMyOwnMemOrStr scoped_doing_my_own_mem_os_str; -    if (Size != w.Size) -      return Size < w.Size; -    return memcmp(Data, w.Data, Size) < 0; -  } -    static size_t GetMaxSize() { return kMaxSize; }    const uint8_t *data() const { return Data; }    uint8_t size() const { return Size; } @@ -115,11 +107,11 @@ private:  };  // Parses one dictionary entry. -// If successfull, write the enty to Unit and returns true, +// If successful, write the enty to Unit and returns true,  // otherwise returns false.  bool ParseOneDictionaryEntry(const std::string &Str, Unit *U);  // Parses the dictionary file, fills Units, returns true iff all lines -// were parsed succesfully. +// were parsed successfully.  bool ParseDictionaryFile(const std::string &Text, Vector<Unit> *Units);  }  // namespace fuzzer diff --git a/lib/fuzzer/FuzzerDriver.cpp b/lib/fuzzer/FuzzerDriver.cpp index f6b642daeda75..783474a39e166 100644 --- a/lib/fuzzer/FuzzerDriver.cpp +++ b/lib/fuzzer/FuzzerDriver.cpp @@ -537,6 +537,8 @@ int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) {    EF = new ExternalFunctions();    if (EF->LLVMFuzzerInitialize)      EF->LLVMFuzzerInitialize(argc, argv); +  if (EF->__msan_scoped_disable_interceptor_checks) +    EF->__msan_scoped_disable_interceptor_checks();    const Vector<std::string> Args(*argv, *argv + *argc);    assert(!Args.empty());    ProgName = new std::string(Args[0]); @@ -567,7 +569,7 @@ int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) {    FuzzingOptions Options;    Options.Verbosity = Flags.verbosity;    Options.MaxLen = Flags.max_len; -  Options.ExperimentalLenControl = Flags.experimental_len_control; +  Options.LenControl = Flags.len_control;    Options.UnitTimeoutSec = Flags.timeout;    Options.ErrorExitCode = Flags.error_exitcode;    Options.TimeoutExitCode = Flags.timeout_exitcode; @@ -613,15 +615,22 @@ int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) {    Options.PrintNewCovPcs = Flags.print_pcs;    Options.PrintNewCovFuncs = Flags.print_funcs;    Options.PrintFinalStats = Flags.print_final_stats; +  Options.PrintMutationStats = Flags.print_mutation_stats;    Options.PrintCorpusStats = Flags.print_corpus_stats;    Options.PrintCoverage = Flags.print_coverage; +  Options.PrintUnstableStats = Flags.print_unstable_stats; +  if (Flags.handle_unstable == TracePC::MinUnstable || +      Flags.handle_unstable == TracePC::ZeroUnstable) +    Options.HandleUnstable = Flags.handle_unstable;    Options.DumpCoverage = Flags.dump_coverage; -  Options.UseClangCoverage = Flags.use_clang_coverage; -  Options.UseFeatureFrequency = Flags.use_feature_frequency;    if (Flags.exit_on_src_pos)      Options.ExitOnSrcPos = Flags.exit_on_src_pos;    if (Flags.exit_on_item)      Options.ExitOnItem = Flags.exit_on_item; +  if (Flags.focus_function) +    Options.FocusFunction = Flags.focus_function; +  if (Flags.data_flow_trace) +    Options.DataFlowTrace = Flags.data_flow_trace;    unsigned Seed = Flags.seed;    // Initialize Seed. @@ -665,6 +674,7 @@ int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) {    if (Flags.cleanse_crash)      return CleanseCrashInput(Args, Options); +#if 0  // deprecated, to be removed.    if (auto Name = Flags.run_equivalence_server) {      SMR.Destroy(Name);      if (!SMR.Create(Name)) { @@ -690,6 +700,7 @@ int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) {      }      Printf("INFO: EQUIVALENCE CLIENT UP\n");    } +#endif    if (DoPlainRun) {      Options.SaveArtifacts = false; @@ -747,7 +758,7 @@ int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) {        Printf("Dictionary analysis failed\n");        exit(1);      } -    Printf("Dictionary analysis suceeded\n"); +    Printf("Dictionary analysis succeeded\n");      exit(0);    } diff --git a/lib/fuzzer/FuzzerExtFunctions.def b/lib/fuzzer/FuzzerExtFunctions.def index 25a655bfd71dd..8bfffdde56d47 100644 --- a/lib/fuzzer/FuzzerExtFunctions.def +++ b/lib/fuzzer/FuzzerExtFunctions.def @@ -29,6 +29,7 @@ EXT_FUNC(LLVMFuzzerCustomCrossOver, size_t,  EXT_FUNC(__lsan_enable, void, (), false);  EXT_FUNC(__lsan_disable, void, (), false);  EXT_FUNC(__lsan_do_recoverable_leak_check, int, (), false); +EXT_FUNC(__sanitizer_acquire_crash_state, bool, (), true);  EXT_FUNC(__sanitizer_install_malloc_and_free_hooks, int,           (void (*malloc_hook)(const volatile void *, size_t),            void (*free_hook)(const volatile void *)), @@ -45,3 +46,6 @@ EXT_FUNC(__sanitizer_set_death_callback, void, (void (*)(void)), true);  EXT_FUNC(__sanitizer_set_report_fd, void, (void*), false);  EXT_FUNC(__sanitizer_dump_coverage, void, (const uintptr_t *, uintptr_t),           false); +EXT_FUNC(__msan_scoped_disable_interceptor_checks, void, (), false); +EXT_FUNC(__msan_scoped_enable_interceptor_checks, void, (), false); +EXT_FUNC(__msan_unpoison, void, (const volatile void *, size_t size), false); diff --git a/lib/fuzzer/FuzzerExtFunctionsWeak.cpp b/lib/fuzzer/FuzzerExtFunctionsWeak.cpp index 5a90723986afe..a4e56fc27b8de 100644 --- a/lib/fuzzer/FuzzerExtFunctionsWeak.cpp +++ b/lib/fuzzer/FuzzerExtFunctionsWeak.cpp @@ -13,7 +13,8 @@  // to clients right now.  //===----------------------------------------------------------------------===//  #include "FuzzerDefs.h" -#if LIBFUZZER_LINUX || LIBFUZZER_NETBSD || LIBFUZZER_FUCHSIA +#if LIBFUZZER_LINUX || LIBFUZZER_NETBSD || LIBFUZZER_FUCHSIA ||                \ +    LIBFUZZER_FREEBSD || LIBFUZZER_OPENBSD  #include "FuzzerExtFunctions.h"  #include "FuzzerIO.h" @@ -51,4 +52,4 @@ ExternalFunctions::ExternalFunctions() {  } // namespace fuzzer -#endif // LIBFUZZER_LINUX || LIBFUZZER_NETBSD +#endif diff --git a/lib/fuzzer/FuzzerExtraCounters.cpp b/lib/fuzzer/FuzzerExtraCounters.cpp index 0e7a7761bf806..c99cd89be293a 100644 --- a/lib/fuzzer/FuzzerExtraCounters.cpp +++ b/lib/fuzzer/FuzzerExtraCounters.cpp @@ -11,7 +11,8 @@  #include "FuzzerDefs.h" -#if LIBFUZZER_LINUX || LIBFUZZER_NETBSD +#if LIBFUZZER_LINUX || LIBFUZZER_NETBSD || LIBFUZZER_FREEBSD ||                \ +    LIBFUZZER_OPENBSD  __attribute__((weak)) extern uint8_t __start___libfuzzer_extra_counters;  __attribute__((weak)) extern uint8_t __stop___libfuzzer_extra_counters; diff --git a/lib/fuzzer/FuzzerFlags.def b/lib/fuzzer/FuzzerFlags.def index a32102a7da073..ba04bc25fd45a 100644 --- a/lib/fuzzer/FuzzerFlags.def +++ b/lib/fuzzer/FuzzerFlags.def @@ -17,7 +17,10 @@ FUZZER_FLAG_INT(runs, -1,  FUZZER_FLAG_INT(max_len, 0, "Maximum length of the test input. "      "If 0, libFuzzer tries to guess a good value based on the corpus "      "and reports it. ") -FUZZER_FLAG_INT(experimental_len_control, 0, "experimental flag") +FUZZER_FLAG_INT(len_control, 1000, "Try generating small inputs first, " +  "then try larger inputs over time.  Specifies the rate at which the length " +  "limit is increased (smaller == faster).  If 0, immediately try inputs with " +  "size up to max_len.")  FUZZER_FLAG_INT(cross_over, 1, "If 1, cross over inputs.")  FUZZER_FLAG_INT(mutate_depth, 5,              "Apply this number of consecutive mutations to each input.") @@ -42,7 +45,7 @@ FUZZER_FLAG_INT(merge, 0, "If 1, the 2-nd, 3-rd, etc corpora will be "    "This flag can be used to minimize a corpus.")  FUZZER_FLAG_STRING(merge_inner, "internal flag")  FUZZER_FLAG_STRING(merge_control_file, -                   "Specify a control file used for the merge proccess. " +                   "Specify a control file used for the merge process. "                     "If a merge process gets killed it tries to leave this file "                     "in a state suitable for resuming the merge. "                     "By default a temporary file will be used.") @@ -107,6 +110,15 @@ FUZZER_FLAG_INT(print_coverage, 0, "If 1, print coverage information as text"  FUZZER_FLAG_INT(dump_coverage, 0, "Deprecated."                                    " If 1, dump coverage information as a"                                    " .sancov file at exit.") +FUZZER_FLAG_INT(handle_unstable, 0, "Experimental." +                   " Executes every input 3 times in total if a unique feature" +                   " is found during the first execution." +                   " If 1, we only use the minimum hit count from the 3 runs" +                   " to determine whether an input is interesting." +                   " If 2, we disregard edges that are found unstable for" +                   " feature collection.") +FUZZER_FLAG_INT(print_unstable_stats, 0, "Experimental." +				  " If 1, print unstable statistics at exit.")  FUZZER_FLAG_INT(handle_segv, 1, "If 1, try to intercept SIGSEGV.")  FUZZER_FLAG_INT(handle_bus, 1, "If 1, try to intercept SIGBUS.")  FUZZER_FLAG_INT(handle_abrt, 1, "If 1, try to intercept SIGABRT.") @@ -142,9 +154,12 @@ FUZZER_FLAG_STRING(exit_on_item, "Exit if an item with a given sha1 sum"  FUZZER_FLAG_INT(ignore_remaining_args, 0, "If 1, ignore all arguments passed "                  "after this one. Useful for fuzzers that need to do their own "                  "argument parsing.") +FUZZER_FLAG_STRING(focus_function, "Experimental. " +     "Fuzzing will focus on inputs that trigger calls to this function") -FUZZER_FLAG_STRING(run_equivalence_server, "Experimental") -FUZZER_FLAG_STRING(use_equivalence_server, "Experimental") +FUZZER_DEPRECATED_FLAG(run_equivalence_server) +FUZZER_DEPRECATED_FLAG(use_equivalence_server)  FUZZER_FLAG_INT(analyze_dict, 0, "Experimental") -FUZZER_FLAG_INT(use_clang_coverage, 0, "Experimental") -FUZZER_FLAG_INT(use_feature_frequency, 0, "Experimental/internal") +FUZZER_DEPRECATED_FLAG(use_clang_coverage) +FUZZER_FLAG_STRING(data_flow_trace, "Experimental: use the data flow trace") +FUZZER_FLAG_INT(print_mutation_stats, 0, "Experimental") diff --git a/lib/fuzzer/FuzzerIO.cpp b/lib/fuzzer/FuzzerIO.cpp index dac5ec658f1ce..f3ead0ec53571 100644 --- a/lib/fuzzer/FuzzerIO.cpp +++ b/lib/fuzzer/FuzzerIO.cpp @@ -100,6 +100,14 @@ std::string DirPlusFile(const std::string &DirPath,    return DirPath + GetSeparator() + FileName;  } +std::string Basename(const std::string &Path, char Separator) { +  size_t Pos = Path.rfind(Separator); +  if (Pos == std::string::npos) +    return Path; +  assert(Pos < Path.size()); +  return Path.substr(Pos + 1); +} +  void DupAndCloseStderr() {    int OutputFd = DuplicateFile(2);    if (OutputFd > 0) { diff --git a/lib/fuzzer/FuzzerIO.h b/lib/fuzzer/FuzzerIO.h index ea9f0d5a6703c..6d7757435b7bf 100644 --- a/lib/fuzzer/FuzzerIO.h +++ b/lib/fuzzer/FuzzerIO.h @@ -67,6 +67,8 @@ struct SizedFile {  void GetSizedFilesFromDir(const std::string &Dir, Vector<SizedFile> *V);  char GetSeparator(); +// Similar to the basename utility: returns the file name w/o the dir prefix. +std::string Basename(const std::string &Path, char Separator = GetSeparator());  FILE* OpenFile(int Fd, const char *Mode); diff --git a/lib/fuzzer/FuzzerIOPosix.cpp b/lib/fuzzer/FuzzerIOPosix.cpp index 2257751c662d7..17e884d3c4c3b 100644 --- a/lib/fuzzer/FuzzerIOPosix.cpp +++ b/lib/fuzzer/FuzzerIOPosix.cpp @@ -54,7 +54,7 @@ void ListFilesInDirRecursive(const std::string &Dir, long *Epoch,    DIR *D = opendir(Dir.c_str());    if (!D) { -    Printf("No such directory: %s; exiting\n", Dir.c_str()); +    Printf("%s: %s; exiting\n", strerror(errno), Dir.c_str());      exit(1);    }    while (auto E = readdir(D)) { diff --git a/lib/fuzzer/FuzzerInterface.h b/lib/fuzzer/FuzzerInterface.h index c2c0a39843c04..0f7effb2ab6a2 100644 --- a/lib/fuzzer/FuzzerInterface.h +++ b/lib/fuzzer/FuzzerInterface.h @@ -30,35 +30,39 @@ extern "C" {  // Executes the code under test with [Data, Data+Size) as the input.  // libFuzzer will invoke this function *many* times with different inputs.  // Must return 0. -int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size); +__attribute__((visibility("default"))) int +LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size);  // Optional user-provided initialization function.  // If provided, this function will be called by libFuzzer once at startup.  // It may read and modify argc/argv.  // Must return 0. -int LLVMFuzzerInitialize(int *argc, char ***argv); +__attribute__((visibility("default"))) int LLVMFuzzerInitialize(int *argc, +                                                                char ***argv);  // Optional user-provided custom mutator.  // Mutates raw data in [Data, Data+Size) inplace.  // Returns the new size, which is not greater than MaxSize.  // Given the same Seed produces the same mutation. -size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size, size_t MaxSize, -                               unsigned int Seed); +__attribute__((visibility("default"))) size_t +LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size, size_t MaxSize, +                        unsigned int Seed);  // Optional user-provided custom cross-over function.  // Combines pieces of Data1 & Data2 together into Out.  // Returns the new size, which is not greater than MaxOutSize.  // Should produce the same mutation given the same Seed. -size_t LLVMFuzzerCustomCrossOver(const uint8_t *Data1, size_t Size1, -                                 const uint8_t *Data2, size_t Size2, -                                 uint8_t *Out, size_t MaxOutSize, -                                 unsigned int Seed); +__attribute__((visibility("default"))) size_t +LLVMFuzzerCustomCrossOver(const uint8_t *Data1, size_t Size1, +                          const uint8_t *Data2, size_t Size2, uint8_t *Out, +                          size_t MaxOutSize, unsigned int Seed);  // Experimental, may go away in future.  // libFuzzer-provided function to be used inside LLVMFuzzerCustomMutator.  // Mutates raw data in [Data, Data+Size) inplace.  // Returns the new size, which is not greater than MaxSize. -size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize); +__attribute__((visibility("default"))) size_t +LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize);  #ifdef __cplusplus  }  // extern "C" diff --git a/lib/fuzzer/FuzzerInternal.h b/lib/fuzzer/FuzzerInternal.h index 2b2638f1f8f29..bfc898248adb1 100644 --- a/lib/fuzzer/FuzzerInternal.h +++ b/lib/fuzzer/FuzzerInternal.h @@ -12,6 +12,7 @@  #ifndef LLVM_FUZZER_INTERNAL_H  #define LLVM_FUZZER_INTERNAL_H +#include "FuzzerDataFlowTrace.h"  #include "FuzzerDefs.h"  #include "FuzzerExtFunctions.h"  #include "FuzzerInterface.h" @@ -66,6 +67,7 @@ public:    static void StaticGracefulExitCallback();    void ExecuteCallback(const uint8_t *Data, size_t Size); +  void CheckForUnstableCounters(const uint8_t *Data, size_t Size);    bool RunOne(const uint8_t *Data, size_t Size, bool MayDeleteFile = false,                InputInfo *II = nullptr, bool *FoundUniqFeatures = nullptr); @@ -116,7 +118,6 @@ private:    uint8_t *CurrentUnitData = nullptr;    std::atomic<size_t> CurrentUnitSize;    uint8_t BaseSha1[kSHA1NumBytes];  // Checksum of the base unit. -  bool RunningCB = false;    bool GracefulExitRequested = false; @@ -134,6 +135,7 @@ private:    InputCorpus &Corpus;    MutationDispatcher &MD;    FuzzingOptions Options; +  DataFlowTrace DFT;    system_clock::time_point ProcessStartTime = system_clock::now();    system_clock::time_point UnitStartTime, UnitStopTime; @@ -150,6 +152,28 @@ private:    static thread_local bool IsMyThread;  }; +struct ScopedEnableMsanInterceptorChecks { +  ScopedEnableMsanInterceptorChecks() { +    if (EF->__msan_scoped_enable_interceptor_checks) +      EF->__msan_scoped_enable_interceptor_checks(); +  } +  ~ScopedEnableMsanInterceptorChecks() { +    if (EF->__msan_scoped_disable_interceptor_checks) +      EF->__msan_scoped_disable_interceptor_checks(); +  } +}; + +struct ScopedDisableMsanInterceptorChecks { +  ScopedDisableMsanInterceptorChecks() { +    if (EF->__msan_scoped_disable_interceptor_checks) +      EF->__msan_scoped_disable_interceptor_checks(); +  } +  ~ScopedDisableMsanInterceptorChecks() { +    if (EF->__msan_scoped_enable_interceptor_checks) +      EF->__msan_scoped_enable_interceptor_checks(); +  } +}; +  } // namespace fuzzer  #endif // LLVM_FUZZER_INTERNAL_H diff --git a/lib/fuzzer/FuzzerLoop.cpp b/lib/fuzzer/FuzzerLoop.cpp index 5b451ca122d7e..4bc88365a0b97 100644 --- a/lib/fuzzer/FuzzerLoop.cpp +++ b/lib/fuzzer/FuzzerLoop.cpp @@ -43,6 +43,8 @@ thread_local bool Fuzzer::IsMyThread;  SharedMemoryRegion SMR; +bool RunningUserCallback = false; +  // Only one Fuzzer per process.  static Fuzzer *F; @@ -105,7 +107,7 @@ void MallocHook(const volatile void *ptr, size_t size) {        return;      Printf("MALLOC[%zd] %p %zd\n", N, ptr, size);      if (TraceLevel >= 2 && EF) -      EF->__sanitizer_print_stack_trace(); +      PrintStackTrace();    }  } @@ -118,7 +120,7 @@ void FreeHook(const volatile void *ptr) {        return;      Printf("FREE[%zd]   %p\n", N, ptr);      if (TraceLevel >= 2 && EF) -      EF->__sanitizer_print_stack_trace(); +      PrintStackTrace();    }  } @@ -129,8 +131,7 @@ void Fuzzer::HandleMalloc(size_t Size) {    Printf("==%d== ERROR: libFuzzer: out-of-memory (malloc(%zd))\n", GetPid(),           Size);    Printf("   To change the out-of-memory limit use -rss_limit_mb=<N>\n\n"); -  if (EF->__sanitizer_print_stack_trace) -    EF->__sanitizer_print_stack_trace(); +  PrintStackTrace();    DumpCurrentUnit("oom-");    Printf("SUMMARY: libFuzzer: out-of-memory\n");    PrintFinalStats(); @@ -149,8 +150,7 @@ Fuzzer::Fuzzer(UserCallback CB, InputCorpus &Corpus, MutationDispatcher &MD,    if (Options.DetectLeaks && EF->__sanitizer_install_malloc_and_free_hooks)      EF->__sanitizer_install_malloc_and_free_hooks(MallocHook, FreeHook);    TPC.SetUseCounters(Options.UseCounters); -  TPC.SetUseValueProfile(Options.UseValueProfile); -  TPC.SetUseClangCoverage(Options.UseClangCoverage); +  TPC.SetUseValueProfileMask(Options.UseValueProfile);    if (Options.Verbosity)      TPC.PrintModuleInfo(); @@ -161,6 +161,8 @@ Fuzzer::Fuzzer(UserCallback CB, InputCorpus &Corpus, MutationDispatcher &MD,    AllocateCurrentUnitData();    CurrentUnitSize = 0;    memset(BaseSha1, 0, sizeof(BaseSha1)); +  TPC.SetFocusFunction(Options.FocusFunction); +  DFT.Init(Options.DataFlowTrace, Options.FocusFunction);  }  Fuzzer::~Fuzzer() {} @@ -179,6 +181,7 @@ void Fuzzer::StaticDeathCallback() {  void Fuzzer::DumpCurrentUnit(const char *Prefix) {    if (!CurrentUnitData)      return; // Happens when running individual inputs. +  ScopedDisableMsanInterceptorChecks S;    MD.PrintMutationSequence();    Printf("; base unit: %s\n", Sha1ToString(BaseSha1).c_str());    size_t UnitSize = CurrentUnitSize; @@ -228,9 +231,10 @@ void Fuzzer::StaticFileSizeExceedCallback() {  }  void Fuzzer::CrashCallback() { +  if (EF->__sanitizer_acquire_crash_state) +    EF->__sanitizer_acquire_crash_state();    Printf("==%lu== ERROR: libFuzzer: deadly signal\n", GetPid()); -  if (EF->__sanitizer_print_stack_trace) -    EF->__sanitizer_print_stack_trace(); +  PrintStackTrace();    Printf("NOTE: libFuzzer has rudimentary signal handlers.\n"           "      Combine libFuzzer with AddressSanitizer or similar for better "           "crash reports.\n"); @@ -241,11 +245,13 @@ void Fuzzer::CrashCallback() {  }  void Fuzzer::ExitCallback() { -  if (!RunningCB) +  if (!RunningUserCallback)      return; // This exit did not come from the user callback +  if (EF->__sanitizer_acquire_crash_state && +      !EF->__sanitizer_acquire_crash_state()) +    return;    Printf("==%lu== ERROR: libFuzzer: fuzz target exited\n", GetPid()); -  if (EF->__sanitizer_print_stack_trace) -    EF->__sanitizer_print_stack_trace(); +  PrintStackTrace();    Printf("SUMMARY: libFuzzer: fuzz target exited\n");    DumpCurrentUnit("crash-");    PrintFinalStats(); @@ -273,7 +279,7 @@ void Fuzzer::AlarmCallback() {    if (!InFuzzingThread())      return;  #endif -  if (!RunningCB) +  if (!RunningUserCallback)      return; // We have not started running units yet.    size_t Seconds =        duration_cast<seconds>(system_clock::now() - UnitStartTime).count(); @@ -282,14 +288,16 @@ void Fuzzer::AlarmCallback() {    if (Options.Verbosity >= 2)      Printf("AlarmCallback %zd\n", Seconds);    if (Seconds >= (size_t)Options.UnitTimeoutSec) { +    if (EF->__sanitizer_acquire_crash_state && +        !EF->__sanitizer_acquire_crash_state()) +      return;      Printf("ALARM: working on the last Unit for %zd seconds\n", Seconds);      Printf("       and the timeout value is %d (use -timeout=N to change)\n",             Options.UnitTimeoutSec);      DumpCurrentUnit("timeout-");      Printf("==%lu== ERROR: libFuzzer: timeout after %d seconds\n", GetPid(),             Seconds); -    if (EF->__sanitizer_print_stack_trace) -      EF->__sanitizer_print_stack_trace(); +    PrintStackTrace();      Printf("SUMMARY: libFuzzer: timeout\n");      PrintFinalStats();      _Exit(Options.TimeoutExitCode); // Stop right now. @@ -297,12 +305,14 @@ void Fuzzer::AlarmCallback() {  }  void Fuzzer::RssLimitCallback() { +  if (EF->__sanitizer_acquire_crash_state && +      !EF->__sanitizer_acquire_crash_state()) +    return;    Printf(        "==%lu== ERROR: libFuzzer: out-of-memory (used: %zdMb; limit: %zdMb)\n",        GetPid(), GetPeakRSSMb(), Options.RssLimitMb);    Printf("   To change the out-of-memory limit use -rss_limit_mb=<N>\n\n"); -  if (EF->__sanitizer_print_memory_profile) -    EF->__sanitizer_print_memory_profile(95, 8); +  PrintMemoryProfile();    DumpCurrentUnit("oom-");    Printf("SUMMARY: libFuzzer: out-of-memory\n");    PrintFinalStats(); @@ -328,7 +338,11 @@ void Fuzzer::PrintStats(const char *Where, const char *End, size_t Units) {        else          Printf("/%zdMb", N >> 20);      } +    if (size_t FF = Corpus.NumInputsThatTouchFocusFunction()) +      Printf(" focus: %zd", FF);    } +  if (TmpMaxMutationLen) +    Printf(" lim: %zd", TmpMaxMutationLen);    if (Units)      Printf(" units: %zd", Units); @@ -340,10 +354,13 @@ void Fuzzer::PrintStats(const char *Where, const char *End, size_t Units) {  void Fuzzer::PrintFinalStats() {    if (Options.PrintCoverage)      TPC.PrintCoverage(); +  if (Options.PrintUnstableStats) +    TPC.PrintUnstableStats();    if (Options.DumpCoverage)      TPC.DumpCoverage();    if (Options.PrintCorpusStats)      Corpus.PrintStats(); +  if (Options.PrintMutationStats) MD.PrintMutationStats();    if (!Options.PrintFinalStats)      return;    size_t ExecPerSec = execPerSec(); @@ -432,6 +449,34 @@ void Fuzzer::PrintPulseAndReportSlowInput(const uint8_t *Data, size_t Size) {    }  } +void Fuzzer::CheckForUnstableCounters(const uint8_t *Data, size_t Size) { +  auto CBSetupAndRun = [&]() { +    ScopedEnableMsanInterceptorChecks S; +    UnitStartTime = system_clock::now(); +    TPC.ResetMaps(); +    RunningUserCallback = true; +    CB(Data, Size); +    RunningUserCallback = false; +    UnitStopTime = system_clock::now(); +  }; + +  // Copy original run counters into our unstable counters +  TPC.InitializeUnstableCounters(); + +  // First Rerun +  CBSetupAndRun(); +  TPC.UpdateUnstableCounters(Options.HandleUnstable); + +  // Second Rerun +  CBSetupAndRun(); +  TPC.UpdateUnstableCounters(Options.HandleUnstable); + +  // Move minimum hit counts back to ModuleInline8bitCounters +  if (Options.HandleUnstable == TracePC::MinUnstable || +      Options.HandleUnstable == TracePC::ZeroUnstable) +    TPC.ApplyUnstableCounters(); +} +  bool Fuzzer::RunOne(const uint8_t *Data, size_t Size, bool MayDeleteFile,                      InputInfo *II, bool *FoundUniqFeatures) {    if (!Size) @@ -442,9 +487,18 @@ bool Fuzzer::RunOne(const uint8_t *Data, size_t Size, bool MayDeleteFile,    UniqFeatureSetTmp.clear();    size_t FoundUniqFeaturesOfII = 0;    size_t NumUpdatesBefore = Corpus.NumFeatureUpdates(); +  bool NewFeaturesUnstable = false; + +  if (Options.HandleUnstable || Options.PrintUnstableStats) { +    TPC.CollectFeatures([&](size_t Feature) { +      if (Corpus.IsFeatureNew(Feature, Size, Options.Shrink)) +        NewFeaturesUnstable = true; +    }); +    if (NewFeaturesUnstable) +      CheckForUnstableCounters(Data, Size); +  } +    TPC.CollectFeatures([&](size_t Feature) { -    if (Options.UseFeatureFrequency) -      Corpus.UpdateFeatureFrequency(Feature);      if (Corpus.AddFeature(Feature, Size, Options.Shrink))        UniqFeatureSetTmp.push_back(Feature);      if (Options.ReduceInputs && II) @@ -452,17 +506,20 @@ bool Fuzzer::RunOne(const uint8_t *Data, size_t Size, bool MayDeleteFile,                               II->UniqFeatureSet.end(), Feature))          FoundUniqFeaturesOfII++;    }); +    if (FoundUniqFeatures)      *FoundUniqFeatures = FoundUniqFeaturesOfII;    PrintPulseAndReportSlowInput(Data, Size);    size_t NumNewFeatures = Corpus.NumFeatureUpdates() - NumUpdatesBefore; +    if (NumNewFeatures) {      TPC.UpdateObservedPCs();      Corpus.AddToCorpus({Data, Data + Size}, NumNewFeatures, MayDeleteFile, -                       UniqFeatureSetTmp); +                       TPC.ObservedFocusFunction(), UniqFeatureSetTmp, DFT, II);      return true;    }    if (II && FoundUniqFeaturesOfII && +      II->DataFlowTraceForFocusFunction.empty() &&        FoundUniqFeaturesOfII == II->UniqFeatureSet.size() &&        II->U.size() > Size) {      Corpus.Replace(II, {Data, Data + Size}); @@ -505,19 +562,24 @@ void Fuzzer::ExecuteCallback(const uint8_t *Data, size_t Size) {    // so that we reliably find buffer overflows in it.    uint8_t *DataCopy = new uint8_t[Size];    memcpy(DataCopy, Data, Size); +  if (EF->__msan_unpoison) +    EF->__msan_unpoison(DataCopy, Size);    if (CurrentUnitData && CurrentUnitData != Data)      memcpy(CurrentUnitData, Data, Size);    CurrentUnitSize = Size; -  AllocTracer.Start(Options.TraceMalloc); -  UnitStartTime = system_clock::now(); -  TPC.ResetMaps(); -  RunningCB = true; -  int Res = CB(DataCopy, Size); -  RunningCB = false; -  UnitStopTime = system_clock::now(); -  (void)Res; -  assert(Res == 0); -  HasMoreMallocsThanFrees = AllocTracer.Stop(); +  { +    ScopedEnableMsanInterceptorChecks S; +    AllocTracer.Start(Options.TraceMalloc); +    UnitStartTime = system_clock::now(); +    TPC.ResetMaps(); +    RunningUserCallback = true; +    int Res = CB(DataCopy, Size); +    RunningUserCallback = false; +    UnitStopTime = system_clock::now(); +    (void)Res; +    assert(Res == 0); +    HasMoreMallocsThanFrees = AllocTracer.Stop(); +  }    if (!LooseMemeq(DataCopy, Data, Size))      CrashOnOverwrittenData();    CurrentUnitSize = 0; @@ -618,8 +680,6 @@ void Fuzzer::MutateAndTestOne() {    MD.StartMutationSequence();    auto &II = Corpus.ChooseUnitToMutate(MD.GetRand()); -  if (Options.UseFeatureFrequency) -    Corpus.UpdateFeatureFrequencyScore(&II);    const auto &U = II.U;    memcpy(BaseSha1, II.Sha1, sizeof(BaseSha1));    assert(CurrentUnitData); @@ -638,7 +698,12 @@ void Fuzzer::MutateAndTestOne() {        break;      MaybeExitGracefully();      size_t NewSize = 0; -    NewSize = MD.Mutate(CurrentUnitData, Size, CurrentMaxMutationLen); +    if (II.HasFocusFunction && !II.DataFlowTraceForFocusFunction.empty() && +        Size <= CurrentMaxMutationLen) +      NewSize = MD.MutateWithMask(CurrentUnitData, Size, Size, +                                  II.DataFlowTraceForFocusFunction); +    else +      NewSize = MD.Mutate(CurrentUnitData, Size, CurrentMaxMutationLen);      assert(NewSize > 0 && "Mutator returned empty unit");      assert(NewSize <= CurrentMaxMutationLen && "Mutator return oversized unit");      Size = NewSize; @@ -728,7 +793,14 @@ void Fuzzer::ReadAndExecuteSeedCorpora(const Vector<std::string> &CorpusDirs) {    }    PrintStats("INITED"); -  if (Corpus.empty()) { +  if (!Options.FocusFunction.empty()) +    Printf("INFO: %zd/%zd inputs touch the focus function\n", +           Corpus.NumInputsThatTouchFocusFunction(), Corpus.size()); +  if (!Options.DataFlowTrace.empty()) +    Printf("INFO: %zd/%zd inputs have the Data Flow Trace\n", +           Corpus.NumInputsWithDataFlowTrace(), Corpus.size()); + +  if (Corpus.empty() && Options.MaxNumberOfRuns) {      Printf("ERROR: no interesting inputs were found. "             "Is the code instrumented for coverage? Exiting.\n");      exit(1); @@ -737,6 +809,7 @@ void Fuzzer::ReadAndExecuteSeedCorpora(const Vector<std::string> &CorpusDirs) {  void Fuzzer::Loop(const Vector<std::string> &CorpusDirs) {    ReadAndExecuteSeedCorpora(CorpusDirs); +  DFT.Clear();  // No need for DFT any more.    TPC.SetPrintNewPCs(Options.PrintNewCovPcs);    TPC.SetPrintNewFuncs(Options.PrintNewCovFuncs);    system_clock::time_point LastCorpusReload = system_clock::now(); @@ -755,16 +828,12 @@ void Fuzzer::Loop(const Vector<std::string> &CorpusDirs) {        break;      // Update TmpMaxMutationLen -    if (Options.ExperimentalLenControl) { +    if (Options.LenControl) {        if (TmpMaxMutationLen < MaxMutationLen &&            TotalNumberOfRuns - LastCorpusUpdateRun > -              Options.ExperimentalLenControl * Log(TmpMaxMutationLen)) { +              Options.LenControl * Log(TmpMaxMutationLen)) {          TmpMaxMutationLen =              Min(MaxMutationLen, TmpMaxMutationLen + Log(TmpMaxMutationLen)); -        if (TmpMaxMutationLen <= MaxMutationLen) -          Printf("#%zd\tTEMP_MAX_LEN: %zd (%zd %zd)\n", TotalNumberOfRuns, -                 TmpMaxMutationLen, Options.ExperimentalLenControl, -                 LastCorpusUpdateRun);          LastCorpusUpdateRun = TotalNumberOfRuns;        }      } else { @@ -826,13 +895,15 @@ void Fuzzer::AnnounceOutput(const uint8_t *Data, size_t Size) {  extern "C" { -size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize) { +__attribute__((visibility("default"))) size_t +LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize) {    assert(fuzzer::F);    return fuzzer::F->GetMD().DefaultMutate(Data, Size, MaxSize);  }  // Experimental -void LLVMFuzzerAnnounceOutput(const uint8_t *Data, size_t Size) { +__attribute__((visibility("default"))) void +LLVMFuzzerAnnounceOutput(const uint8_t *Data, size_t Size) {    assert(fuzzer::F);    fuzzer::F->AnnounceOutput(Data, Size);  } diff --git a/lib/fuzzer/FuzzerMain.cpp b/lib/fuzzer/FuzzerMain.cpp index af8657200be29..f2c8e9c7bb111 100644 --- a/lib/fuzzer/FuzzerMain.cpp +++ b/lib/fuzzer/FuzzerMain.cpp @@ -16,6 +16,6 @@ extern "C" {  int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size);  }  // extern "C" -int main(int argc, char **argv) { +__attribute__((visibility("default"))) int main(int argc, char **argv) {    return fuzzer::FuzzerDriver(&argc, &argv, LLVMFuzzerTestOneInput);  } diff --git a/lib/fuzzer/FuzzerMutate.cpp b/lib/fuzzer/FuzzerMutate.cpp index 9ee5299f1b60c..ff076cca683fb 100644 --- a/lib/fuzzer/FuzzerMutate.cpp +++ b/lib/fuzzer/FuzzerMutate.cpp @@ -30,39 +30,41 @@ MutationDispatcher::MutationDispatcher(Random &Rand,    DefaultMutators.insert(        DefaultMutators.begin(),        { -          {&MutationDispatcher::Mutate_EraseBytes, "EraseBytes"}, -          {&MutationDispatcher::Mutate_InsertByte, "InsertByte"}, +          {&MutationDispatcher::Mutate_EraseBytes, "EraseBytes", 0, 0}, +          {&MutationDispatcher::Mutate_InsertByte, "InsertByte", 0, 0},            {&MutationDispatcher::Mutate_InsertRepeatedBytes, -           "InsertRepeatedBytes"}, -          {&MutationDispatcher::Mutate_ChangeByte, "ChangeByte"}, -          {&MutationDispatcher::Mutate_ChangeBit, "ChangeBit"}, -          {&MutationDispatcher::Mutate_ShuffleBytes, "ShuffleBytes"}, -          {&MutationDispatcher::Mutate_ChangeASCIIInteger, "ChangeASCIIInt"}, -          {&MutationDispatcher::Mutate_ChangeBinaryInteger, "ChangeBinInt"}, -          {&MutationDispatcher::Mutate_CopyPart, "CopyPart"}, -          {&MutationDispatcher::Mutate_CrossOver, "CrossOver"}, +           "InsertRepeatedBytes", 0, 0}, +          {&MutationDispatcher::Mutate_ChangeByte, "ChangeByte", 0, 0}, +          {&MutationDispatcher::Mutate_ChangeBit, "ChangeBit", 0, 0}, +          {&MutationDispatcher::Mutate_ShuffleBytes, "ShuffleBytes", 0, 0}, +          {&MutationDispatcher::Mutate_ChangeASCIIInteger, "ChangeASCIIInt", 0, +           0}, +          {&MutationDispatcher::Mutate_ChangeBinaryInteger, "ChangeBinInt", 0, +           0}, +          {&MutationDispatcher::Mutate_CopyPart, "CopyPart", 0, 0}, +          {&MutationDispatcher::Mutate_CrossOver, "CrossOver", 0, 0},            {&MutationDispatcher::Mutate_AddWordFromManualDictionary, -           "ManualDict"}, +           "ManualDict", 0, 0},            {&MutationDispatcher::Mutate_AddWordFromPersistentAutoDictionary, -           "PersAutoDict"}, +           "PersAutoDict", 0, 0},        });    if(Options.UseCmp)      DefaultMutators.push_back( -        {&MutationDispatcher::Mutate_AddWordFromTORC, "CMP"}); +        {&MutationDispatcher::Mutate_AddWordFromTORC, "CMP", 0, 0});    if (EF->LLVMFuzzerCustomMutator) -    Mutators.push_back({&MutationDispatcher::Mutate_Custom, "Custom"}); +    Mutators.push_back({&MutationDispatcher::Mutate_Custom, "Custom", 0, 0});    else      Mutators = DefaultMutators;    if (EF->LLVMFuzzerCustomCrossOver)      Mutators.push_back( -        {&MutationDispatcher::Mutate_CustomCrossOver, "CustomCrossOver"}); +        {&MutationDispatcher::Mutate_CustomCrossOver, "CustomCrossOver", 0, 0});  }  static char RandCh(Random &Rand) {    if (Rand.RandBool()) return Rand(256); -  const char *Special = "!*'();:@&=+$,/?%#[]012Az-`~.\xff\x00"; +  const char Special[] = "!*'();:@&=+$,/?%#[]012Az-`~.\xff\x00";    return Special[Rand(sizeof(Special) - 1)];  } @@ -195,7 +197,6 @@ DictionaryEntry MutationDispatcher::MakeDictionaryEntryFromCMP(      const void *Arg1Mutation, const void *Arg2Mutation,      size_t ArgSize, const uint8_t *Data,      size_t Size) { -  ScopedDoingMyOwnMemOrStr scoped_doing_my_own_mem_os_str;    bool HandleFirst = Rand.RandBool();    const void *ExistingBytes, *DesiredBytes;    Word W; @@ -339,7 +340,9 @@ size_t MutationDispatcher::InsertPartOf(const uint8_t *From, size_t FromSize,  size_t MutationDispatcher::Mutate_CopyPart(uint8_t *Data, size_t Size,                                             size_t MaxSize) {    if (Size > MaxSize || Size == 0) return 0; -  if (Rand.RandBool()) +  // If Size == MaxSize, `InsertPartOf(...)` will +  // fail so there's no point using it in this case. +  if (Size == MaxSize || Rand.RandBool())      return CopyPartOf(Data, Size, Data, Size);    else      return InsertPartOf(Data, Size, Data, Size, MaxSize); @@ -463,6 +466,7 @@ void MutationDispatcher::RecordSuccessfulMutationSequence() {      if (!PersistentAutoDictionary.ContainsWord(DE->GetW()))        PersistentAutoDictionary.push_back({DE->GetW(), 1});    } +  RecordUsefulMutations();  }  void MutationDispatcher::PrintRecommendedDictionary() { @@ -483,8 +487,7 @@ void MutationDispatcher::PrintRecommendedDictionary() {  void MutationDispatcher::PrintMutationSequence() {    Printf("MS: %zd ", CurrentMutatorSequence.size()); -  for (auto M : CurrentMutatorSequence) -    Printf("%s-", M.Name); +  for (auto M : CurrentMutatorSequence) Printf("%s-", M->Name);    if (!CurrentDictionaryEntrySequence.empty()) {      Printf(" DE: ");      for (auto DE : CurrentDictionaryEntrySequence) { @@ -512,12 +515,13 @@ size_t MutationDispatcher::MutateImpl(uint8_t *Data, size_t Size,    // in which case they will return 0.    // Try several times before returning un-mutated data.    for (int Iter = 0; Iter < 100; Iter++) { -    auto M = Mutators[Rand(Mutators.size())]; -    size_t NewSize = (this->*(M.Fn))(Data, Size, MaxSize); +    auto M = &Mutators[Rand(Mutators.size())]; +    size_t NewSize = (this->*(M->Fn))(Data, Size, MaxSize);      if (NewSize && NewSize <= MaxSize) {        if (Options.OnlyASCII)          ToASCII(Data, NewSize);        CurrentMutatorSequence.push_back(M); +      M->TotalCount++;        return NewSize;      }    } @@ -525,9 +529,54 @@ size_t MutationDispatcher::MutateImpl(uint8_t *Data, size_t Size,    return 1;   // Fallback, should not happen frequently.  } +// Mask represents the set of Data bytes that are worth mutating. +size_t MutationDispatcher::MutateWithMask(uint8_t *Data, size_t Size, +                                          size_t MaxSize, +                                          const Vector<uint8_t> &Mask) { +  assert(Size <= Mask.size()); +  // * Copy the worthy bytes into a temporary array T +  // * Mutate T +  // * Copy T back. +  // This is totally unoptimized. +  auto &T = MutateWithMaskTemp; +  if (T.size() < Size) +    T.resize(Size); +  size_t OneBits = 0; +  for (size_t I = 0; I < Size; I++) +    if (Mask[I]) +      T[OneBits++] = Data[I]; + +  assert(!T.empty()); +  size_t NewSize = Mutate(T.data(), OneBits, OneBits); +  assert(NewSize <= OneBits); +  (void)NewSize; +  // Even if NewSize < OneBits we still use all OneBits bytes. +  for (size_t I = 0, J = 0; I < Size; I++) +    if (Mask[I]) +      Data[I] = T[J++]; +  return Size; +} +  void MutationDispatcher::AddWordToManualDictionary(const Word &W) {    ManualDictionary.push_back(        {W, std::numeric_limits<size_t>::max()});  } +void MutationDispatcher::RecordUsefulMutations() { +  for (auto M : CurrentMutatorSequence) M->UsefulCount++; +} + +void MutationDispatcher::PrintMutationStats() { +  Printf("\nstat::mutation_usefulness:      "); +  for (size_t i = 0; i < Mutators.size(); i++) { +    double UsefulPercentage = +        Mutators[i].TotalCount +            ? (100.0 * Mutators[i].UsefulCount) / Mutators[i].TotalCount +            : 0; +    Printf("%.3f", UsefulPercentage); +    if (i < Mutators.size() - 1) Printf(","); +  } +  Printf("\n"); +} +  }  // namespace fuzzer diff --git a/lib/fuzzer/FuzzerMutate.h b/lib/fuzzer/FuzzerMutate.h index 4aa58af9902d5..828ecc13d8662 100644 --- a/lib/fuzzer/FuzzerMutate.h +++ b/lib/fuzzer/FuzzerMutate.h @@ -27,7 +27,7 @@ public:    void StartMutationSequence();    /// Print the current sequence of mutations.    void PrintMutationSequence(); -  /// Indicate that the current sequence of mutations was successfull. +  /// Indicate that the current sequence of mutations was successful.    void RecordSuccessfulMutationSequence();    /// Mutates data by invoking user-provided mutator.    size_t Mutate_Custom(uint8_t *Data, size_t Size, size_t MaxSize); @@ -70,6 +70,13 @@ public:    /// Applies one of the configured mutations.    /// Returns the new size of data which could be up to MaxSize.    size_t Mutate(uint8_t *Data, size_t Size, size_t MaxSize); + +  /// Applies one of the configured mutations to the bytes of Data +  /// that have '1' in Mask. +  /// Mask.size() should be >= Size. +  size_t MutateWithMask(uint8_t *Data, size_t Size, size_t MaxSize, +                        const Vector<uint8_t> &Mask); +    /// Applies one of the default mutations. Provided as a service    /// to mutation authors.    size_t DefaultMutate(uint8_t *Data, size_t Size, size_t MaxSize); @@ -86,11 +93,16 @@ public:    Random &GetRand() { return Rand; } -private: +  void PrintMutationStats(); + +  void RecordUsefulMutations(); + private:    struct Mutator {      size_t (MutationDispatcher::*Fn)(uint8_t *Data, size_t Size, size_t Max);      const char *Name; +    uint64_t UsefulCount; +    uint64_t TotalCount;    };    size_t AddWordFromDictionary(Dictionary &D, uint8_t *Data, size_t Size, @@ -125,11 +137,11 @@ private:    // recreated periodically.    Dictionary TempAutoDictionary;    // Persistent dictionary modified by the fuzzer, consists of -  // entries that led to successfull discoveries in the past mutations. +  // entries that led to successful discoveries in the past mutations.    Dictionary PersistentAutoDictionary; -  Vector<Mutator> CurrentMutatorSequence;    Vector<DictionaryEntry *> CurrentDictionaryEntrySequence; +  Vector<Mutator *> CurrentMutatorSequence;    static const size_t kCmpDictionaryEntriesDequeSize = 16;    DictionaryEntry CmpDictionaryEntriesDeque[kCmpDictionaryEntriesDequeSize]; @@ -137,6 +149,7 @@ private:    const InputCorpus *Corpus = nullptr;    Vector<uint8_t> MutateInPlaceHere; +  Vector<uint8_t> MutateWithMaskTemp;    // CustomCrossOver needs its own buffer as a custom implementation may call    // LLVMFuzzerMutate, which in turn may resize MutateInPlaceHere.    Vector<uint8_t> CustomCrossOverInPlaceHere; diff --git a/lib/fuzzer/FuzzerOptions.h b/lib/fuzzer/FuzzerOptions.h index 15a378020b855..ce39c0876cd72 100644 --- a/lib/fuzzer/FuzzerOptions.h +++ b/lib/fuzzer/FuzzerOptions.h @@ -18,7 +18,7 @@ namespace fuzzer {  struct FuzzingOptions {    int Verbosity = 1;    size_t MaxLen = 0; -  size_t ExperimentalLenControl = 0; +  size_t LenControl = 1000;    int UnitTimeoutSec = 300;    int TimeoutExitCode = 77;    int ErrorExitCode = 77; @@ -31,7 +31,7 @@ struct FuzzingOptions {    bool UseCounters = false;    bool UseMemmem = true;    bool UseCmp = false; -  bool UseValueProfile = false; +  int UseValueProfile = false;    bool Shrink = false;    bool ReduceInputs = false;    int ReloadIntervalSec = 1; @@ -45,18 +45,21 @@ struct FuzzingOptions {    std::string ExactArtifactPath;    std::string ExitOnSrcPos;    std::string ExitOnItem; +  std::string FocusFunction; +  std::string DataFlowTrace;    bool SaveArtifacts = true;    bool PrintNEW = true; // Print a status line when new units are found;    bool PrintNewCovPcs = false;    int PrintNewCovFuncs = 0;    bool PrintFinalStats = false; +  bool PrintMutationStats = false;    bool PrintCorpusStats = false;    bool PrintCoverage = false; +  bool PrintUnstableStats = false; +  int HandleUnstable = 0;    bool DumpCoverage = false; -  bool UseClangCoverage = false;    bool DetectLeaks = true;    int PurgeAllocatorIntervalSec = 1; -  int UseFeatureFrequency = false;    int  TraceMalloc = 0;    bool HandleAbrt = false;    bool HandleBus = false; diff --git a/lib/fuzzer/FuzzerShmemPosix.cpp b/lib/fuzzer/FuzzerShmemPosix.cpp index 50cdcfb509dc2..41a93f61004b7 100644 --- a/lib/fuzzer/FuzzerShmemPosix.cpp +++ b/lib/fuzzer/FuzzerShmemPosix.cpp @@ -32,6 +32,11 @@ std::string SharedMemoryRegion::Path(const char *Name) {  std::string SharedMemoryRegion::SemName(const char *Name, int Idx) {    std::string Res(Name); +  // When passing a name without a leading <slash> character to +  // sem_open, the behaviour is unspecified in POSIX. Add a leading +  // <slash> character for the name if there is no such one. +  if (!Res.empty() && Res[0] != '/') +    Res.insert(Res.begin(), '/');    return Res + (char)('0' + Idx);  } @@ -52,7 +57,7 @@ bool SharedMemoryRegion::Create(const char *Name) {    for (int i = 0; i < 2; i++) {      sem_unlink(SemName(Name, i).c_str());      Semaphore[i] = sem_open(SemName(Name, i).c_str(), O_CREAT, 0644, 0); -    if (Semaphore[i] == (void *)-1) +    if (Semaphore[i] == SEM_FAILED)        return false;    }    IAmServer = true; @@ -70,7 +75,7 @@ bool SharedMemoryRegion::Open(const char *Name) {      return false;    for (int i = 0; i < 2; i++) {      Semaphore[i] = sem_open(SemName(Name, i).c_str(), 0); -    if (Semaphore[i] == (void *)-1) +    if (Semaphore[i] == SEM_FAILED)        return false;    }    IAmServer = false; diff --git a/lib/fuzzer/FuzzerTracePC.cpp b/lib/fuzzer/FuzzerTracePC.cpp index 5e9f9f2f6dcce..29ffc8e34fc0f 100644 --- a/lib/fuzzer/FuzzerTracePC.cpp +++ b/lib/fuzzer/FuzzerTracePC.cpp @@ -39,8 +39,6 @@ namespace fuzzer {  TracePC TPC; -int ScopedDoingMyOwnMemOrStr::DoingMyOwnMemOrStr; -  uint8_t *TracePC::Counters() const {    return __sancov_trace_pc_guard_8bit_counters;  } @@ -59,6 +57,49 @@ size_t TracePC::GetTotalPCCoverage() {    return Res;  } +template<class CallBack> +void TracePC::IterateInline8bitCounters(CallBack CB) const { +  if (NumInline8bitCounters && NumInline8bitCounters == NumPCsInPCTables) { +    size_t CounterIdx = 0; +    for (size_t i = 0; i < NumModulesWithInline8bitCounters; i++) { +      uint8_t *Beg = ModuleCounters[i].Start; +      size_t Size = ModuleCounters[i].Stop - Beg; +      assert(Size == (size_t)(ModulePCTable[i].Stop - ModulePCTable[i].Start)); +      for (size_t j = 0; j < Size; j++, CounterIdx++) +        CB(i, j, CounterIdx); +    } +  } +} + +// Initializes unstable counters by copying Inline8bitCounters to unstable +// counters. +void TracePC::InitializeUnstableCounters() { +  IterateInline8bitCounters([&](int i, int j, int UnstableIdx) { +    UnstableCounters[UnstableIdx].Counter = ModuleCounters[i].Start[j]; +  }); +} + +// Compares the current counters with counters from previous runs +// and records differences as unstable edges. +void TracePC::UpdateUnstableCounters(int UnstableMode) { +  IterateInline8bitCounters([&](int i, int j, int UnstableIdx) { +    if (ModuleCounters[i].Start[j] != UnstableCounters[UnstableIdx].Counter) { +      UnstableCounters[UnstableIdx].IsUnstable = true; +      if (UnstableMode == ZeroUnstable) +        UnstableCounters[UnstableIdx].Counter = 0; +      else if (UnstableMode == MinUnstable) +        UnstableCounters[UnstableIdx].Counter = std::min( +            ModuleCounters[i].Start[j], UnstableCounters[UnstableIdx].Counter); +    } +  }); +} + +// Moves the minimum hit counts to ModuleCounters. +void TracePC::ApplyUnstableCounters() { +  IterateInline8bitCounters([&](int i, int j, int UnstableIdx) { +    ModuleCounters[i].Start[j] = UnstableCounters[UnstableIdx].Counter; +  }); +}  void TracePC::HandleInline8bitCountersInit(uint8_t *Start, uint8_t *Stop) {    if (Start == Stop) return; @@ -132,8 +173,8 @@ void TracePC::PrintModuleInfo() {        _Exit(1);      }    } -  if (size_t NumClangCounters = ClangCountersEnd() - ClangCountersBegin()) -    Printf("INFO: %zd Clang Coverage Counters\n", NumClangCounters); +  if (size_t NumExtraCounters = ExtraCountersEnd() - ExtraCountersBegin()) +    Printf("INFO: %zd Extra Counters\n", NumExtraCounters);  }  ATTRIBUTE_NO_SANITIZE_ALL @@ -147,28 +188,25 @@ void TracePC::HandleCallerCallee(uintptr_t Caller, uintptr_t Callee) {  void TracePC::UpdateObservedPCs() {    Vector<uintptr_t> CoveredFuncs;    auto ObservePC = [&](uintptr_t PC) { -    if (ObservedPCs.insert(PC).second && DoPrintNewPCs) -      PrintPC("\tNEW_PC: %p %F %L\n", "\tNEW_PC: %p\n", PC + 1); +    if (ObservedPCs.insert(PC).second && DoPrintNewPCs) { +      PrintPC("\tNEW_PC: %p %F %L", "\tNEW_PC: %p", PC + 1); +      Printf("\n"); +    }    };    auto Observe = [&](const PCTableEntry &TE) {      if (TE.PCFlags & 1) -      if (ObservedFuncs.insert(TE.PC).second && NumPrintNewFuncs) +      if (++ObservedFuncs[TE.PC] == 1 && NumPrintNewFuncs)          CoveredFuncs.push_back(TE.PC);      ObservePC(TE.PC);    };    if (NumPCsInPCTables) {      if (NumInline8bitCounters == NumPCsInPCTables) { -      for (size_t i = 0; i < NumModulesWithInline8bitCounters; i++) { -        uint8_t *Beg = ModuleCounters[i].Start; -        size_t Size = ModuleCounters[i].Stop - Beg; -        assert(Size == -               (size_t)(ModulePCTable[i].Stop - ModulePCTable[i].Start)); -        for (size_t j = 0; j < Size; j++) -          if (Beg[j]) -            Observe(ModulePCTable[i].Start[j]); -      } +      IterateInline8bitCounters([&](int i, int j, int CounterIdx) { +        if (ModuleCounters[i].Start[j]) +          Observe(ModulePCTable[i].Start[j]); +      });      } else if (NumGuards == NumPCsInPCTables) {        size_t GuardIdx = 1;        for (size_t i = 0; i < NumModules; i++) { @@ -182,17 +220,12 @@ void TracePC::UpdateObservedPCs() {        }      }    } -  if (size_t NumClangCounters = -      ClangCountersEnd() - ClangCountersBegin()) { -    auto P = ClangCountersBegin(); -    for (size_t Idx = 0; Idx < NumClangCounters; Idx++) -      if (P[Idx]) -        ObservePC((uintptr_t)Idx); -  } -  for (size_t i = 0, N = Min(CoveredFuncs.size(), NumPrintNewFuncs); i < N; i++) { -    Printf("\tNEW_FUNC[%zd/%zd]: ", i, CoveredFuncs.size()); -    PrintPC("%p %F %L\n", "%p\n", CoveredFuncs[i] + 1); +  for (size_t i = 0, N = Min(CoveredFuncs.size(), NumPrintNewFuncs); i < N; +       i++) { +    Printf("\tNEW_FUNC[%zd/%zd]: ", i + 1, CoveredFuncs.size()); +    PrintPC("%p %F %L", "%p", CoveredFuncs[i] + 1); +    Printf("\n");    }  } @@ -218,6 +251,57 @@ static std::string GetModuleName(uintptr_t PC) {    return ModulePathRaw;  } +template<class CallBack> +void TracePC::IterateCoveredFunctions(CallBack CB) { +  for (size_t i = 0; i < NumPCTables; i++) { +    auto &M = ModulePCTable[i]; +    assert(M.Start < M.Stop); +    auto ModuleName = GetModuleName(M.Start->PC); +    for (auto NextFE = M.Start; NextFE < M.Stop; ) { +      auto FE = NextFE; +      assert((FE->PCFlags & 1) && "Not a function entry point"); +      do { +        NextFE++; +      } while (NextFE < M.Stop && !(NextFE->PCFlags & 1)); +      if (ObservedFuncs.count(FE->PC)) +        CB(FE, NextFE, ObservedFuncs[FE->PC]); +    } +  } +} + +void TracePC::SetFocusFunction(const std::string &FuncName) { +  // This function should be called once. +  assert(FocusFunction.first > NumModulesWithInline8bitCounters); +  if (FuncName.empty()) +    return; +  for (size_t M = 0; M < NumModulesWithInline8bitCounters; M++) { +    auto &PCTE = ModulePCTable[M]; +    size_t N = PCTE.Stop - PCTE.Start; +    for (size_t I = 0; I < N; I++) { +      if (!(PCTE.Start[I].PCFlags & 1)) continue;  // not a function entry. +      auto Name = DescribePC("%F", GetNextInstructionPc(PCTE.Start[I].PC)); +      if (Name[0] == 'i' && Name[1] == 'n' && Name[2] == ' ') +        Name = Name.substr(3, std::string::npos); +      if (FuncName != Name) continue; +      Printf("INFO: Focus function is set to '%s'\n", Name.c_str()); +      FocusFunction = {M, I}; +      return; +    } +  } +} + +bool TracePC::ObservedFocusFunction() { +  size_t I = FocusFunction.first; +  size_t J = FocusFunction.second; +  if (I >= NumModulesWithInline8bitCounters) +    return false; +  auto &MC = ModuleCounters[I]; +  size_t Size = MC.Stop - MC.Start; +  if (J >= Size) +    return false; +  return MC.Start[J] != 0; +} +  void TracePC::PrintCoverage() {    if (!EF->__sanitizer_symbolize_pc ||        !EF->__sanitizer_get_module_and_offset_for_pc) { @@ -227,53 +311,33 @@ void TracePC::PrintCoverage() {      return;    }    Printf("COVERAGE:\n"); -  std::string LastFunctionName = ""; -  std::string LastFileStr = ""; -  Set<size_t> UncoveredLines; -  Set<size_t> CoveredLines; - -  auto FunctionEndCallback = [&](const std::string &CurrentFunc, -                                 const std::string &CurrentFile) { -    if (LastFunctionName != CurrentFunc) { -      if (CoveredLines.empty() && !UncoveredLines.empty()) { -        Printf("UNCOVERED_FUNC: %s\n", LastFunctionName.c_str()); -      } else { -        for (auto Line : UncoveredLines) { -          if (!CoveredLines.count(Line)) -            Printf("UNCOVERED_LINE: %s %s:%zd\n", LastFunctionName.c_str(), -                   LastFileStr.c_str(), Line); -        } -      } - -      UncoveredLines.clear(); -      CoveredLines.clear(); -      LastFunctionName = CurrentFunc; -      LastFileStr = CurrentFile; -    } +  auto CoveredFunctionCallback = [&](const PCTableEntry *First, +                                     const PCTableEntry *Last, +                                     uintptr_t Counter) { +    assert(First < Last); +    auto VisualizePC = GetNextInstructionPc(First->PC); +    std::string FileStr = DescribePC("%s", VisualizePC); +    if (!IsInterestingCoverageFile(FileStr)) +      return; +    std::string FunctionStr = DescribePC("%F", VisualizePC); +    if (FunctionStr.find("in ") == 0) +      FunctionStr = FunctionStr.substr(3); +    std::string LineStr = DescribePC("%l", VisualizePC); +    size_t Line = std::stoul(LineStr); +    size_t NumEdges = Last - First; +    Vector<uintptr_t> UncoveredPCs; +    for (auto TE = First; TE < Last; TE++) +      if (!ObservedPCs.count(TE->PC)) +        UncoveredPCs.push_back(TE->PC); +    Printf("COVERED_FUNC: hits: %zd", Counter); +    Printf(" edges: %zd/%zd", NumEdges - UncoveredPCs.size(), NumEdges); +    Printf(" %s %s:%zd\n", FunctionStr.c_str(), FileStr.c_str(), Line); +    for (auto PC: UncoveredPCs) +      Printf("  UNCOVERED_PC: %s\n", +             DescribePC("%s:%l", GetNextInstructionPc(PC)).c_str());    }; -  for (size_t i = 0; i < NumPCTables; i++) { -    auto &M = ModulePCTable[i]; -    assert(M.Start < M.Stop); -    auto ModuleName = GetModuleName(M.Start->PC); -    for (auto Ptr = M.Start; Ptr < M.Stop; Ptr++) { -      auto PC = Ptr->PC; -      auto VisualizePC = GetNextInstructionPc(PC); -      bool IsObserved = ObservedPCs.count(PC); -      std::string FileStr = DescribePC("%s", VisualizePC); -      if (!IsInterestingCoverageFile(FileStr)) continue; -      std::string FunctionStr = DescribePC("%F", VisualizePC); -      FunctionEndCallback(FunctionStr, FileStr); -      std::string LineStr = DescribePC("%l", VisualizePC); -      size_t Line = std::stoul(LineStr); -      if (IsObserved && CoveredLines.insert(Line).second) -        Printf("COVERED: %s %s:%zd\n", FunctionStr.c_str(), FileStr.c_str(), -               Line); -      else -        UncoveredLines.insert(Line); -    } -  } -  FunctionEndCallback("", ""); +  IterateCoveredFunctions(CoveredFunctionCallback);  }  void TracePC::DumpCoverage() { @@ -285,6 +349,15 @@ void TracePC::DumpCoverage() {    }  } +void TracePC::PrintUnstableStats() { +  size_t count = 0; +  for (size_t i = 0; i < NumInline8bitCounters; i++) +    if (UnstableCounters[i].IsUnstable) +      count++; +  Printf("stat::stability_rate: %.2f\n", +         100 - static_cast<float>(count * 100) / NumInline8bitCounters); +} +  // Value profile.  // We keep track of various values that affect control flow.  // These values are inserted into a bit-set-based hash map. @@ -334,7 +407,14 @@ void TracePC::HandleCmp(uintptr_t PC, T Arg1, T Arg2) {        TORC4.Insert(ArgXor, Arg1, Arg2);    else if (sizeof(T) == 8)        TORC8.Insert(ArgXor, Arg1, Arg2); -  ValueProfileMap.AddValue(Idx); +  // TODO: remove these flags and instead use all metrics at once. +  if (UseValueProfileMask & 1) +    ValueProfileMap.AddValue(Idx); +  if (UseValueProfileMask & 2) +    ValueProfileMap.AddValue( +        PC * 64 + (Arg1 == Arg2 ? 0 : __builtin_clzll(Arg1 - Arg2) + 1)); +  if (UseValueProfileMask & 4)  // alternative way to use the hamming distance +    ValueProfileMap.AddValue(PC * 64 + ArgDistance);  }  static size_t InternalStrnlen(const char *S, size_t MaxLen) { @@ -536,7 +616,7 @@ void __sanitizer_cov_trace_gep(uintptr_t Idx) {  ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY  void __sanitizer_weak_hook_memcmp(void *caller_pc, const void *s1,                                    const void *s2, size_t n, int result) { -  if (fuzzer::ScopedDoingMyOwnMemOrStr::DoingMyOwnMemOrStr) return; +  if (!fuzzer::RunningUserCallback) return;    if (result == 0) return;  // No reason to mutate.    if (n <= 1) return;  // Not interesting.    fuzzer::TPC.AddValueForMemcmp(caller_pc, s1, s2, n, /*StopAtZero*/false); @@ -545,7 +625,7 @@ void __sanitizer_weak_hook_memcmp(void *caller_pc, const void *s1,  ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY  void __sanitizer_weak_hook_strncmp(void *caller_pc, const char *s1,                                     const char *s2, size_t n, int result) { -  if (fuzzer::ScopedDoingMyOwnMemOrStr::DoingMyOwnMemOrStr) return; +  if (!fuzzer::RunningUserCallback) return;    if (result == 0) return;  // No reason to mutate.    size_t Len1 = fuzzer::InternalStrnlen(s1, n);    size_t Len2 = fuzzer::InternalStrnlen(s2, n); @@ -558,7 +638,7 @@ void __sanitizer_weak_hook_strncmp(void *caller_pc, const char *s1,  ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY  void __sanitizer_weak_hook_strcmp(void *caller_pc, const char *s1,                                     const char *s2, int result) { -  if (fuzzer::ScopedDoingMyOwnMemOrStr::DoingMyOwnMemOrStr) return; +  if (!fuzzer::RunningUserCallback) return;    if (result == 0) return;  // No reason to mutate.    size_t N = fuzzer::InternalStrnlen2(s1, s2);    if (N <= 1) return;  // Not interesting. @@ -568,35 +648,35 @@ void __sanitizer_weak_hook_strcmp(void *caller_pc, const char *s1,  ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY  void __sanitizer_weak_hook_strncasecmp(void *called_pc, const char *s1,                                         const char *s2, size_t n, int result) { -  if (fuzzer::ScopedDoingMyOwnMemOrStr::DoingMyOwnMemOrStr) return; +  if (!fuzzer::RunningUserCallback) return;    return __sanitizer_weak_hook_strncmp(called_pc, s1, s2, n, result);  }  ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY  void __sanitizer_weak_hook_strcasecmp(void *called_pc, const char *s1,                                        const char *s2, int result) { -  if (fuzzer::ScopedDoingMyOwnMemOrStr::DoingMyOwnMemOrStr) return; +  if (!fuzzer::RunningUserCallback) return;    return __sanitizer_weak_hook_strcmp(called_pc, s1, s2, result);  }  ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY  void __sanitizer_weak_hook_strstr(void *called_pc, const char *s1,                                    const char *s2, char *result) { -  if (fuzzer::ScopedDoingMyOwnMemOrStr::DoingMyOwnMemOrStr) return; +  if (!fuzzer::RunningUserCallback) return;    fuzzer::TPC.MMT.Add(reinterpret_cast<const uint8_t *>(s2), strlen(s2));  }  ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY  void __sanitizer_weak_hook_strcasestr(void *called_pc, const char *s1,                                        const char *s2, char *result) { -  if (fuzzer::ScopedDoingMyOwnMemOrStr::DoingMyOwnMemOrStr) return; +  if (!fuzzer::RunningUserCallback) return;    fuzzer::TPC.MMT.Add(reinterpret_cast<const uint8_t *>(s2), strlen(s2));  }  ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY  void __sanitizer_weak_hook_memmem(void *called_pc, const void *s1, size_t len1,                                    const void *s2, size_t len2, void *result) { -  if (fuzzer::ScopedDoingMyOwnMemOrStr::DoingMyOwnMemOrStr) return; +  if (!fuzzer::RunningUserCallback) return;    fuzzer::TPC.MMT.Add(reinterpret_cast<const uint8_t *>(s2), len2);  }  }  // extern "C" diff --git a/lib/fuzzer/FuzzerTracePC.h b/lib/fuzzer/FuzzerTracePC.h index c3f241b905b1d..097ba69bdc088 100644 --- a/lib/fuzzer/FuzzerTracePC.h +++ b/lib/fuzzer/FuzzerTracePC.h @@ -17,6 +17,7 @@  #include "FuzzerValueBitMap.h"  #include <set> +#include <unordered_map>  namespace fuzzer { @@ -73,6 +74,11 @@ class TracePC {    // How many bits of PC are used from __sanitizer_cov_trace_pc.    static const size_t kTracePcBits = 18; +  enum HandleUnstableOptions { +    MinUnstable = 1, +    ZeroUnstable = 2, +  }; +    void HandleInit(uint32_t *Start, uint32_t *Stop);    void HandleInline8bitCountersInit(uint8_t *Start, uint8_t *Stop);    void HandlePCsInit(const uintptr_t *Start, const uintptr_t *Stop); @@ -80,8 +86,7 @@ class TracePC {    template <class T> void HandleCmp(uintptr_t PC, T Arg1, T Arg2);    size_t GetTotalPCCoverage();    void SetUseCounters(bool UC) { UseCounters = UC; } -  void SetUseClangCoverage(bool UCC) { UseClangCoverage = UCC; } -  void SetUseValueProfile(bool VP) { UseValueProfile = VP; } +  void SetUseValueProfileMask(uint32_t VPMask) { UseValueProfileMask = VPMask; }    void SetPrintNewPCs(bool P) { DoPrintNewPCs = P; }    void SetPrintNewFuncs(size_t P) { NumPrintNewFuncs = P; }    void UpdateObservedPCs(); @@ -93,8 +98,6 @@ class TracePC {        memset(Counters(), 0, GetNumPCs());      ClearExtraCounters();      ClearInlineCounters(); -    if (UseClangCoverage) -      ClearClangCounters();    }    void ClearInlineCounters(); @@ -106,6 +109,10 @@ class TracePC {    void PrintCoverage();    void DumpCoverage(); +  void PrintUnstableStats(); + +  template<class CallBack> +  void IterateCoveredFunctions(CallBack CB);    void AddValueForMemcmp(void *caller_pc, const void *s1, const void *s2,                           size_t n, bool StopAtZero); @@ -132,10 +139,23 @@ class TracePC {        CB(PC);    } +  void SetFocusFunction(const std::string &FuncName); +  bool ObservedFocusFunction(); + +  void InitializeUnstableCounters(); +  void UpdateUnstableCounters(int UnstableMode); +  void ApplyUnstableCounters(); +  private: +  struct UnstableEdge { +    uint8_t Counter; +    bool IsUnstable; +  }; + +  UnstableEdge UnstableCounters[kNumPCs]; +    bool UseCounters = false; -  bool UseValueProfile = false; -  bool UseClangCoverage = false; +  uint32_t UseValueProfileMask = false;    bool DoPrintNewPCs = false;    size_t NumPrintNewFuncs = 0; @@ -163,7 +183,12 @@ private:    uintptr_t *PCs() const;    Set<uintptr_t> ObservedPCs; -  Set<uintptr_t> ObservedFuncs; +  std::unordered_map<uintptr_t, uintptr_t> ObservedFuncs;  // PC => Counter. + +  template <class Callback> +  void IterateInline8bitCounters(Callback CB) const; + +  std::pair<size_t, size_t> FocusFunction = {-1, -1};  // Module and PC IDs.    ValueBitMap ValueProfileMap;    uintptr_t InitialStack; @@ -251,23 +276,11 @@ void TracePC::CollectFeatures(Callback HandleFeature) const {      }    } -  if (size_t NumClangCounters = ClangCountersEnd() - ClangCountersBegin()) { -    auto P = ClangCountersBegin(); -    for (size_t Idx = 0; Idx < NumClangCounters; Idx++) -      if (auto Cnt = P[Idx]) { -        if (UseCounters) -          HandleFeature(FirstFeature + Idx * 8 + CounterToFeature(Cnt)); -        else -          HandleFeature(FirstFeature + Idx); -      } -    FirstFeature += NumClangCounters; -  } -    ForEachNonZeroByte(ExtraCountersBegin(), ExtraCountersEnd(), FirstFeature,                       Handle8bitCounter);    FirstFeature += (ExtraCountersEnd() - ExtraCountersBegin()) * 8; -  if (UseValueProfile) { +  if (UseValueProfileMask) {      ValueProfileMap.ForEach([&](size_t Idx) {        HandleFeature(FirstFeature + Idx);      }); diff --git a/lib/fuzzer/FuzzerUtil.cpp b/lib/fuzzer/FuzzerUtil.cpp index 96b37d34815de..6286f9a718adb 100644 --- a/lib/fuzzer/FuzzerUtil.cpp +++ b/lib/fuzzer/FuzzerUtil.cpp @@ -16,6 +16,7 @@  #include <chrono>  #include <cstring>  #include <errno.h> +#include <mutex>  #include <signal.h>  #include <sstream>  #include <stdio.h> @@ -179,8 +180,12 @@ std::string Base64(const Unit &U) {    return Res;  } +static std::mutex SymbolizeMutex; +  std::string DescribePC(const char *SymbolizedFMT, uintptr_t PC) { -  if (!EF->__sanitizer_symbolize_pc) return "<can not symbolize>"; +  std::unique_lock<std::mutex> l(SymbolizeMutex, std::try_to_lock); +  if (!EF->__sanitizer_symbolize_pc || !l.owns_lock()) +    return "<can not symbolize>";    char PcDescr[1024] = {};    EF->__sanitizer_symbolize_pc(reinterpret_cast<void*>(PC),                                 SymbolizedFMT, PcDescr, sizeof(PcDescr)); @@ -195,6 +200,18 @@ void PrintPC(const char *SymbolizedFMT, const char *FallbackFMT, uintptr_t PC) {      Printf(FallbackFMT, PC);  } +void PrintStackTrace() { +  std::unique_lock<std::mutex> l(SymbolizeMutex, std::try_to_lock); +  if (EF->__sanitizer_print_stack_trace && l.owns_lock()) +    EF->__sanitizer_print_stack_trace(); +} + +void PrintMemoryProfile() { +  std::unique_lock<std::mutex> l(SymbolizeMutex, std::try_to_lock); +  if (EF->__sanitizer_print_memory_profile && l.owns_lock()) +    EF->__sanitizer_print_memory_profile(95, 8); +} +  unsigned NumberOfCpuCores() {    unsigned N = std::thread::hardware_concurrency();    if (!N) { diff --git a/lib/fuzzer/FuzzerUtil.h b/lib/fuzzer/FuzzerUtil.h index f2ed028ce78ed..8c5c57c3ab83b 100644 --- a/lib/fuzzer/FuzzerUtil.h +++ b/lib/fuzzer/FuzzerUtil.h @@ -40,6 +40,10 @@ void PrintPC(const char *SymbolizedFMT, const char *FallbackFMT, uintptr_t PC);  std::string DescribePC(const char *SymbolizedFMT, uintptr_t PC); +void PrintStackTrace(); + +void PrintMemoryProfile(); +  unsigned NumberOfCpuCores();  // Platform specific functions. diff --git a/lib/fuzzer/FuzzerUtilFuchsia.cpp b/lib/fuzzer/FuzzerUtilFuchsia.cpp index a5fdc37fb5a6e..cd2bb7438e9d0 100644 --- a/lib/fuzzer/FuzzerUtilFuchsia.cpp +++ b/lib/fuzzer/FuzzerUtilFuchsia.cpp @@ -17,29 +17,54 @@  #include <cerrno>  #include <cinttypes>  #include <cstdint> -#include <fbl/unique_fd.h>  #include <fcntl.h> -#include <launchpad/launchpad.h> +#include <lib/fdio/spawn.h>  #include <string> +#include <sys/select.h>  #include <thread> +#include <unistd.h>  #include <zircon/errors.h> +#include <zircon/process.h> +#include <zircon/sanitizer.h>  #include <zircon/status.h>  #include <zircon/syscalls.h> +#include <zircon/syscalls/debug.h> +#include <zircon/syscalls/exception.h>  #include <zircon/syscalls/port.h>  #include <zircon/types.h> -#include <zx/object.h> -#include <zx/port.h> -#include <zx/process.h> -#include <zx/time.h>  namespace fuzzer { +// Given that Fuchsia doesn't have the POSIX signals that libFuzzer was written +// around, the general approach is to spin up dedicated threads to watch for +// each requested condition (alarm, interrupt, crash).  Of these, the crash +// handler is the most involved, as it requires resuming the crashed thread in +// order to invoke the sanitizers to get the needed state. + +// Forward declaration of assembly trampoline needed to resume crashed threads. +// This appears to have external linkage to  C++, which is why it's not in the +// anonymous namespace.  The assembly definition inside MakeTrampoline() +// actually defines the symbol with internal linkage only. +void CrashTrampolineAsm() __asm__("CrashTrampolineAsm"); +  namespace { +// TODO(phosek): remove this and replace it with ZX_TIME_INFINITE +#define ZX_TIME_INFINITE_OLD INT64_MAX +  // A magic value for the Zircon exception port, chosen to spell 'FUZZING'  // when interpreted as a byte sequence on little-endian platforms.  const uint64_t kFuzzingCrash = 0x474e495a5a5546; +// Helper function to handle Zircon syscall failures. +void ExitOnErr(zx_status_t Status, const char *Syscall) { +  if (Status != ZX_OK) { +    Printf("libFuzzer: %s failed: %s\n", Syscall, +           _zx_status_get_string(Status)); +    exit(1); +  } +} +  void AlarmHandler(int Seconds) {    while (true) {      SleepSeconds(Seconds); @@ -48,37 +73,226 @@ void AlarmHandler(int Seconds) {  }  void InterruptHandler() { +  fd_set readfds;    // Ctrl-C sends ETX in Zircon. -  while (getchar() != 0x03); +  do { +    FD_ZERO(&readfds); +    FD_SET(STDIN_FILENO, &readfds); +    select(STDIN_FILENO + 1, &readfds, nullptr, nullptr, nullptr); +  } while(!FD_ISSET(STDIN_FILENO, &readfds) || getchar() != 0x03);    Fuzzer::StaticInterruptCallback();  } -void CrashHandler(zx::port *Port) { -  std::unique_ptr<zx::port> ExceptionPort(Port); -  zx_port_packet_t Packet; -  ExceptionPort->wait(ZX_TIME_INFINITE, &Packet, 0); -  // Unbind as soon as possible so we don't receive exceptions from this thread. -  if (zx_task_bind_exception_port(ZX_HANDLE_INVALID, ZX_HANDLE_INVALID, -                                  kFuzzingCrash, 0) != ZX_OK) { -    // Shouldn't happen; if it does the safest option is to just exit. -    Printf("libFuzzer: unable to unbind exception port; aborting!\n"); -    exit(1); -  } -  if (Packet.key != kFuzzingCrash) { -    Printf("libFuzzer: invalid crash key: %" PRIx64 "; aborting!\n", -           Packet.key); -    exit(1); -  } -  // CrashCallback should not return from this call +// For the crash handler, we need to call Fuzzer::StaticCrashSignalCallback +// without POSIX signal handlers.  To achieve this, we use an assembly function +// to add the necessary CFI unwinding information and a C function to bridge +// from that back into C++. + +// FIXME: This works as a short-term solution, but this code really shouldn't be +// architecture dependent. A better long term solution is to implement remote +// unwinding and expose the necessary APIs through sanitizer_common and/or ASAN +// to allow the exception handling thread to gather the crash state directly. +// +// Alternatively, Fuchsia may in future actually implement basic signal +// handling for the machine trap signals. +#if defined(__x86_64__) +#define FOREACH_REGISTER(OP_REG, OP_NUM) \ +  OP_REG(rax)                            \ +  OP_REG(rbx)                            \ +  OP_REG(rcx)                            \ +  OP_REG(rdx)                            \ +  OP_REG(rsi)                            \ +  OP_REG(rdi)                            \ +  OP_REG(rbp)                            \ +  OP_REG(rsp)                            \ +  OP_REG(r8)                             \ +  OP_REG(r9)                             \ +  OP_REG(r10)                            \ +  OP_REG(r11)                            \ +  OP_REG(r12)                            \ +  OP_REG(r13)                            \ +  OP_REG(r14)                            \ +  OP_REG(r15)                            \ +  OP_REG(rip) + +#elif defined(__aarch64__) +#define FOREACH_REGISTER(OP_REG, OP_NUM) \ +  OP_NUM(0)                              \ +  OP_NUM(1)                              \ +  OP_NUM(2)                              \ +  OP_NUM(3)                              \ +  OP_NUM(4)                              \ +  OP_NUM(5)                              \ +  OP_NUM(6)                              \ +  OP_NUM(7)                              \ +  OP_NUM(8)                              \ +  OP_NUM(9)                              \ +  OP_NUM(10)                             \ +  OP_NUM(11)                             \ +  OP_NUM(12)                             \ +  OP_NUM(13)                             \ +  OP_NUM(14)                             \ +  OP_NUM(15)                             \ +  OP_NUM(16)                             \ +  OP_NUM(17)                             \ +  OP_NUM(18)                             \ +  OP_NUM(19)                             \ +  OP_NUM(20)                             \ +  OP_NUM(21)                             \ +  OP_NUM(22)                             \ +  OP_NUM(23)                             \ +  OP_NUM(24)                             \ +  OP_NUM(25)                             \ +  OP_NUM(26)                             \ +  OP_NUM(27)                             \ +  OP_NUM(28)                             \ +  OP_NUM(29)                             \ +  OP_NUM(30)                             \ +  OP_REG(sp) + +#else +#error "Unsupported architecture for fuzzing on Fuchsia" +#endif + +// Produces a CFI directive for the named or numbered register. +#define CFI_OFFSET_REG(reg) ".cfi_offset " #reg ", %c[" #reg "]\n" +#define CFI_OFFSET_NUM(num) CFI_OFFSET_REG(r##num) + +// Produces an assembler input operand for the named or numbered register. +#define ASM_OPERAND_REG(reg) \ +  [reg] "i"(offsetof(zx_thread_state_general_regs_t, reg)), +#define ASM_OPERAND_NUM(num)                                 \ +  [r##num] "i"(offsetof(zx_thread_state_general_regs_t, r[num])), + +// Trampoline to bridge from the assembly below to the static C++ crash +// callback. +__attribute__((noreturn)) +static void StaticCrashHandler() {    Fuzzer::StaticCrashSignalCallback(); +  for (;;) { +    _Exit(1); +  } +} + +// Creates the trampoline with the necessary CFI information to unwind through +// to the crashing call stack.  The attribute is necessary because the function +// is never called; it's just a container around the assembly to allow it to +// use operands for compile-time computed constants. +__attribute__((used)) +void MakeTrampoline() { +  __asm__(".cfi_endproc\n" +    ".pushsection .text.CrashTrampolineAsm\n" +    ".type CrashTrampolineAsm,STT_FUNC\n" +"CrashTrampolineAsm:\n" +    ".cfi_startproc simple\n" +    ".cfi_signal_frame\n" +#if defined(__x86_64__) +    ".cfi_return_column rip\n" +    ".cfi_def_cfa rsp, 0\n" +    FOREACH_REGISTER(CFI_OFFSET_REG, CFI_OFFSET_NUM) +    "call %c[StaticCrashHandler]\n" +    "ud2\n" +#elif defined(__aarch64__) +    ".cfi_return_column 33\n" +    ".cfi_def_cfa sp, 0\n" +    ".cfi_offset 33, %c[pc]\n" +    FOREACH_REGISTER(CFI_OFFSET_REG, CFI_OFFSET_NUM) +    "bl %[StaticCrashHandler]\n" +#else +#error "Unsupported architecture for fuzzing on Fuchsia" +#endif +    ".cfi_endproc\n" +    ".size CrashTrampolineAsm, . - CrashTrampolineAsm\n" +    ".popsection\n" +    ".cfi_startproc\n" +    : // No outputs +    : FOREACH_REGISTER(ASM_OPERAND_REG, ASM_OPERAND_NUM) +#if defined(__aarch64__) +      ASM_OPERAND_REG(pc) +#endif +      [StaticCrashHandler] "i" (StaticCrashHandler)); +} + +void CrashHandler(zx_handle_t *Event) { +  // This structure is used to ensure we close handles to objects we create in +  // this handler. +  struct ScopedHandle { +    ~ScopedHandle() { _zx_handle_close(Handle); } +    zx_handle_t Handle = ZX_HANDLE_INVALID; +  }; + +  // Create and bind the exception port.  We need to claim to be a "debugger" so +  // the kernel will allow us to modify and resume dying threads (see below). +  // Once the port is set, we can signal the main thread to continue and wait +  // for the exception to arrive. +  ScopedHandle Port; +  ExitOnErr(_zx_port_create(0, &Port.Handle), "_zx_port_create"); +  zx_handle_t Self = _zx_process_self(); + +  ExitOnErr(_zx_task_bind_exception_port(Self, Port.Handle, kFuzzingCrash, +                                         ZX_EXCEPTION_PORT_DEBUGGER), +            "_zx_task_bind_exception_port"); + +  ExitOnErr(_zx_object_signal(*Event, 0, ZX_USER_SIGNAL_0), +            "_zx_object_signal"); + +  zx_port_packet_t Packet; +  ExitOnErr(_zx_port_wait(Port.Handle, ZX_TIME_INFINITE_OLD, &Packet), +            "_zx_port_wait"); + +  // At this point, we want to get the state of the crashing thread, but +  // libFuzzer and the sanitizers assume this will happen from that same thread +  // via a POSIX signal handler. "Resurrecting" the thread in the middle of the +  // appropriate callback is as simple as forcibly setting the instruction +  // pointer/program counter, provided we NEVER EVER return from that function +  // (since otherwise our stack will not be valid). +  ScopedHandle Thread; +  ExitOnErr(_zx_object_get_child(Self, Packet.exception.tid, +                                 ZX_RIGHT_SAME_RIGHTS, &Thread.Handle), +            "_zx_object_get_child"); + +  zx_thread_state_general_regs_t GeneralRegisters; +  ExitOnErr(_zx_thread_read_state(Thread.Handle, ZX_THREAD_STATE_GENERAL_REGS, +                                  &GeneralRegisters, sizeof(GeneralRegisters)), +            "_zx_thread_read_state"); + +  // To unwind properly, we need to push the crashing thread's register state +  // onto the stack and jump into a trampoline with CFI instructions on how +  // to restore it. +#if defined(__x86_64__) +  uintptr_t StackPtr = +      (GeneralRegisters.rsp - (128 + sizeof(GeneralRegisters))) & +      -(uintptr_t)16; +  __unsanitized_memcpy(reinterpret_cast<void *>(StackPtr), &GeneralRegisters, +         sizeof(GeneralRegisters)); +  GeneralRegisters.rsp = StackPtr; +  GeneralRegisters.rip = reinterpret_cast<zx_vaddr_t>(CrashTrampolineAsm); + +#elif defined(__aarch64__) +  uintptr_t StackPtr = +      (GeneralRegisters.sp - sizeof(GeneralRegisters)) & -(uintptr_t)16; +  __unsanitized_memcpy(reinterpret_cast<void *>(StackPtr), &GeneralRegisters, +                       sizeof(GeneralRegisters)); +  GeneralRegisters.sp = StackPtr; +  GeneralRegisters.pc = reinterpret_cast<zx_vaddr_t>(CrashTrampolineAsm); + +#else +#error "Unsupported architecture for fuzzing on Fuchsia" +#endif + +  // Now force the crashing thread's state. +  ExitOnErr(_zx_thread_write_state(Thread.Handle, ZX_THREAD_STATE_GENERAL_REGS, +                                   &GeneralRegisters, sizeof(GeneralRegisters)), +            "_zx_thread_write_state"); + +  ExitOnErr(_zx_task_resume_from_exception(Thread.Handle, Port.Handle, 0), +            "_zx_task_resume_from_exception");  }  } // namespace  // Platform specific functions.  void SetSignalHandler(const FuzzingOptions &Options) { -  zx_status_t rc; -    // Set up alarm handler if needed.    if (Options.UnitTimeoutSec > 0) {      std::thread T(AlarmHandler, Options.UnitTimeoutSec / 2 + 1); @@ -96,37 +310,30 @@ void SetSignalHandler(const FuzzingOptions &Options) {        !Options.HandleFpe && !Options.HandleAbrt)      return; -  // Create an exception port -  zx::port *ExceptionPort = new zx::port(); -  if ((rc = zx::port::create(0, ExceptionPort)) != ZX_OK) { -    Printf("libFuzzer: zx_port_create failed: %s\n", zx_status_get_string(rc)); -    exit(1); -  } +  // Set up the crash handler and wait until it is ready before proceeding. +  zx_handle_t Event; +  ExitOnErr(_zx_event_create(0, &Event), "_zx_event_create"); -  // Bind the port to receive exceptions from our process -  if ((rc = zx_task_bind_exception_port(zx_process_self(), ExceptionPort->get(), -                                        kFuzzingCrash, 0)) != ZX_OK) { -    Printf("libFuzzer: unable to bind exception port: %s\n", -           zx_status_get_string(rc)); -    exit(1); -  } +  std::thread T(CrashHandler, &Event); +  zx_status_t Status = _zx_object_wait_one(Event, ZX_USER_SIGNAL_0, +                                           ZX_TIME_INFINITE_OLD, nullptr); +  _zx_handle_close(Event); +  ExitOnErr(Status, "_zx_object_wait_one"); -  // Set up the crash handler. -  std::thread T(CrashHandler, ExceptionPort);    T.detach();  }  void SleepSeconds(int Seconds) { -  zx::nanosleep(zx::deadline_after(ZX_SEC(Seconds))); +  _zx_nanosleep(_zx_deadline_after(ZX_SEC(Seconds)));  }  unsigned long GetPid() {    zx_status_t rc;    zx_info_handle_basic_t Info; -  if ((rc = zx_object_get_info(zx_process_self(), ZX_INFO_HANDLE_BASIC, &Info, -                               sizeof(Info), NULL, NULL)) != ZX_OK) { +  if ((rc = _zx_object_get_info(_zx_process_self(), ZX_INFO_HANDLE_BASIC, &Info, +                                sizeof(Info), NULL, NULL)) != ZX_OK) {      Printf("libFuzzer: unable to get info about self: %s\n", -           zx_status_get_string(rc)); +           _zx_status_get_string(rc));      exit(1);    }    return Info.koid; @@ -135,15 +342,30 @@ unsigned long GetPid() {  size_t GetPeakRSSMb() {    zx_status_t rc;    zx_info_task_stats_t Info; -  if ((rc = zx_object_get_info(zx_process_self(), ZX_INFO_TASK_STATS, &Info, -                               sizeof(Info), NULL, NULL)) != ZX_OK) { +  if ((rc = _zx_object_get_info(_zx_process_self(), ZX_INFO_TASK_STATS, &Info, +                                sizeof(Info), NULL, NULL)) != ZX_OK) {      Printf("libFuzzer: unable to get info about self: %s\n", -           zx_status_get_string(rc)); +           _zx_status_get_string(rc));      exit(1);    }    return (Info.mem_private_bytes + Info.mem_shared_bytes) >> 20;  } +template <typename Fn> +class RunOnDestruction { + public: +  explicit RunOnDestruction(Fn fn) : fn_(fn) {} +  ~RunOnDestruction() { fn_(); } + + private: +  Fn fn_; +}; + +template <typename Fn> +RunOnDestruction<Fn> at_scope_exit(Fn fn) { +  return RunOnDestruction<Fn>(fn); +} +  int ExecuteCommand(const Command &Cmd) {    zx_status_t rc; @@ -151,30 +373,24 @@ int ExecuteCommand(const Command &Cmd) {    auto Args = Cmd.getArguments();    size_t Argc = Args.size();    assert(Argc != 0); -  std::unique_ptr<const char *[]> Argv(new const char *[Argc]); +  std::unique_ptr<const char *[]> Argv(new const char *[Argc + 1]);    for (size_t i = 0; i < Argc; ++i)      Argv[i] = Args[i].c_str(); - -  // Create the basic launchpad.  Clone everything except stdio. -  launchpad_t *lp; -  launchpad_create(ZX_HANDLE_INVALID, Argv[0], &lp); -  launchpad_load_from_file(lp, Argv[0]); -  launchpad_set_args(lp, Argc, Argv.get()); -  launchpad_clone(lp, LP_CLONE_ALL & (~LP_CLONE_FDIO_STDIO)); +  Argv[Argc] = nullptr;    // Determine stdout    int FdOut = STDOUT_FILENO; -  fbl::unique_fd OutputFile; +    if (Cmd.hasOutputFile()) {      auto Filename = Cmd.getOutputFile(); -    OutputFile.reset(open(Filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0)); -    if (!OutputFile) { +    FdOut = open(Filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0); +    if (FdOut == -1) {        Printf("libFuzzer: failed to open %s: %s\n", Filename.c_str(),               strerror(errno));        return ZX_ERR_IO;      } -    FdOut = OutputFile.get();    } +  auto CloseFdOut = at_scope_exit([&]() { close(FdOut); } );    // Determine stderr    int FdErr = STDERR_FILENO; @@ -182,36 +398,59 @@ int ExecuteCommand(const Command &Cmd) {      FdErr = FdOut;    // Clone the file descriptors into the new process -  if ((rc = launchpad_clone_fd(lp, STDIN_FILENO, STDIN_FILENO)) != ZX_OK || -      (rc = launchpad_clone_fd(lp, FdOut, STDOUT_FILENO)) != ZX_OK || -      (rc = launchpad_clone_fd(lp, FdErr, STDERR_FILENO)) != ZX_OK) { -    Printf("libFuzzer: failed to clone FDIO: %s\n", zx_status_get_string(rc)); -    return rc; -  } - -  // Start the process +  fdio_spawn_action_t SpawnAction[] = { +      { +          .action = FDIO_SPAWN_ACTION_CLONE_FD, +          .fd = +              { +                  .local_fd = STDIN_FILENO, +                  .target_fd = STDIN_FILENO, +              }, +      }, +      { +          .action = FDIO_SPAWN_ACTION_CLONE_FD, +          .fd = +              { +                  .local_fd = FdOut, +                  .target_fd = STDOUT_FILENO, +              }, +      }, +      { +          .action = FDIO_SPAWN_ACTION_CLONE_FD, +          .fd = +              { +                  .local_fd = FdErr, +                  .target_fd = STDERR_FILENO, +              }, +      }, +  }; + +  // Start the process. +  char ErrorMsg[FDIO_SPAWN_ERR_MSG_MAX_LENGTH];    zx_handle_t ProcessHandle = ZX_HANDLE_INVALID; -  const char *ErrorMsg = nullptr; -  if ((rc = launchpad_go(lp, &ProcessHandle, &ErrorMsg)) != ZX_OK) { +  rc = fdio_spawn_etc( +      ZX_HANDLE_INVALID, FDIO_SPAWN_CLONE_ALL & (~FDIO_SPAWN_CLONE_STDIO), +      Argv[0], Argv.get(), nullptr, 3, SpawnAction, &ProcessHandle, ErrorMsg); +  if (rc != ZX_OK) {      Printf("libFuzzer: failed to launch '%s': %s, %s\n", Argv[0], ErrorMsg, -           zx_status_get_string(rc)); +           _zx_status_get_string(rc));      return rc;    } -  zx::process Process(ProcessHandle); +  auto CloseHandle = at_scope_exit([&]() { _zx_handle_close(ProcessHandle); });    // Now join the process and return the exit status. -  if ((rc = Process.wait_one(ZX_PROCESS_TERMINATED, ZX_TIME_INFINITE, -                             nullptr)) != ZX_OK) { +  if ((rc = _zx_object_wait_one(ProcessHandle, ZX_PROCESS_TERMINATED, +                                ZX_TIME_INFINITE_OLD, nullptr)) != ZX_OK) {      Printf("libFuzzer: failed to join '%s': %s\n", Argv[0], -           zx_status_get_string(rc)); +           _zx_status_get_string(rc));      return rc;    }    zx_info_process_t Info; -  if ((rc = Process.get_info(ZX_INFO_PROCESS, &Info, sizeof(Info), nullptr, -                             nullptr)) != ZX_OK) { +  if ((rc = _zx_object_get_info(ProcessHandle, ZX_INFO_PROCESS, &Info, +                                sizeof(Info), nullptr, nullptr)) != ZX_OK) {      Printf("libFuzzer: unable to get return code from '%s': %s\n", Argv[0], -           zx_status_get_string(rc)); +           _zx_status_get_string(rc));      return rc;    } diff --git a/lib/fuzzer/FuzzerUtilLinux.cpp b/lib/fuzzer/FuzzerUtilLinux.cpp index c7cf2c0a778bc..c103fd230b0c6 100644 --- a/lib/fuzzer/FuzzerUtilLinux.cpp +++ b/lib/fuzzer/FuzzerUtilLinux.cpp @@ -9,7 +9,8 @@  // Misc utils for Linux.  //===----------------------------------------------------------------------===//  #include "FuzzerDefs.h" -#if LIBFUZZER_LINUX || LIBFUZZER_NETBSD +#if LIBFUZZER_LINUX || LIBFUZZER_NETBSD || LIBFUZZER_FREEBSD ||                \ +    LIBFUZZER_OPENBSD  #include "FuzzerCommand.h"  #include <stdlib.h> @@ -23,4 +24,4 @@ int ExecuteCommand(const Command &Cmd) {  } // namespace fuzzer -#endif // LIBFUZZER_LINUX || LIBFUZZER_NETBSD +#endif diff --git a/lib/fuzzer/FuzzerUtilPosix.cpp b/lib/fuzzer/FuzzerUtilPosix.cpp index 934b7aa98ff18..bc64d3293702f 100644 --- a/lib/fuzzer/FuzzerUtilPosix.cpp +++ b/lib/fuzzer/FuzzerUtilPosix.cpp @@ -118,7 +118,8 @@ size_t GetPeakRSSMb() {    struct rusage usage;    if (getrusage(RUSAGE_SELF, &usage))      return 0; -  if (LIBFUZZER_LINUX) { +  if (LIBFUZZER_LINUX || LIBFUZZER_FREEBSD || LIBFUZZER_NETBSD || +      LIBFUZZER_OPENBSD) {      // ru_maxrss is in KiB      return usage.ru_maxrss >> 10;    } else if (LIBFUZZER_APPLE) { diff --git a/lib/fuzzer/afl/afl_driver.cpp b/lib/fuzzer/afl/afl_driver.cpp index bbe5be795ed4a..fa494c03bde08 100644 --- a/lib/fuzzer/afl/afl_driver.cpp +++ b/lib/fuzzer/afl/afl_driver.cpp @@ -69,20 +69,38 @@ statistics from the file. If that fails then the process will quit.  #define LIBFUZZER_LINUX 1  #define LIBFUZZER_APPLE 0  #define LIBFUZZER_NETBSD 0 +#define LIBFUZZER_FREEBSD 0 +#define LIBFUZZER_OPENBSD 0  #elif __APPLE__  #define LIBFUZZER_LINUX 0  #define LIBFUZZER_APPLE 1  #define LIBFUZZER_NETBSD 0 +#define LIBFUZZER_FREEBSD 0 +#define LIBFUZZER_OPENBSD 0  #elif __NetBSD__  #define LIBFUZZER_LINUX 0  #define LIBFUZZER_APPLE 0  #define LIBFUZZER_NETBSD 1 +#define LIBFUZZER_FREEBSD 0 +#define LIBFUZZER_OPENBSD 0 +#elif __FreeBSD__ +#define LIBFUZZER_LINUX 0 +#define LIBFUZZER_APPLE 0 +#define LIBFUZZER_NETBSD 0 +#define LIBFUZZER_FREEBSD 1 +#define LIBFUZZER_OPENBSD 0 +#elif __OpenBSD__ +#define LIBFUZZER_LINUX 0 +#define LIBFUZZER_APPLE 0 +#define LIBFUZZER_NETBSD 0 +#define LIBFUZZER_FREEBSD 0 +#define LIBFUZZER_OPENBSD 1  #else  #error "Support for your platform has not been implemented"  #endif  // Used to avoid repeating error checking boilerplate. If cond is false, a -// fatal error has occured in the program. In this event print error_message +// fatal error has occurred in the program. In this event print error_message  // to stderr and abort(). Otherwise do nothing. Note that setting  // AFL_DRIVER_STDERR_DUPLICATE_FILENAME may cause error_message to be appended  // to the file as well, if the error occurs after the duplication is performed. @@ -120,12 +138,24 @@ static const int kNumExtraStats = 2;  static const char *kExtraStatsFormatString = "peak_rss_mb            : %u\n"                                               "slowest_unit_time_sec  : %u\n"; +// Experimental feature to use afl_driver without AFL's deferred mode. +// Needs to run before __afl_auto_init. +__attribute__((constructor(0))) void __decide_deferred_forkserver(void) { +  if (getenv("AFL_DRIVER_DONT_DEFER")) { +    if (unsetenv("__AFL_DEFER_FORKSRV")) { +      perror("Failed to unset __AFL_DEFER_FORKSRV"); +      abort(); +    } +  } +} +  // Copied from FuzzerUtil.cpp.  size_t GetPeakRSSMb() {    struct rusage usage;    if (getrusage(RUSAGE_SELF, &usage))      return 0; -  if (LIBFUZZER_LINUX || LIBFUZZER_NETBSD) { +  if (LIBFUZZER_LINUX || LIBFUZZER_NETBSD || LIBFUZZER_FREEBSD || +      LIBFUZZER_OPENBSD) {      // ru_maxrss is in KiB      return usage.ru_maxrss >> 10;    } else if (LIBFUZZER_APPLE) { @@ -270,7 +300,7 @@ int ExecuteFilesOnyByOne(int argc, char **argv) {      assert(in);      LLVMFuzzerTestOneInput(reinterpret_cast<const uint8_t *>(bytes.data()),                             bytes.size()); -    std::cout << "Execution successfull" << std::endl; +    std::cout << "Execution successful" << std::endl;    }    return 0;  } @@ -296,7 +326,8 @@ int main(int argc, char **argv) {    maybe_duplicate_stderr();    maybe_initialize_extra_stats(); -  __afl_manual_init(); +  if (!getenv("AFL_DRIVER_DONT_DEFER")) +    __afl_manual_init();    int N = 1000;    if (argc == 2 && argv[1][0] == '-') diff --git a/lib/fuzzer/build.sh b/lib/fuzzer/build.sh index 4556af5daf7db..504e54e3a819e 100755 --- a/lib/fuzzer/build.sh +++ b/lib/fuzzer/build.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/bin/sh  LIBFUZZER_SRC_DIR=$(dirname $0)  CXX="${CXX:-clang}"  for f in $LIBFUZZER_SRC_DIR/*.cpp; do diff --git a/lib/fuzzer/dataflow/DataFlow.cpp b/lib/fuzzer/dataflow/DataFlow.cpp new file mode 100644 index 0000000000000..a79c796ac456c --- /dev/null +++ b/lib/fuzzer/dataflow/DataFlow.cpp @@ -0,0 +1,217 @@ +/*===- DataFlow.cpp - a standalone DataFlow tracer                  -------===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// An experimental data-flow tracer for fuzz targets. +// It is based on DFSan and SanitizerCoverage. +// https://clang.llvm.org/docs/DataFlowSanitizer.html +// https://clang.llvm.org/docs/SanitizerCoverage.html#tracing-data-flow +// +// It executes the fuzz target on the given input while monitoring the +// data flow for every instrumented comparison instruction. +// +// The output shows which functions depend on which bytes of the input. +// +// Build: +//   1. Compile this file with -fsanitize=dataflow +//   2. Build the fuzz target with -g -fsanitize=dataflow +//       -fsanitize-coverage=trace-pc-guard,pc-table,func,trace-cmp +//   3. Link those together with -fsanitize=dataflow +// +//  -fsanitize-coverage=trace-cmp inserts callbacks around every comparison +//  instruction, DFSan modifies the calls to pass the data flow labels. +//  The callbacks update the data flow label for the current function. +//  See e.g. __dfsw___sanitizer_cov_trace_cmp1 below. +// +//  -fsanitize-coverage=trace-pc-guard,pc-table,func instruments function +//  entries so that the comparison callback knows that current function. +// +// +// Run: +//   # Collect data flow for INPUT_FILE, write to OUTPUT_FILE (default: stdout) +//   ./a.out INPUT_FILE [OUTPUT_FILE] +// +//   # Print all instrumented functions. llvm-symbolizer must be present in PATH +//   ./a.out +// +// Example output: +// =============== +//  F0 11111111111111 +//  F1 10000000000000 +//  =============== +// "FN xxxxxxxxxx": tells what bytes of the input does the function N depend on. +//    The byte string is LEN+1 bytes. The last byte is set if the function +//    depends on the input length. +//===----------------------------------------------------------------------===*/ + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <string.h> + +#include <execinfo.h>  // backtrace_symbols_fd + +#include <sanitizer/dfsan_interface.h> + +extern "C" { +extern int LLVMFuzzerTestOneInput(const unsigned char *Data, size_t Size); +__attribute__((weak)) extern int LLVMFuzzerInitialize(int *argc, char ***argv); +} // extern "C" + +static size_t InputLen; +static size_t NumFuncs; +static const uintptr_t *FuncsBeg; +static __thread size_t CurrentFunc; +static dfsan_label *FuncLabels;  // Array of NumFuncs elements. +static char *PrintableStringForLabel;  // InputLen + 2 bytes. +static bool LabelSeen[1 << 8 * sizeof(dfsan_label)]; + +// Prints all instrumented functions. +static int PrintFunctions() { +  // We don't have the symbolizer integrated with dfsan yet. +  // So use backtrace_symbols_fd and pipe it through llvm-symbolizer. +  // TODO(kcc): this is pretty ugly and may break in lots of ways. +  //      We'll need to make a proper in-process symbolizer work with DFSan. +  FILE *Pipe = popen("sed 's/(+/ /g; s/).*//g' " +                     "| llvm-symbolizer " +                     "| grep 'dfs\\$' " +                     "| sed 's/dfs\\$//g'", "w"); +  for (size_t I = 0; I < NumFuncs; I++) { +    uintptr_t PC = FuncsBeg[I * 2]; +    void *const Buf[1] = {(void*)PC}; +    backtrace_symbols_fd(Buf, 1, fileno(Pipe)); +  } +  pclose(Pipe); +  return 0; +} + +extern "C" +void SetBytesForLabel(dfsan_label L, char *Bytes) { +  if (LabelSeen[L]) +    return; +  LabelSeen[L] = true; +  assert(L); +  if (L <= InputLen + 1) { +    Bytes[L - 1] = '1'; +  } else { +    auto *DLI = dfsan_get_label_info(L); +    SetBytesForLabel(DLI->l1, Bytes); +    SetBytesForLabel(DLI->l2, Bytes); +  } +} + +static char *GetPrintableStringForLabel(dfsan_label L) { +  memset(PrintableStringForLabel, '0', InputLen + 1); +  PrintableStringForLabel[InputLen + 1] = 0; +  memset(LabelSeen, 0, sizeof(LabelSeen)); +  SetBytesForLabel(L, PrintableStringForLabel); +  return PrintableStringForLabel; +} + +static void PrintDataFlow(FILE *Out) { +  for (size_t I = 0; I < NumFuncs; I++) +    if (FuncLabels[I]) +      fprintf(Out, "F%zd %s\n", I, GetPrintableStringForLabel(FuncLabels[I])); +} + +int main(int argc, char **argv) { +  if (LLVMFuzzerInitialize) +    LLVMFuzzerInitialize(&argc, &argv); +  if (argc == 1) +    return PrintFunctions(); +  assert(argc == 4 || argc == 5); +  size_t Beg = atoi(argv[1]); +  size_t End = atoi(argv[2]); +  assert(Beg < End); + +  const char *Input = argv[3]; +  fprintf(stderr, "INFO: reading '%s'\n", Input); +  FILE *In = fopen(Input, "r"); +  assert(In); +  fseek(In, 0, SEEK_END); +  InputLen = ftell(In); +  fseek(In, 0, SEEK_SET); +  unsigned char *Buf = (unsigned char*)malloc(InputLen); +  size_t NumBytesRead = fread(Buf, 1, InputLen, In); +  assert(NumBytesRead == InputLen); +  PrintableStringForLabel = (char*)malloc(InputLen + 2); +  fclose(In); + +  fprintf(stderr, "INFO: running '%s'\n", Input); +  for (size_t I = 1; I <= InputLen; I++) { +    dfsan_label L = dfsan_create_label("", nullptr); +    assert(L == I); +    size_t Idx = I - 1; +    if (Idx >= Beg && Idx < End) +      dfsan_set_label(L, Buf + Idx, 1); +  } +  dfsan_label SizeL = dfsan_create_label("", nullptr); +  assert(SizeL == InputLen + 1); +  dfsan_set_label(SizeL, &InputLen, sizeof(InputLen)); + +  LLVMFuzzerTestOneInput(Buf, InputLen); +  free(Buf); + +  bool OutIsStdout = argc == 4; +  fprintf(stderr, "INFO: writing dataflow to %s\n", +          OutIsStdout ? "<stdout>" : argv[4]); +  FILE *Out = OutIsStdout ? stdout : fopen(argv[4], "w"); +  PrintDataFlow(Out); +  if (!OutIsStdout) fclose(Out); +} + +extern "C" { + +void __sanitizer_cov_trace_pc_guard_init(uint32_t *start, +                                         uint32_t *stop) { +  assert(NumFuncs == 0 && "This tool does not support DSOs"); +  assert(start < stop && "The code is not instrumented for coverage"); +  if (start == stop || *start) return;  // Initialize only once. +  for (uint32_t *x = start; x < stop; x++) +    *x = ++NumFuncs;  // The first index is 1. +  FuncLabels = (dfsan_label*)calloc(NumFuncs, sizeof(dfsan_label)); +  fprintf(stderr, "INFO: %zd instrumented function(s) observed\n", NumFuncs); +} + +void __sanitizer_cov_pcs_init(const uintptr_t *pcs_beg, +                              const uintptr_t *pcs_end) { +  assert(NumFuncs == (pcs_end - pcs_beg) / 2); +  FuncsBeg = pcs_beg; +} + +void __sanitizer_cov_trace_pc_indir(uint64_t x){}  // unused. + +void __sanitizer_cov_trace_pc_guard(uint32_t *guard){ +  uint32_t FuncNum = *guard - 1;  // Guards start from 1. +  assert(FuncNum < NumFuncs); +  CurrentFunc = FuncNum; +} + +void __dfsw___sanitizer_cov_trace_switch(uint64_t Val, uint64_t *Cases, +                                         dfsan_label L1, dfsan_label UnusedL) { +  assert(CurrentFunc < NumFuncs); +  FuncLabels[CurrentFunc] = dfsan_union(FuncLabels[CurrentFunc], L1); +} + +#define HOOK(Name, Type)                                                       \ +  void Name(Type Arg1, Type Arg2, dfsan_label L1, dfsan_label L2) {            \ +    assert(CurrentFunc < NumFuncs);                                            \ +    FuncLabels[CurrentFunc] =                                                  \ +        dfsan_union(FuncLabels[CurrentFunc], dfsan_union(L1, L2));             \ +  } + +HOOK(__dfsw___sanitizer_cov_trace_const_cmp1, uint8_t) +HOOK(__dfsw___sanitizer_cov_trace_const_cmp2, uint16_t) +HOOK(__dfsw___sanitizer_cov_trace_const_cmp4, uint32_t) +HOOK(__dfsw___sanitizer_cov_trace_const_cmp8, uint64_t) +HOOK(__dfsw___sanitizer_cov_trace_cmp1, uint8_t) +HOOK(__dfsw___sanitizer_cov_trace_cmp2, uint16_t) +HOOK(__dfsw___sanitizer_cov_trace_cmp4, uint32_t) +HOOK(__dfsw___sanitizer_cov_trace_cmp8, uint64_t) + +} // extern "C" diff --git a/lib/fuzzer/scripts/collect_data_flow.py b/lib/fuzzer/scripts/collect_data_flow.py new file mode 100755 index 0000000000000..3edff66bb9d16 --- /dev/null +++ b/lib/fuzzer/scripts/collect_data_flow.py @@ -0,0 +1,79 @@ +#!/usr/bin/env python +#===- lib/fuzzer/scripts/collect_data_flow.py ------------------------------===# +# +#                     The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +#===------------------------------------------------------------------------===# +# Runs the data-flow tracer several times on the same input in order to collect +# the complete trace for all input bytes (running it on all bytes at once +# may fail if DFSan runs out of labels). +# Usage: +# +#   # Collect dataflow for one input, store it in OUTPUT (default is stdout) +#   collect_data_flow.py BINARY INPUT [OUTPUT] +# +#   # Collect dataflow for all inputs in CORPUS_DIR, store them in OUTPUT_DIR +#   collect_data_flow.py BINARY CORPUS_DIR OUTPUT_DIR +#===------------------------------------------------------------------------===# +import atexit +import hashlib +import sys +import os +import subprocess +import tempfile +import shutil + +tmpdir = "" + +def cleanup(d): +  print("removing: %s" % d) +  shutil.rmtree(d) + +def collect_dataflow_for_corpus(self, exe, corpus_dir, output_dir): +  print("Collecting dataflow for corpus: %s output_dir: %s" % (corpus_dir, +                                                               output_dir)) +  assert not os.path.exists(output_dir) +  os.mkdir(output_dir) +  for root, dirs, files in os.walk(corpus_dir): +    for f in files: +      path = os.path.join(root, f) +      sha1 = hashlib.sha1(open(path).read()).hexdigest() +      output = os.path.join(output_dir, sha1) +      subprocess.call([self, exe, path, output]) +  functions_txt = open(os.path.join(output_dir, "functions.txt"), "w") +  subprocess.call([exe], stdout=functions_txt) + + +def main(argv): +  exe = argv[1] +  inp = argv[2] +  if os.path.isdir(inp): +    return collect_dataflow_for_corpus(argv[0], exe, inp, argv[3]) +  size = os.path.getsize(inp) +  q = [[0, size]] +  tmpdir = tempfile.mkdtemp(prefix="libfuzzer-tmp-") +  atexit.register(cleanup, tmpdir) +  print "tmpdir: ", tmpdir +  outputs = [] +  while len(q): +    r = q.pop() +    print "******* Trying:  ", r +    tmpfile = os.path.join(tmpdir, str(r[0]) + "-" + str(r[1])) +    ret = subprocess.call([exe, str(r[0]), str(r[1]), inp, tmpfile]) +    if ret and r[1] - r[0] >= 2: +      q.append([r[0], (r[1] + r[0]) / 2]) +      q.append([(r[1] + r[0]) / 2, r[1]]) +    else: +      outputs.append(tmpfile) +      print "******* Success: ", r +  f = sys.stdout +  if len(argv) >= 4: +    f = open(argv[3], "w") +  merge = os.path.join(os.path.dirname(argv[0]), "merge_data_flow.py") +  subprocess.call([merge] + outputs, stdout=f) + +if __name__ == '__main__': +  main(sys.argv) diff --git a/lib/fuzzer/scripts/merge_data_flow.py b/lib/fuzzer/scripts/merge_data_flow.py new file mode 100755 index 0000000000000..d2f5081e7b8cc --- /dev/null +++ b/lib/fuzzer/scripts/merge_data_flow.py @@ -0,0 +1,36 @@ +#!/usr/bin/env python +#===- lib/fuzzer/scripts/merge_data_flow.py ------------------------------===# +# +#                     The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +#===------------------------------------------------------------------------===# +# Merge several data flow traces into one. +# Usage: +#   merge_data_flow.py trace1 trace2 ...  > result +#===------------------------------------------------------------------------===# +import sys +import fileinput +from array import array + +def Merge(a, b): +  res = array('b') +  for i in range(0, len(a)): +    res.append(ord('1' if a[i] == '1' or b[i] == '1' else '0')) +  return res.tostring() + +def main(argv): +  D = {} +  for line in fileinput.input(): +    [F,BV] = line.strip().split(' ') +    if F in D: +      D[F] = Merge(D[F], BV) +    else: +      D[F] = BV; +  for F in D.keys(): +    print("%s %s" % (F, D[F])) + +if __name__ == '__main__': +  main(sys.argv) diff --git a/lib/fuzzer/scripts/unbalanced_allocs.py b/lib/fuzzer/scripts/unbalanced_allocs.py index a4ce187679d74..74478ad55af0c 100755 --- a/lib/fuzzer/scripts/unbalanced_allocs.py +++ b/lib/fuzzer/scripts/unbalanced_allocs.py @@ -24,9 +24,9 @@ def PrintStack(line, stack):    global _skip    if _skip > 0:      return -  print 'Unbalanced ' + line.rstrip(); +  print('Unbalanced ' + line.rstrip());    for l in stack: -    print l.rstrip() +    print(l.rstrip())  def ProcessStack(line, f):    stack = [] @@ -63,15 +63,15 @@ def ProcessRun(line, f):      return ProcessMalloc(line, f, {})    allocs = {} -  print line.rstrip() +  print(line.rstrip())    line = f.readline()    while line:      if line.startswith('MallocFreeTracer: STOP'):        global _skip        _skip = _skip - 1 -      for _, (l, s) in allocs.iteritems(): +      for _, (l, s) in allocs.items():          PrintStack(l, s) -      print line.rstrip() +      print(line.rstrip())        return f.readline()      line = ProcessMalloc(line, f, allocs)    return line diff --git a/lib/fuzzer/tests/CMakeLists.txt b/lib/fuzzer/tests/CMakeLists.txt index dac8773597e8c..ed5807168301b 100644 --- a/lib/fuzzer/tests/CMakeLists.txt +++ b/lib/fuzzer/tests/CMakeLists.txt @@ -3,22 +3,32 @@ set(LIBFUZZER_UNITTEST_CFLAGS    ${COMPILER_RT_GTEST_CFLAGS}    -I${COMPILER_RT_SOURCE_DIR}/lib/fuzzer    -fno-rtti -  -Werror    -O2) +if (APPLE) +  set(FUZZER_SUPPORTED_OS osx) +endif() +  add_custom_target(FuzzerUnitTests)  set_target_properties(FuzzerUnitTests PROPERTIES FOLDER "Compiler-RT Tests")  set(LIBFUZZER_UNITTEST_LINK_FLAGS ${COMPILER_RT_UNITTEST_LINK_FLAGS})  list(APPEND LIBFUZZER_UNITTEST_LINK_FLAGS --driver-mode=g++) -if(APPLE) -  list(APPEND LIBFUZZER_UNITTEST_LINK_FLAGS -lc++) +if(APPLE OR CMAKE_SYSTEM_NAME STREQUAL "FreeBSD") +  list(APPEND LIBFUZZER_UNITTEST_LINK_FLAGS -lc++ -lpthread)  else()    list(APPEND LIBFUZZER_UNITTEST_LINK_FLAGS -lstdc++ -lpthread)  endif() -foreach(arch ${FUZZER_SUPPORTED_ARCH}) +if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux" AND COMPILER_RT_LIBCXX_PATH) +  list(APPEND LIBFUZZER_UNITTEST_CFLAGS -nostdinc++ -D_LIBCPP_ABI_VERSION=Fuzzer) +endif() + +if(COMPILER_RT_DEFAULT_TARGET_ARCH IN_LIST FUZZER_SUPPORTED_ARCH) +  # libFuzzer unit tests are only run on the host machine. +  set(arch ${COMPILER_RT_DEFAULT_TARGET_ARCH}) +    set(LIBFUZZER_TEST_RUNTIME RTFuzzerTest.${arch})    if(APPLE)      set(LIBFUZZER_TEST_RUNTIME_OBJECTS @@ -33,14 +43,20 @@ foreach(arch ${FUZZER_SUPPORTED_ARCH})      ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}      FOLDER "Compiler-RT Runtime tests") +  if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux" AND COMPILER_RT_LIBCXX_PATH) +    set(LIBFUZZER_TEST_RUNTIME_DEPS libcxx_fuzzer_${arch}-build) +    set(LIBFUZZER_TEST_RUNTIME_CFLAGS -isystem ${COMPILER_RT_LIBCXX_PATH}/include) +    set(LIBFUZZER_TEST_RUNTIME_LINK_FLAGS ${LIBCXX_${arch}_PREFIX}/lib/libc++.a) +  endif() +    set(FuzzerTestObjects)    generate_compiler_rt_tests(FuzzerTestObjects      FuzzerUnitTests "Fuzzer-${arch}-Test" ${arch}      SOURCES FuzzerUnittest.cpp ${COMPILER_RT_GTEST_SOURCE}      RUNTIME ${LIBFUZZER_TEST_RUNTIME} -    DEPS gtest -    CFLAGS ${LIBFUZZER_UNITTEST_CFLAGS} -    LINK_FLAGS ${LIBFUZZER_UNITTEST_LINK_FLAGS}) +    DEPS gtest ${LIBFUZZER_TEST_RUNTIME_DEPS} +    CFLAGS ${LIBFUZZER_UNITTEST_CFLAGS} ${LIBFUZZER_TEST_RUNTIME_CFLAGS} +    LINK_FLAGS ${LIBFUZZER_UNITTEST_LINK_FLAGS} ${LIBFUZZER_TEST_RUNTIME_LINK_FLAGS})    set_target_properties(FuzzerUnitTests PROPERTIES      RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) -endforeach() +endif() diff --git a/lib/fuzzer/tests/FuzzerUnittest.cpp b/lib/fuzzer/tests/FuzzerUnittest.cpp index 97ec3b4bb6af4..e3b06702603d0 100644 --- a/lib/fuzzer/tests/FuzzerUnittest.cpp +++ b/lib/fuzzer/tests/FuzzerUnittest.cpp @@ -28,6 +28,14 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {    abort();  } +TEST(Fuzzer, Basename) { +  EXPECT_EQ(Basename("foo/bar"), "bar"); +  EXPECT_EQ(Basename("bar"), "bar"); +  EXPECT_EQ(Basename("/bar"), "bar"); +  EXPECT_EQ(Basename("foo/x"), "x"); +  EXPECT_EQ(Basename("foo/"), ""); +} +  TEST(Fuzzer, CrossOver) {    std::unique_ptr<ExternalFunctions> t(new ExternalFunctions());    fuzzer::EF = t.get(); @@ -328,7 +336,7 @@ void TestShuffleBytes(Mutator M, int NumIter) {  }  TEST(FuzzerMutate, ShuffleBytes1) { -  TestShuffleBytes(&MutationDispatcher::Mutate_ShuffleBytes, 1 << 16); +  TestShuffleBytes(&MutationDispatcher::Mutate_ShuffleBytes, 1 << 17);  }  TEST(FuzzerMutate, ShuffleBytes2) {    TestShuffleBytes(&MutationDispatcher::Mutate, 1 << 20); @@ -381,6 +389,21 @@ TEST(FuzzerMutate, CopyPart1) {  TEST(FuzzerMutate, CopyPart2) {    TestCopyPart(&MutationDispatcher::Mutate, 1 << 13);  } +TEST(FuzzerMutate, CopyPartNoInsertAtMaxSize) { +  // This (non exhaustively) tests if `Mutate_CopyPart` tries to perform an +  // insert on an input of size `MaxSize`.  Performing an insert in this case +  // will lead to the mutation failing. +  std::unique_ptr<ExternalFunctions> t(new ExternalFunctions()); +  fuzzer::EF = t.get(); +  Random Rand(0); +  std::unique_ptr<MutationDispatcher> MD(new MutationDispatcher(Rand, {})); +  uint8_t Data[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x00, 0x11, 0x22}; +  size_t MaxSize = sizeof(Data); +  for (int count = 0; count < (1 << 18); ++count) { +    size_t NewSize = MD->Mutate_CopyPart(Data, MaxSize, MaxSize); +    ASSERT_EQ(NewSize, MaxSize); +  } +}  void TestAddWordFromDictionary(Mutator M, int NumIter) {    std::unique_ptr<ExternalFunctions> t(new ExternalFunctions()); @@ -559,12 +582,14 @@ TEST(FuzzerUtil, Base64) {  }  TEST(Corpus, Distribution) { +  DataFlowTrace DFT;    Random Rand(0);    std::unique_ptr<InputCorpus> C(new InputCorpus(""));    size_t N = 10;    size_t TriesPerUnit = 1<<16;    for (size_t i = 0; i < N; i++) -    C->AddToCorpus(Unit{ static_cast<uint8_t>(i) }, 1, false, {}); +    C->AddToCorpus(Unit{static_cast<uint8_t>(i)}, 1, false, false, {}, DFT, +                   nullptr);    Vector<size_t> Hist(N);    for (size_t i = 0; i < N * TriesPerUnit; i++) { diff --git a/lib/hwasan/.clang-format b/lib/hwasan/.clang-format index f6cb8ad931f54..560308c91deec 100644 --- a/lib/hwasan/.clang-format +++ b/lib/hwasan/.clang-format @@ -1 +1,2 @@  BasedOnStyle: Google +AllowShortIfStatementsOnASingleLine: false diff --git a/lib/hwasan/CMakeLists.txt b/lib/hwasan/CMakeLists.txt index 3f3a6155590c6..42bf4366f1929 100644 --- a/lib/hwasan/CMakeLists.txt +++ b/lib/hwasan/CMakeLists.txt @@ -4,39 +4,38 @@ include_directories(..)  set(HWASAN_RTL_SOURCES    hwasan.cc    hwasan_allocator.cc +  hwasan_dynamic_shadow.cc    hwasan_interceptors.cc    hwasan_linux.cc +  hwasan_poisoning.cc    hwasan_report.cc    hwasan_thread.cc -  hwasan_poisoning.cc    )  set(HWASAN_RTL_CXX_SOURCES    hwasan_new_delete.cc) +set(HWASAN_RTL_HEADERS +  hwasan.h +  hwasan_allocator.h +  hwasan_dynamic_shadow.h +  hwasan_flags.h +  hwasan_flags.inc +  hwasan_interface_internal.h +  hwasan_mapping.h +  hwasan_poisoning.h +  hwasan_report.h +  hwasan_thread.h) +  set(HWASAN_RTL_CFLAGS ${SANITIZER_COMMON_CFLAGS})  append_rtti_flag(OFF HWASAN_RTL_CFLAGS) -append_list_if(COMPILER_RT_HAS_FPIE_FLAG -fPIE HWASAN_RTL_CFLAGS) +append_list_if(COMPILER_RT_HAS_FPIC_FLAG -fPIC HWASAN_RTL_CFLAGS)  # Prevent clang from generating libc calls.  append_list_if(COMPILER_RT_HAS_FFREESTANDING_FLAG -ffreestanding HWASAN_RTL_CFLAGS)  set(HWASAN_DYNAMIC_LINK_FLAGS ${SANITIZER_COMMON_LINK_FLAGS}) -if(ANDROID) -# On Android, -z global does not do what it is documented to do. -# On Android, -z global moves the library ahead in the lookup order, -# placing it right after the LD_PRELOADs. This is used to compensate for the fact -# that Android linker does not look at the dependencies of the main executable -# that aren't dependencies of the current DSO when resolving symbols from said DSO. -# As a net result, this allows running ASan executables without LD_PRELOAD-ing the -# ASan runtime library. -# The above is applicable to L MR1 or newer. -  if (COMPILER_RT_HAS_Z_GLOBAL) -    list(APPEND HWASAN_DYNAMIC_LINK_FLAGS -Wl,-z,global) -  endif() -endif() -  set(HWASAN_DYNAMIC_CFLAGS ${HWASAN_RTL_CFLAGS})  append_list_if(COMPILER_RT_HAS_FTLS_MODEL_INITIAL_EXEC    -ftls-model=initial-exec HWASAN_DYNAMIC_CFLAGS) @@ -55,13 +54,18 @@ add_compiler_rt_component(hwasan)  add_compiler_rt_object_libraries(RTHwasan    ARCHS ${HWASAN_SUPPORTED_ARCH} -  SOURCES ${HWASAN_RTL_SOURCES} CFLAGS ${HWASAN_RTL_CFLAGS}) +  SOURCES ${HWASAN_RTL_SOURCES} +  ADDITIONAL_HEADERS ${HWASAN_RTL_HEADERS} +  CFLAGS ${HWASAN_RTL_CFLAGS})  add_compiler_rt_object_libraries(RTHwasan_cxx    ARCHS ${HWASAN_SUPPORTED_ARCH} -  SOURCES ${HWASAN_RTL_CXX_SOURCES} CFLAGS ${HWASAN_RTL_CFLAGS}) +  SOURCES ${HWASAN_RTL_CXX_SOURCES} +  ADDITIONAL_HEADERS ${HWASAN_RTL_HEADERS} +  CFLAGS ${HWASAN_RTL_CFLAGS})  add_compiler_rt_object_libraries(RTHwasan_dynamic    ARCHS ${HWASAN_SUPPORTED_ARCH} -  SOURCES ${HWASAN_RTL_SOURCES} ${TSAN_RTL_CXX_SOURCES} +  SOURCES ${HWASAN_RTL_SOURCES} ${HWASAN_RTL_CXX_SOURCES} +  ADDITIONAL_HEADERS ${HWASAN_RTL_HEADERS}    CFLAGS ${HWASAN_DYNAMIC_CFLAGS})  file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/dummy.cc "") @@ -78,7 +82,9 @@ foreach(arch ${HWASAN_SUPPORTED_ARCH})                  RTInterception                  RTSanitizerCommon                  RTSanitizerCommonLibc -		RTUbsan +                RTSanitizerCommonCoverage +                RTSanitizerCommonSymbolizer +                RTUbsan      CFLAGS ${HWASAN_RTL_CFLAGS}      PARENT_TARGET hwasan)    add_compiler_rt_runtime(clang_rt.hwasan_cxx @@ -112,7 +118,9 @@ foreach(arch ${HWASAN_SUPPORTED_ARCH})              RTInterception              RTSanitizerCommon              RTSanitizerCommonLibc -	    RTUbsan +            RTSanitizerCommonCoverage +            RTSanitizerCommonSymbolizer +            RTUbsan              # The only purpose of RTHWAsan_dynamic_version_script_dummy is to              # carry a dependency of the shared runtime on the version script.              # Replacing it with a straightforward @@ -126,7 +134,7 @@ foreach(arch ${HWASAN_SUPPORTED_ARCH})      DEFS ${ASAN_DYNAMIC_DEFINITIONS}      PARENT_TARGET hwasan) -  if(UNIX) +  if(SANITIZER_USE_SYMBOLS)      add_sanitizer_rt_symbols(clang_rt.hwasan        ARCHS ${arch}        EXTRA hwasan.syms.extra) diff --git a/lib/hwasan/hwasan.cc b/lib/hwasan/hwasan.cc index 8b1e5a7846af5..7dab8249e3f71 100644 --- a/lib/hwasan/hwasan.cc +++ b/lib/hwasan/hwasan.cc @@ -1,4 +1,4 @@ -//===-- hwasan.cc -----------------------------------------------------------===// +//===-- hwasan.cc ---------------------------------------------------------===//  //  //                     The LLVM Compiler Infrastructure  // @@ -13,8 +13,10 @@  //===----------------------------------------------------------------------===//  #include "hwasan.h" -#include "hwasan_thread.h" +#include "hwasan_mapping.h"  #include "hwasan_poisoning.h" +#include "hwasan_report.h" +#include "hwasan_thread.h"  #include "sanitizer_common/sanitizer_atomic.h"  #include "sanitizer_common/sanitizer_common.h"  #include "sanitizer_common/sanitizer_flags.h" @@ -84,7 +86,7 @@ static void InitializeFlags() {      cf.check_printf = false;      cf.intercept_tls_get_addr = true;      cf.exitcode = 99; -    cf.handle_sigill = kHandleSignalExclusive; +    cf.handle_sigtrap = kHandleSignalExclusive;      OverrideCommonFlags(cf);    } @@ -143,12 +145,22 @@ void PrintWarning(uptr pc, uptr bp) {    ReportInvalidAccess(&stack, 0);  } +static void HWAsanCheckFailed(const char *file, int line, const char *cond, +                              u64 v1, u64 v2) { +  Report("HWAddressSanitizer CHECK failed: %s:%d \"%s\" (0x%zx, 0x%zx)\n", file, +         line, cond, (uptr)v1, (uptr)v2); +  PRINT_CURRENT_STACK_CHECK(); +  Die(); +} +  } // namespace __hwasan  // Interface.  using namespace __hwasan; +uptr __hwasan_shadow_memory_dynamic_address;  // Global interface symbol. +  void __hwasan_init() {    CHECK(!hwasan_init_is_running);    if (hwasan_inited) return; @@ -160,23 +172,28 @@ void __hwasan_init() {    CacheBinaryName();    InitializeFlags(); -  __sanitizer_set_report_path(common_flags()->log_path); +  // Install tool-specific callbacks in sanitizer_common. +  SetCheckFailedCallback(HWAsanCheckFailed); -  InitializeInterceptors(); -  InstallDeadlySignalHandlers(HwasanOnDeadlySignal); -  InstallAtExitHandler(); // Needs __cxa_atexit interceptor. +  __sanitizer_set_report_path(common_flags()->log_path);    DisableCoreDumperIfNecessary();    if (!InitShadow()) { -    Printf("FATAL: HWAddressSanitizer can not mmap the shadow memory.\n"); -    Printf("FATAL: Make sure to compile with -fPIE and to link with -pie.\n"); -    Printf("FATAL: Disabling ASLR is known to cause this error.\n"); -    Printf("FATAL: If running under GDB, try " -           "'set disable-randomization off'.\n"); +    Printf("FATAL: HWAddressSanitizer cannot mmap the shadow memory.\n"); +    if (HWASAN_FIXED_MAPPING) { +      Printf("FATAL: Make sure to compile with -fPIE and to link with -pie.\n"); +      Printf("FATAL: Disabling ASLR is known to cause this error.\n"); +      Printf("FATAL: If running under GDB, try " +             "'set disable-randomization off'.\n"); +    }      DumpProcessMap();      Die();    } +  InitializeInterceptors(); +  InstallDeadlySignalHandlers(HwasanOnDeadlySignal); +  InstallAtExitHandler(); // Needs __cxa_atexit interceptor. +    Symbolizer::GetOrInit()->AddHooks(EnterSymbolizer, ExitSymbolizer);    InitializeCoverage(common_flags()->coverage, common_flags()->coverage_dir); @@ -240,11 +257,23 @@ void __sanitizer_unaligned_store64(uu64 *p, u64 x) {  template<unsigned X>  __attribute__((always_inline)) -static void SigIll() { +static void SigTrap(uptr p) {  #if defined(__aarch64__) -  asm("hlt %0\n\t" ::"n"(X)); -#elif defined(__x86_64__) || defined(__i386__) -  asm("ud2\n\t"); +  (void)p; +  // 0x900 is added to do not interfere with the kernel use of lower values of +  // brk immediate. +  // FIXME: Add a constraint to put the pointer into x0, the same as x86 branch. +  asm("brk %0\n\t" ::"n"(0x900 + X)); +#elif defined(__x86_64__) +  // INT3 + NOP DWORD ptr [EAX + X] to pass X to our signal handler, 5 bytes +  // total. The pointer is passed via rdi. +  // 0x40 is added as a safeguard, to help distinguish our trap from others and +  // to avoid 0 offsets in the command (otherwise it'll be reduced to a +  // different nop command, the three bytes one). +  asm volatile( +      "int3\n" +      "nopl %c0(%%rax)\n" +      :: "n"(0x40 + X), "D"(p));  #else    // FIXME: not always sigill.    __builtin_trap(); @@ -261,8 +290,8 @@ __attribute__((always_inline, nodebug)) static void CheckAddress(uptr p) {    uptr ptr_raw = p & ~kAddressTagMask;    tag_t mem_tag = *(tag_t *)MEM_TO_SHADOW(ptr_raw);    if (UNLIKELY(ptr_tag != mem_tag)) { -    SigIll<0x100 + 0x20 * (EA == ErrorAction::Recover) + -           0x10 * (AT == AccessType::Store) + LogSize>(); +    SigTrap<0x20 * (EA == ErrorAction::Recover) + +           0x10 * (AT == AccessType::Store) + LogSize>(p);      if (EA == ErrorAction::Abort) __builtin_unreachable();    }  } @@ -277,13 +306,13 @@ __attribute__((always_inline, nodebug)) static void CheckAddressSized(uptr p,    tag_t *shadow_last = (tag_t *)MEM_TO_SHADOW(ptr_raw + sz - 1);    for (tag_t *t = shadow_first; t <= shadow_last; ++t)      if (UNLIKELY(ptr_tag != *t)) { -      SigIll<0x100 + 0x20 * (EA == ErrorAction::Recover) + -             0x10 * (AT == AccessType::Store) + 0xf>(); +      SigTrap<0x20 * (EA == ErrorAction::Recover) + +             0x10 * (AT == AccessType::Store) + 0xf>(p);        if (EA == ErrorAction::Abort) __builtin_unreachable();      }  } -void __hwasan_load(uptr p, uptr sz) { +void __hwasan_loadN(uptr p, uptr sz) {    CheckAddressSized<ErrorAction::Abort, AccessType::Load>(p, sz);  }  void __hwasan_load1(uptr p) { @@ -302,7 +331,7 @@ void __hwasan_load16(uptr p) {    CheckAddress<ErrorAction::Abort, AccessType::Load, 4>(p);  } -void __hwasan_load_noabort(uptr p, uptr sz) { +void __hwasan_loadN_noabort(uptr p, uptr sz) {    CheckAddressSized<ErrorAction::Recover, AccessType::Load>(p, sz);  }  void __hwasan_load1_noabort(uptr p) { @@ -321,7 +350,7 @@ void __hwasan_load16_noabort(uptr p) {    CheckAddress<ErrorAction::Recover, AccessType::Load, 4>(p);  } -void __hwasan_store(uptr p, uptr sz) { +void __hwasan_storeN(uptr p, uptr sz) {    CheckAddressSized<ErrorAction::Abort, AccessType::Store>(p, sz);  }  void __hwasan_store1(uptr p) { @@ -340,7 +369,7 @@ void __hwasan_store16(uptr p) {    CheckAddress<ErrorAction::Abort, AccessType::Store, 4>(p);  } -void __hwasan_store_noabort(uptr p, uptr sz) { +void __hwasan_storeN_noabort(uptr p, uptr sz) {    CheckAddressSized<ErrorAction::Recover, AccessType::Store>(p, sz);  }  void __hwasan_store1_noabort(uptr p) { @@ -359,6 +388,18 @@ void __hwasan_store16_noabort(uptr p) {    CheckAddress<ErrorAction::Recover, AccessType::Store, 4>(p);  } +void __hwasan_tag_memory(uptr p, u8 tag, uptr sz) { +  TagMemoryAligned(p, sz, tag); +} + +static const u8 kFallbackTag = 0xBB; + +u8 __hwasan_generate_tag() { +  HwasanThread *t = GetCurrentThread(); +  if (!t) return kFallbackTag; +  return t->GenerateRandomTag(); +} +  #if !SANITIZER_SUPPORTS_WEAK_HOOKS  extern "C" {  SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE diff --git a/lib/hwasan/hwasan.h b/lib/hwasan/hwasan.h index bcf5282dce7c3..47d1d057a0ddb 100644 --- a/lib/hwasan/hwasan.h +++ b/lib/hwasan/hwasan.h @@ -1,4 +1,4 @@ -//===-- hwasan.h --------------------------------------------------*- C++ -*-===// +//===-- hwasan.h ------------------------------------------------*- C++ -*-===//  //  //                     The LLVM Compiler Infrastructure  // @@ -32,16 +32,6 @@  typedef u8 tag_t; -// Reasonable values are 4 (for 1/16th shadow) and 6 (for 1/64th). -const uptr kShadowScale = 4; -const uptr kShadowAlignment = 1UL << kShadowScale; - -#define MEM_TO_SHADOW_OFFSET(mem) ((uptr)(mem) >> kShadowScale) -#define MEM_TO_SHADOW(mem) ((uptr)(mem) >> kShadowScale) -#define SHADOW_TO_MEM(shadow) ((uptr)(shadow) << kShadowScale) - -#define MEM_IS_APP(mem) true -  // TBI (Top Byte Ignore) feature of AArch64: bits [63:56] are ignored in address  // translation and can be used to store a tag.  const unsigned kAddressTagShift = 56; @@ -107,15 +97,6 @@ void PrintWarning(uptr pc, uptr bp);  void GetStackTrace(BufferedStackTrace *stack, uptr max_s, uptr pc, uptr bp,                     void *context, bool request_fast_unwind); -void ReportInvalidAccess(StackTrace *stack, u32 origin); -void ReportTagMismatch(StackTrace *stack, uptr addr, uptr access_size, -                       bool is_store); -void ReportStats(); -void ReportAtExitStatistics(); -void DescribeMemoryRange(const void *x, uptr size); -void ReportInvalidAccessInsideAddressRange(const char *what, const void *start, uptr size, -                                 uptr offset); -  // Returns a "chained" origin id, pointing to the given stack trace followed by  // the previous origin id.  u32 ChainOrigin(u32 id, StackTrace *stack); @@ -135,6 +116,15 @@ const int STACK_TRACE_TAG_POISON = StackTrace::TAG_CUSTOM + 1;    GetStackTrace(&stack, kStackTraceMax, pc, bp, nullptr, \                  common_flags()->fast_unwind_on_fatal) +#define GET_FATAL_STACK_TRACE_HERE \ +  GET_FATAL_STACK_TRACE_PC_BP(StackTrace::GetCurrentPc(), GET_CURRENT_FRAME()) + +#define PRINT_CURRENT_STACK_CHECK() \ +  {                                 \ +    GET_FATAL_STACK_TRACE_HERE;     \ +    stack.Print();                  \ +  } +  class ScopedThreadLocalStateBackup {   public:    ScopedThreadLocalStateBackup() { Backup(); } diff --git a/lib/hwasan/hwasan_allocator.cc b/lib/hwasan/hwasan_allocator.cc index fbcaf78b88f03..c2b9b0b695899 100644 --- a/lib/hwasan/hwasan_allocator.cc +++ b/lib/hwasan/hwasan_allocator.cc @@ -1,4 +1,4 @@ -//===-- hwasan_allocator.cc --------------------------- ---------------------===// +//===-- hwasan_allocator.cc ------------------------- ---------------------===//  //  //                     The LLVM Compiler Infrastructure  // @@ -15,11 +15,13 @@  #include "sanitizer_common/sanitizer_allocator.h"  #include "sanitizer_common/sanitizer_allocator_checks.h"  #include "sanitizer_common/sanitizer_allocator_interface.h" +#include "sanitizer_common/sanitizer_allocator_report.h"  #include "sanitizer_common/sanitizer_atomic.h"  #include "sanitizer_common/sanitizer_errno.h"  #include "sanitizer_common/sanitizer_stackdepot.h"  #include "hwasan.h"  #include "hwasan_allocator.h" +#include "hwasan_mapping.h"  #include "hwasan_thread.h"  #include "hwasan_poisoning.h" @@ -70,8 +72,8 @@ struct HwasanMapUnmapCallback {    }  }; -#if !defined(__aarch64__) -#error unsupported platform +#if !defined(__aarch64__) && !defined(__x86_64__) +#error Unsupported platform  #endif  static const uptr kMaxAllowedMallocSize = 2UL << 30;  // 2G @@ -100,6 +102,9 @@ static AllocatorCache fallback_allocator_cache;  static SpinMutex fallback_mutex;  static atomic_uint8_t hwasan_allocator_tagging_enabled; +static const tag_t kFallbackAllocTag = 0xBB; +static const tag_t kFallbackFreeTag = 0xBC; +  void HwasanAllocatorInit() {    atomic_store_relaxed(&hwasan_allocator_tagging_enabled,                         !flags()->disable_allocator_tagging); @@ -123,9 +128,12 @@ static void *HwasanAllocate(StackTrace *stack, uptr size, uptr alignment,    size = RoundUpTo(size, kShadowAlignment);    if (size > kMaxAllowedMallocSize) { -    Report("WARNING: HWAddressSanitizer failed to allocate %p bytes\n", -           (void *)size); -    return Allocator::FailureHandler::OnBadRequest(); +    if (AllocatorMayReturnNull()) { +      Report("WARNING: HWAddressSanitizer failed to allocate 0x%zx bytes\n", +             size); +      return nullptr; +    } +    ReportAllocationSizeTooBig(size, kMaxAllowedMallocSize, stack);    }    HwasanThread *t = GetCurrentThread();    void *allocated; @@ -137,6 +145,12 @@ static void *HwasanAllocate(StackTrace *stack, uptr size, uptr alignment,      AllocatorCache *cache = &fallback_allocator_cache;      allocated = allocator.Allocate(cache, size, alignment);    } +  if (UNLIKELY(!allocated)) { +    SetAllocatorOutOfMemory(); +    if (AllocatorMayReturnNull()) +      return nullptr; +    ReportOutOfMemory(size, stack); +  }    Metadata *meta =        reinterpret_cast<Metadata *>(allocator.GetMetaData(allocated));    meta->state = CHUNK_ALLOCATED; @@ -145,10 +159,11 @@ static void *HwasanAllocate(StackTrace *stack, uptr size, uptr alignment,    if (zeroise)      internal_memset(allocated, 0, size); -  void *user_ptr = (flags()->tag_in_malloc && -                    atomic_load_relaxed(&hwasan_allocator_tagging_enabled)) -                       ? (void *)TagMemoryAligned((uptr)allocated, size, 0xBB) -                       : allocated; +  void *user_ptr = allocated; +  if (flags()->tag_in_malloc && +      atomic_load_relaxed(&hwasan_allocator_tagging_enabled)) +    user_ptr = (void *)TagMemoryAligned( +        (uptr)user_ptr, size, t ? t->GenerateRandomTag() : kFallbackAllocTag);    HWASAN_MALLOC_HOOK(user_ptr, size);    return user_ptr; @@ -166,10 +181,11 @@ void HwasanDeallocate(StackTrace *stack, void *user_ptr) {    meta->free_context_id = StackDepotPut(*stack);    // This memory will not be reused by anyone else, so we are free to keep it    // poisoned. +  HwasanThread *t = GetCurrentThread();    if (flags()->tag_in_free &&        atomic_load_relaxed(&hwasan_allocator_tagging_enabled)) -    TagMemoryAligned((uptr)p, size, 0xBC); -  HwasanThread *t = GetCurrentThread(); +    TagMemoryAligned((uptr)p, size, +                     t ? t->GenerateRandomTag() : kFallbackFreeTag);    if (t) {      AllocatorCache *cache = GetAllocatorCache(&t->malloc_storage());      allocator.Deallocate(cache, p); @@ -195,8 +211,12 @@ void *HwasanReallocate(StackTrace *stack, void *user_old_p, uptr new_size,      meta->requested_size = new_size;      if (!atomic_load_relaxed(&hwasan_allocator_tagging_enabled))        return user_old_p; -    if (flags()->retag_in_realloc) -      return (void *)TagMemoryAligned((uptr)old_p, new_size, 0xCC); +    if (flags()->retag_in_realloc) { +      HwasanThread *t = GetCurrentThread(); +      return (void *)TagMemoryAligned( +          (uptr)old_p, new_size, +          t ? t->GenerateRandomTag() : kFallbackAllocTag); +    }      if (new_size > old_size) {        tag_t tag = GetTagFromPointer((uptr)user_old_p);        TagMemoryAligned((uptr)old_p + old_size, new_size - old_size, tag); @@ -212,6 +232,15 @@ void *HwasanReallocate(StackTrace *stack, void *user_old_p, uptr new_size,    return new_p;  } +void *HwasanCalloc(StackTrace *stack, uptr nmemb, uptr size) { +  if (UNLIKELY(CheckForCallocOverflow(size, nmemb))) { +    if (AllocatorMayReturnNull()) +      return nullptr; +    ReportCallocOverflow(nmemb, size, stack); +  } +  return HwasanAllocate(stack, nmemb * size, sizeof(u64), true); +} +  HwasanChunkView FindHeapChunkByAddress(uptr address) {    void *block = allocator.GetBlockBegin(reinterpret_cast<void*>(address));    if (!block) @@ -235,9 +264,7 @@ void *hwasan_malloc(uptr size, StackTrace *stack) {  }  void *hwasan_calloc(uptr nmemb, uptr size, StackTrace *stack) { -  if (UNLIKELY(CheckForCallocOverflow(size, nmemb))) -    return SetErrnoOnNull(Allocator::FailureHandler::OnBadRequest()); -  return SetErrnoOnNull(HwasanAllocate(stack, nmemb * size, sizeof(u64), true)); +  return SetErrnoOnNull(HwasanCalloc(stack, nmemb, size));  }  void *hwasan_realloc(void *ptr, uptr size, StackTrace *stack) { @@ -251,14 +278,17 @@ void *hwasan_realloc(void *ptr, uptr size, StackTrace *stack) {  }  void *hwasan_valloc(uptr size, StackTrace *stack) { -  return SetErrnoOnNull(HwasanAllocate(stack, size, GetPageSizeCached(), false)); +  return SetErrnoOnNull( +      HwasanAllocate(stack, size, GetPageSizeCached(), false));  }  void *hwasan_pvalloc(uptr size, StackTrace *stack) {    uptr PageSize = GetPageSizeCached();    if (UNLIKELY(CheckForPvallocOverflow(size, PageSize))) {      errno = errno_ENOMEM; -    return Allocator::FailureHandler::OnBadRequest(); +    if (AllocatorMayReturnNull()) +      return nullptr; +    ReportPvallocOverflow(size, stack);    }    // pvalloc(0) should allocate one page.    size = size ? RoundUpTo(size, PageSize) : PageSize; @@ -268,7 +298,9 @@ void *hwasan_pvalloc(uptr size, StackTrace *stack) {  void *hwasan_aligned_alloc(uptr alignment, uptr size, StackTrace *stack) {    if (UNLIKELY(!CheckAlignedAllocAlignmentAndSize(alignment, size))) {      errno = errno_EINVAL; -    return Allocator::FailureHandler::OnBadRequest(); +    if (AllocatorMayReturnNull()) +      return nullptr; +    ReportInvalidAlignedAllocAlignment(size, alignment, stack);    }    return SetErrnoOnNull(HwasanAllocate(stack, size, alignment, false));  } @@ -276,7 +308,9 @@ void *hwasan_aligned_alloc(uptr alignment, uptr size, StackTrace *stack) {  void *hwasan_memalign(uptr alignment, uptr size, StackTrace *stack) {    if (UNLIKELY(!IsPowerOfTwo(alignment))) {      errno = errno_EINVAL; -    return Allocator::FailureHandler::OnBadRequest(); +    if (AllocatorMayReturnNull()) +      return nullptr; +    ReportInvalidAllocationAlignment(alignment, stack);    }    return SetErrnoOnNull(HwasanAllocate(stack, size, alignment, false));  } @@ -284,18 +318,20 @@ void *hwasan_memalign(uptr alignment, uptr size, StackTrace *stack) {  int hwasan_posix_memalign(void **memptr, uptr alignment, uptr size,                          StackTrace *stack) {    if (UNLIKELY(!CheckPosixMemalignAlignment(alignment))) { -    Allocator::FailureHandler::OnBadRequest(); -    return errno_EINVAL; +    if (AllocatorMayReturnNull()) +      return errno_EINVAL; +    ReportInvalidPosixMemalignAlignment(alignment, stack);    }    void *ptr = HwasanAllocate(stack, size, alignment, false);    if (UNLIKELY(!ptr)) +    // OOM error is already taken care of by HwasanAllocate.      return errno_ENOMEM;    CHECK(IsAligned((uptr)ptr, alignment));    *memptr = ptr;    return 0;  } -} // namespace __hwasan +}  // namespace __hwasan  using namespace __hwasan; diff --git a/lib/hwasan/hwasan_dynamic_shadow.cc b/lib/hwasan/hwasan_dynamic_shadow.cc new file mode 100644 index 0000000000000..17338003aa652 --- /dev/null +++ b/lib/hwasan/hwasan_dynamic_shadow.cc @@ -0,0 +1,132 @@ +//===-- hwasan_dynamic_shadow.cc --------------------------------*- C++ -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file is a part of HWAddressSanitizer. It reserves dynamic shadow memory +/// region and handles ifunc resolver case, when necessary. +/// +//===----------------------------------------------------------------------===// + +#include "hwasan_dynamic_shadow.h" +#include "hwasan_mapping.h" +#include "sanitizer_common/sanitizer_common.h" +#include "sanitizer_common/sanitizer_posix.h" + +// The code in this file needs to run in an unrelocated binary. It should not +// access any external symbol, including its own non-hidden globals. + +namespace __hwasan { + +static void UnmapFromTo(uptr from, uptr to) { +  if (to == from) +    return; +  CHECK(to >= from); +  uptr res = internal_munmap(reinterpret_cast<void *>(from), to - from); +  if (UNLIKELY(internal_iserror(res))) { +    Report("ERROR: %s failed to unmap 0x%zx (%zd) bytes at address %p\n", +           SanitizerToolName, to - from, to - from, from); +    CHECK("unable to unmap" && 0); +  } +} + +// Returns an address aligned to 8 pages, such that one page on the left and +// shadow_size_bytes bytes on the right of it are mapped r/o. +static uptr MapDynamicShadow(uptr shadow_size_bytes) { +  const uptr granularity = GetMmapGranularity(); +  const uptr alignment = granularity * SHADOW_GRANULARITY; +  const uptr left_padding = granularity; +  const uptr shadow_size = +      RoundUpTo(shadow_size_bytes, granularity); +  const uptr map_size = shadow_size + left_padding + alignment; + +  const uptr map_start = (uptr)MmapNoAccess(map_size); +  CHECK_NE(map_start, ~(uptr)0); + +  const uptr shadow_start = RoundUpTo(map_start + left_padding, alignment); + +  UnmapFromTo(map_start, shadow_start - left_padding); +  UnmapFromTo(shadow_start + shadow_size, map_start + map_size); + +  return shadow_start; +} + +}  // namespace __hwasan + +#if HWASAN_PREMAP_SHADOW + +extern "C" { + +INTERFACE_ATTRIBUTE void __hwasan_shadow(); +decltype(__hwasan_shadow)* __hwasan_premap_shadow(); + +}  // extern "C" + +namespace __hwasan { + +// Conservative upper limit. +static uptr PremapShadowSize() { +  return RoundUpTo(GetMaxVirtualAddress() >> kShadowScale, +                   GetMmapGranularity()); +} + +static uptr PremapShadow() { +  return MapDynamicShadow(PremapShadowSize()); +} + +static bool IsPremapShadowAvailable() { +  const uptr shadow = reinterpret_cast<uptr>(&__hwasan_shadow); +  const uptr resolver = reinterpret_cast<uptr>(&__hwasan_premap_shadow); +  // shadow == resolver is how Android KitKat and older handles ifunc. +  // shadow == 0 just in case. +  return shadow != 0 && shadow != resolver; +} + +static uptr FindPremappedShadowStart(uptr shadow_size_bytes) { +  const uptr granularity = GetMmapGranularity(); +  const uptr shadow_start = reinterpret_cast<uptr>(&__hwasan_shadow); +  const uptr premap_shadow_size = PremapShadowSize(); +  const uptr shadow_size = RoundUpTo(shadow_size_bytes, granularity); + +  // We may have mapped too much. Release extra memory. +  UnmapFromTo(shadow_start + shadow_size, shadow_start + premap_shadow_size); +  return shadow_start; +} + +}  // namespace __hwasan + +extern "C" { + +decltype(__hwasan_shadow)* __hwasan_premap_shadow() { +  // The resolver might be called multiple times. Map the shadow just once. +  static __sanitizer::uptr shadow = 0; +  if (!shadow) +    shadow = __hwasan::PremapShadow(); +  return reinterpret_cast<decltype(__hwasan_shadow)*>(shadow); +} + +// __hwasan_shadow is a "function" that has the same address as the first byte +// of the shadow mapping. +INTERFACE_ATTRIBUTE __attribute__((ifunc("__hwasan_premap_shadow"))) +void __hwasan_shadow(); + +}  // extern "C" + +#endif  // HWASAN_PREMAP_SHADOW + +namespace __hwasan { + +uptr FindDynamicShadowStart(uptr shadow_size_bytes) { +#if HWASAN_PREMAP_SHADOW +  if (IsPremapShadowAvailable()) +    return FindPremappedShadowStart(shadow_size_bytes); +#endif +  return MapDynamicShadow(shadow_size_bytes); +} + +}  // namespace __hwasan diff --git a/lib/hwasan/hwasan_dynamic_shadow.h b/lib/hwasan/hwasan_dynamic_shadow.h new file mode 100644 index 0000000000000..b5e9e1dd6a067 --- /dev/null +++ b/lib/hwasan/hwasan_dynamic_shadow.h @@ -0,0 +1,27 @@ +//===-- hwasan_dynamic_shadow.h ---------------------------------*- C++ -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file is a part of HWAddressSanitizer. It reserves dynamic shadow memory +/// region. +/// +//===----------------------------------------------------------------------===// + +#ifndef HWASAN_PREMAP_SHADOW_H +#define HWASAN_PREMAP_SHADOW_H + +#include "sanitizer_common/sanitizer_internal_defs.h" + +namespace __hwasan { + +uptr FindDynamicShadowStart(uptr shadow_size_bytes); + +}  // namespace __hwasan + +#endif  // HWASAN_PREMAP_SHADOW_H diff --git a/lib/hwasan/hwasan_flags.inc b/lib/hwasan/hwasan_flags.inc index a2cb701ae93d3..c45781168d6c8 100644 --- a/lib/hwasan/hwasan_flags.inc +++ b/lib/hwasan/hwasan_flags.inc @@ -27,3 +27,7 @@ HWASAN_FLAG(bool, atexit, false, "")  // Test only flag to disable malloc/realloc/free memory tagging on startup.  // Tagging can be reenabled with __hwasan_enable_allocator_tagging().  HWASAN_FLAG(bool, disable_allocator_tagging, false, "") + +// If false, use simple increment of a thread local counter to generate new +// tags. +HWASAN_FLAG(bool, random_tags, true, "") diff --git a/lib/hwasan/hwasan_interceptors.cc b/lib/hwasan/hwasan_interceptors.cc index fb39e9fdacf9e..66aab95db56f7 100644 --- a/lib/hwasan/hwasan_interceptors.cc +++ b/lib/hwasan/hwasan_interceptors.cc @@ -17,8 +17,10 @@  #include "interception/interception.h"  #include "hwasan.h" +#include "hwasan_mapping.h"  #include "hwasan_thread.h"  #include "hwasan_poisoning.h" +#include "hwasan_report.h"  #include "sanitizer_common/sanitizer_platform_limits_posix.h"  #include "sanitizer_common/sanitizer_allocator.h"  #include "sanitizer_common/sanitizer_allocator_interface.h" @@ -258,34 +260,17 @@ INTERCEPTOR(void *, realloc, void *ptr, SIZE_T size) {  INTERCEPTOR(void *, malloc, SIZE_T size) {    GET_MALLOC_STACK_TRACE; +  if (UNLIKELY(!hwasan_init_is_running)) +    ENSURE_HWASAN_INITED();    if (UNLIKELY(!hwasan_inited))      // Hack: dlsym calls malloc before REAL(malloc) is retrieved from dlsym.      return AllocateFromLocalPool(size);    return hwasan_malloc(size, &stack);  } - -INTERCEPTOR(void *, mmap, void *addr, SIZE_T length, int prot, int flags, -            int fd, OFF_T offset) { -  if (hwasan_init_is_running) -    return REAL(mmap)(addr, length, prot, flags, fd, offset); -  ENSURE_HWASAN_INITED(); -  if (addr && !MEM_IS_APP(addr)) { -    if (flags & map_fixed) { -      errno = errno_EINVAL; -      return (void *)-1; -    } else { -      addr = nullptr; -    } -  } -  void *res = REAL(mmap)(addr, length, prot, flags, fd, offset); -  return res; -} - -#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD -INTERCEPTOR(void *, mmap64, void *addr, SIZE_T length, int prot, int flags, -            int fd, OFF64_T offset) { -  ENSURE_HWASAN_INITED(); +template <class Mmap> +static void *mmap_interceptor(Mmap real_mmap, void *addr, SIZE_T sz, int prot, +                              int flags, int fd, OFF64_T off) {    if (addr && !MEM_IS_APP(addr)) {      if (flags & map_fixed) {        errno = errno_EINVAL; @@ -294,13 +279,8 @@ INTERCEPTOR(void *, mmap64, void *addr, SIZE_T length, int prot, int flags,        addr = nullptr;      }    } -  void *res = REAL(mmap64)(addr, length, prot, flags, fd, offset); -  return res; +  return real_mmap(addr, sz, prot, flags, fd, off);  } -#define HWASAN_MAYBE_INTERCEPT_MMAP64 INTERCEPT_FUNCTION(mmap64) -#else -#define HWASAN_MAYBE_INTERCEPT_MMAP64 -#endif  extern "C" int pthread_attr_init(void *attr);  extern "C" int pthread_attr_destroy(void *attr); @@ -427,6 +407,22 @@ int OnExit() {      *begin = *end = 0;                                                         \    } +#define COMMON_INTERCEPTOR_MEMSET_IMPL(ctx, dst, v, size) \ +  {                                                       \ +    COMMON_INTERCEPTOR_ENTER(ctx, memset, dst, v, size);  \ +    if (common_flags()->intercept_intrin &&               \ +        MEM_IS_APP(GetAddressFromPointer(dst)))           \ +      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, size);     \ +    return REAL(memset)(dst, v, size);                    \ +  } + +#define COMMON_INTERCEPTOR_MMAP_IMPL(ctx, mmap, addr, length, prot, flags, fd, \ +                                     offset)                                   \ +  do {                                                                         \ +    return mmap_interceptor(REAL(mmap), addr, length, prot, flags, fd,         \ +                            offset);                                           \ +  } while (false) +  #include "sanitizer_common/sanitizer_platform_interceptors.h"  #include "sanitizer_common/sanitizer_common_interceptors.inc"  #include "sanitizer_common/sanitizer_signal_interceptors.inc" @@ -448,6 +444,7 @@ int OnExit() {      (void)(s);                                \    } while (false)  #include "sanitizer_common/sanitizer_common_syscalls.inc" +#include "sanitizer_common/sanitizer_syscalls_netbsd.inc" @@ -459,8 +456,6 @@ void InitializeInterceptors() {    InitializeCommonInterceptors();    InitializeSignalInterceptors(); -  INTERCEPT_FUNCTION(mmap); -  HWASAN_MAYBE_INTERCEPT_MMAP64;    INTERCEPT_FUNCTION(posix_memalign);    HWASAN_MAYBE_INTERCEPT_MEMALIGN;    INTERCEPT_FUNCTION(__libc_memalign); diff --git a/lib/hwasan/hwasan_interface_internal.h b/lib/hwasan/hwasan_interface_internal.h index 7e95271ac0af7..b4e5c80904df3 100644 --- a/lib/hwasan/hwasan_interface_internal.h +++ b/lib/hwasan/hwasan_interface_internal.h @@ -18,6 +18,7 @@  #include "sanitizer_common/sanitizer_internal_defs.h"  extern "C" { +  SANITIZER_INTERFACE_ATTRIBUTE  void __hwasan_init(); @@ -32,7 +33,10 @@ using __sanitizer::u16;  using __sanitizer::u8;  SANITIZER_INTERFACE_ATTRIBUTE -void __hwasan_load(uptr, uptr); +extern uptr __hwasan_shadow_memory_dynamic_address; + +SANITIZER_INTERFACE_ATTRIBUTE +void __hwasan_loadN(uptr, uptr);  SANITIZER_INTERFACE_ATTRIBUTE  void __hwasan_load1(uptr);  SANITIZER_INTERFACE_ATTRIBUTE @@ -45,7 +49,7 @@ SANITIZER_INTERFACE_ATTRIBUTE  void __hwasan_load16(uptr);  SANITIZER_INTERFACE_ATTRIBUTE -void __hwasan_load_noabort(uptr, uptr); +void __hwasan_loadN_noabort(uptr, uptr);  SANITIZER_INTERFACE_ATTRIBUTE  void __hwasan_load1_noabort(uptr);  SANITIZER_INTERFACE_ATTRIBUTE @@ -58,7 +62,7 @@ SANITIZER_INTERFACE_ATTRIBUTE  void __hwasan_load16_noabort(uptr);  SANITIZER_INTERFACE_ATTRIBUTE -void __hwasan_store(uptr, uptr); +void __hwasan_storeN(uptr, uptr);  SANITIZER_INTERFACE_ATTRIBUTE  void __hwasan_store1(uptr);  SANITIZER_INTERFACE_ATTRIBUTE @@ -71,7 +75,7 @@ SANITIZER_INTERFACE_ATTRIBUTE  void __hwasan_store16(uptr);  SANITIZER_INTERFACE_ATTRIBUTE -void __hwasan_store_noabort(uptr, uptr); +void __hwasan_storeN_noabort(uptr, uptr);  SANITIZER_INTERFACE_ATTRIBUTE  void __hwasan_store1_noabort(uptr);  SANITIZER_INTERFACE_ATTRIBUTE @@ -83,6 +87,12 @@ void __hwasan_store8_noabort(uptr);  SANITIZER_INTERFACE_ATTRIBUTE  void __hwasan_store16_noabort(uptr); +SANITIZER_INTERFACE_ATTRIBUTE +void __hwasan_tag_memory(uptr p, u8 tag, uptr sz); + +SANITIZER_INTERFACE_ATTRIBUTE +u8 __hwasan_generate_tag(); +  // Returns the offset of the first tag mismatch or -1 if the whole range is  // good.  SANITIZER_INTERFACE_ATTRIBUTE diff --git a/lib/hwasan/hwasan_linux.cc b/lib/hwasan/hwasan_linux.cc index 48dea8eb6ff46..5ab98dca594d8 100644 --- a/lib/hwasan/hwasan_linux.cc +++ b/lib/hwasan/hwasan_linux.cc @@ -1,4 +1,4 @@ -//===-- hwasan_linux.cc -----------------------------------------------------===// +//===-- hwasan_linux.cc -----------------------------------------*- C++ -*-===//  //  //                     The LLVM Compiler Infrastructure  // @@ -6,41 +6,45 @@  // License. See LICENSE.TXT for details.  //  //===----------------------------------------------------------------------===// -// -// This file is a part of HWAddressSanitizer. -// -// Linux-, NetBSD- and FreeBSD-specific code. +/// +/// \file +/// This file is a part of HWAddressSanitizer and contains Linux-, NetBSD- and +/// FreeBSD-specific code. +///  //===----------------------------------------------------------------------===//  #include "sanitizer_common/sanitizer_platform.h"  #if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD  #include "hwasan.h" +#include "hwasan_dynamic_shadow.h" +#include "hwasan_interface_internal.h" +#include "hwasan_mapping.h" +#include "hwasan_report.h"  #include "hwasan_thread.h"  #include <elf.h>  #include <link.h>  #include <pthread.h> +#include <signal.h>  #include <stdio.h>  #include <stdlib.h> -#include <signal.h> +#include <sys/resource.h> +#include <sys/time.h>  #include <unistd.h>  #include <unwind.h> -#include <sys/time.h> -#include <sys/resource.h>  #include "sanitizer_common/sanitizer_common.h"  #include "sanitizer_common/sanitizer_procmaps.h"  namespace __hwasan { -void ReserveShadowMemoryRange(uptr beg, uptr end, const char *name) { +static void ReserveShadowMemoryRange(uptr beg, uptr end, const char *name) {    CHECK_EQ((beg % GetMmapGranularity()), 0);    CHECK_EQ(((end + 1) % GetMmapGranularity()), 0);    uptr size = end - beg + 1;    DecreaseTotalMmap(size);  // Don't count the shadow against mmap_limit_mb. -  void *res = MmapFixedNoReserve(beg, size, name); -  if (res != (void *)beg) { +  if (!MmapFixedNoReserve(beg, size, name)) {      Report(          "ReserveShadowMemoryRange failed while trying to map 0x%zx bytes. "          "Perhaps you're using ulimit -v\n", @@ -52,8 +56,11 @@ void ReserveShadowMemoryRange(uptr beg, uptr end, const char *name) {  }  static void ProtectGap(uptr addr, uptr size) { +  if (!size) +    return;    void *res = MmapFixedNoAccess(addr, size, "shadow gap"); -  if (addr == (uptr)res) return; +  if (addr == (uptr)res) +    return;    // A few pages at the start of the address space can not be protected.    // But we really want to protect as much as possible, to prevent this memory    // being returned as a result of a non-FIXED mmap(). @@ -63,63 +70,160 @@ static void ProtectGap(uptr addr, uptr size) {        addr += step;        size -= step;        void *res = MmapFixedNoAccess(addr, size, "shadow gap"); -      if (addr == (uptr)res) return; +      if (addr == (uptr)res) +        return;      }    }    Report( -      "ERROR: Failed to protect the shadow gap. " -      "ASan cannot proceed correctly. ABORTING.\n"); +      "ERROR: Failed to protect shadow gap [%p, %p]. " +      "HWASan cannot proceed correctly. ABORTING.\n", (void *)addr, +      (void *)(addr + size));    DumpProcessMap();    Die();  } -bool InitShadow() { -  const uptr maxVirtualAddress = GetMaxUserVirtualAddress(); +static uptr kLowMemStart; +static uptr kLowMemEnd; +static uptr kLowShadowEnd; +static uptr kLowShadowStart; +static uptr kHighShadowStart; +static uptr kHighShadowEnd; +static uptr kHighMemStart; +static uptr kHighMemEnd; + +static void PrintRange(uptr start, uptr end, const char *name) { +  Printf("|| [%p, %p] || %.*s ||\n", (void *)start, (void *)end, 10, name); +} -  // LowMem covers as much of the first 4GB as possible. -  const uptr kLowMemEnd = 1UL<<32; -  const uptr kLowShadowEnd = kLowMemEnd >> kShadowScale; -  const uptr kLowShadowStart = kLowShadowEnd >> kShadowScale; +static void PrintAddressSpaceLayout() { +  PrintRange(kHighMemStart, kHighMemEnd, "HighMem"); +  if (kHighShadowEnd + 1 < kHighMemStart) +    PrintRange(kHighShadowEnd + 1, kHighMemStart - 1, "ShadowGap"); +  else +    CHECK_EQ(kHighShadowEnd + 1, kHighMemStart); +  PrintRange(kHighShadowStart, kHighShadowEnd, "HighShadow"); +  if (SHADOW_OFFSET) { +    if (kLowShadowEnd + 1 < kHighShadowStart) +      PrintRange(kLowShadowEnd + 1, kHighShadowStart - 1, "ShadowGap"); +    else +      CHECK_EQ(kLowMemEnd + 1, kHighShadowStart); +    PrintRange(kLowShadowStart, kLowShadowEnd, "LowShadow"); +    if (kLowMemEnd + 1 < kLowShadowStart) +      PrintRange(kLowMemEnd + 1, kLowShadowStart - 1, "ShadowGap"); +    else +      CHECK_EQ(kLowMemEnd + 1, kLowShadowStart); +    PrintRange(kLowMemStart, kLowMemEnd, "LowMem"); +    CHECK_EQ(0, kLowMemStart); +  } else { +    if (kLowMemEnd + 1 < kHighShadowStart) +      PrintRange(kLowMemEnd + 1, kHighShadowStart - 1, "ShadowGap"); +    else +      CHECK_EQ(kLowMemEnd + 1, kHighShadowStart); +    PrintRange(kLowMemStart, kLowMemEnd, "LowMem"); +    CHECK_EQ(kLowShadowEnd + 1, kLowMemStart); +    PrintRange(kLowShadowStart, kLowShadowEnd, "LowShadow"); +    PrintRange(0, kLowShadowStart - 1, "ShadowGap"); +  } +} +static uptr GetHighMemEnd() {    // HighMem covers the upper part of the address space. -  const uptr kHighShadowEnd = (maxVirtualAddress >> kShadowScale) + 1; -  const uptr kHighShadowStart = Max(kLowMemEnd, kHighShadowEnd >> kShadowScale); -  CHECK(kHighShadowStart < kHighShadowEnd); - -  const uptr kHighMemStart = kHighShadowStart << kShadowScale; -  CHECK(kHighShadowEnd <= kHighMemStart); - -  if (Verbosity()) { -    Printf("|| `[%p, %p]` || HighMem    ||\n", (void *)kHighMemStart, -           (void *)maxVirtualAddress); -    if (kHighMemStart > kHighShadowEnd) -      Printf("|| `[%p, %p]` || ShadowGap2 ||\n", (void *)kHighShadowEnd, -             (void *)kHighMemStart); -    Printf("|| `[%p, %p]` || HighShadow ||\n", (void *)kHighShadowStart, -           (void *)kHighShadowEnd); -    if (kHighShadowStart > kLowMemEnd) -      Printf("|| `[%p, %p]` || ShadowGap2 ||\n", (void *)kHighShadowEnd, -             (void *)kHighMemStart); -    Printf("|| `[%p, %p]` || LowMem     ||\n", (void *)kLowShadowEnd, -           (void *)kLowMemEnd); -    Printf("|| `[%p, %p]` || LowShadow  ||\n", (void *)kLowShadowStart, -           (void *)kLowShadowEnd); -    Printf("|| `[%p, %p]` || ShadowGap1 ||\n", (void *)0, -           (void *)kLowShadowStart); +  uptr max_address = GetMaxUserVirtualAddress(); +  if (SHADOW_OFFSET) +    // Adjust max address to make sure that kHighMemEnd and kHighMemStart are +    // properly aligned: +    max_address |= SHADOW_GRANULARITY * GetMmapGranularity() - 1; +  return max_address; +} + +static void InitializeShadowBaseAddress(uptr shadow_size_bytes) { +  // Set the shadow memory address to uninitialized. +  __hwasan_shadow_memory_dynamic_address = kDefaultShadowSentinel; +  uptr shadow_start = SHADOW_OFFSET; +  // Detect if a dynamic shadow address must be used and find the available +  // location when necessary. When dynamic address is used, the macro +  // kLowShadowBeg expands to __hwasan_shadow_memory_dynamic_address which +  // was just set to kDefaultShadowSentinel. +  if (shadow_start == kDefaultShadowSentinel) { +    __hwasan_shadow_memory_dynamic_address = 0; +    CHECK_EQ(0, SHADOW_OFFSET); +    shadow_start = FindDynamicShadowStart(shadow_size_bytes);    } +  // Update the shadow memory address (potentially) used by instrumentation. +  __hwasan_shadow_memory_dynamic_address = shadow_start; +} -  ReserveShadowMemoryRange(kLowShadowStart, kLowShadowEnd - 1, "low shadow"); -  ReserveShadowMemoryRange(kHighShadowStart, kHighShadowEnd - 1, "high shadow"); -  ProtectGap(0, kLowShadowStart); -  if (kHighShadowStart > kLowMemEnd) -    ProtectGap(kLowMemEnd, kHighShadowStart - kLowMemEnd); -  if (kHighMemStart > kHighShadowEnd) -    ProtectGap(kHighShadowEnd, kHighMemStart - kHighShadowEnd); +bool InitShadow() { +  // Define the entire memory range. +  kHighMemEnd = GetHighMemEnd(); + +  // Determine shadow memory base offset. +  InitializeShadowBaseAddress(MEM_TO_SHADOW_SIZE(kHighMemEnd)); + +  // Place the low memory first. +  if (SHADOW_OFFSET) { +    kLowMemEnd = SHADOW_OFFSET - 1; +    kLowMemStart = 0; +  } else { +    // LowMem covers as much of the first 4GB as possible. +    kLowMemEnd = (1UL << 32) - 1; +    kLowMemStart = MEM_TO_SHADOW(kLowMemEnd) + 1; +  } + +  // Define the low shadow based on the already placed low memory. +  kLowShadowEnd = MEM_TO_SHADOW(kLowMemEnd); +  kLowShadowStart = SHADOW_OFFSET ? SHADOW_OFFSET : MEM_TO_SHADOW(kLowMemStart); + +  // High shadow takes whatever memory is left up there (making sure it is not +  // interfering with low memory in the fixed case). +  kHighShadowEnd = MEM_TO_SHADOW(kHighMemEnd); +  kHighShadowStart = Max(kLowMemEnd, MEM_TO_SHADOW(kHighShadowEnd)) + 1; + +  // High memory starts where allocated shadow allows. +  kHighMemStart = SHADOW_TO_MEM(kHighShadowStart); + +  // Check the sanity of the defined memory ranges (there might be gaps). +  CHECK_EQ(kHighMemStart % GetMmapGranularity(), 0); +  CHECK_GT(kHighMemStart, kHighShadowEnd); +  CHECK_GT(kHighShadowEnd, kHighShadowStart); +  CHECK_GT(kHighShadowStart, kLowMemEnd); +  CHECK_GT(kLowMemEnd, kLowMemStart); +  CHECK_GT(kLowShadowEnd, kLowShadowStart); +  if (SHADOW_OFFSET) +    CHECK_GT(kLowShadowStart, kLowMemEnd); +  else +    CHECK_GT(kLowMemEnd, kLowShadowStart); + +  if (Verbosity()) +    PrintAddressSpaceLayout(); + +  // Reserve shadow memory. +  ReserveShadowMemoryRange(kLowShadowStart, kLowShadowEnd, "low shadow"); +  ReserveShadowMemoryRange(kHighShadowStart, kHighShadowEnd, "high shadow"); + +  // Protect all the gaps. +  ProtectGap(0, Min(kLowMemStart, kLowShadowStart)); +  if (SHADOW_OFFSET) { +    if (kLowMemEnd + 1 < kLowShadowStart) +      ProtectGap(kLowMemEnd + 1, kLowShadowStart - kLowMemEnd - 1); +    if (kLowShadowEnd + 1 < kHighShadowStart) +      ProtectGap(kLowShadowEnd + 1, kHighShadowStart - kLowShadowEnd - 1); +  } else { +    if (kLowMemEnd + 1 < kHighShadowStart) +      ProtectGap(kLowMemEnd + 1, kHighShadowStart - kLowMemEnd - 1); +  } +  if (kHighShadowEnd + 1 < kHighMemStart) +    ProtectGap(kHighShadowEnd + 1, kHighMemStart - kHighShadowEnd - 1);    return true;  } +bool MemIsApp(uptr p) { +  CHECK(GetTagFromPointer(p) == 0); +  return p >= kHighMemStart || (p >= kLowMemStart && p <= kLowMemEnd); +} +  static void HwasanAtExit(void) {    if (flags()->print_stats && (flags()->atexit || hwasan_report_count > 0))      ReportStats(); @@ -177,50 +281,65 @@ struct AccessInfo {    bool recover;  }; -#if defined(__aarch64__)  static AccessInfo GetAccessInfo(siginfo_t *info, ucontext_t *uc) { -  // Access type is encoded in HLT immediate as 0x1XY, -  // where X&1 is 1 for store, 0 for load, -  // and X&2 is 1 if the error is recoverable. -  // Valid values of Y are 0 to 4, which are interpreted as log2(access_size), -  // and 0xF, which means that access size is stored in X1 register. -  // Access address is always in X0 register. -  AccessInfo ai; +  // Access type is passed in a platform dependent way (see below) and encoded +  // as 0xXY, where X&1 is 1 for store, 0 for load, and X&2 is 1 if the error is +  // recoverable. Valid values of Y are 0 to 4, which are interpreted as +  // log2(access_size), and 0xF, which means that access size is passed via +  // platform dependent register (see below). +#if defined(__aarch64__) +  // Access type is encoded in BRK immediate as 0x900 + 0xXY. For Y == 0xF, +  // access size is stored in X1 register. Access address is always in X0 +  // register.    uptr pc = (uptr)info->si_addr; -  unsigned code = ((*(u32 *)pc) >> 5) & 0xffff; -  if ((code & 0xff00) != 0x100) -    return AccessInfo{0, 0, false, false}; // Not ours. -  bool is_store = code & 0x10; -  bool recover = code & 0x20; -  unsigned size_log = code & 0xf; +  const unsigned code = ((*(u32 *)pc) >> 5) & 0xffff; +  if ((code & 0xff00) != 0x900) +    return AccessInfo{}; // Not ours. + +  const bool is_store = code & 0x10; +  const bool recover = code & 0x20; +  const uptr addr = uc->uc_mcontext.regs[0]; +  const unsigned size_log = code & 0xf; +  if (size_log > 4 && size_log != 0xf) +    return AccessInfo{}; // Not ours. +  const uptr size = size_log == 0xf ? uc->uc_mcontext.regs[1] : 1U << size_log; + +#elif defined(__x86_64__) +  // Access type is encoded in the instruction following INT3 as +  // NOP DWORD ptr [EAX + 0x40 + 0xXY]. For Y == 0xF, access size is stored in +  // RSI register. Access address is always in RDI register. +  uptr pc = (uptr)uc->uc_mcontext.gregs[REG_RIP]; +  uint8_t *nop = (uint8_t*)pc; +  if (*nop != 0x0f || *(nop + 1) != 0x1f || *(nop + 2) != 0x40  || +      *(nop + 3) < 0x40) +    return AccessInfo{}; // Not ours. +  const unsigned code = *(nop + 3); + +  const bool is_store = code & 0x10; +  const bool recover = code & 0x20; +  const uptr addr = uc->uc_mcontext.gregs[REG_RDI]; +  const unsigned size_log = code & 0xf;    if (size_log > 4 && size_log != 0xf) -    return AccessInfo{0, 0, false, false}; // Not ours. +    return AccessInfo{}; // Not ours. +  const uptr size = +      size_log == 0xf ? uc->uc_mcontext.gregs[REG_RSI] : 1U << size_log; -  ai.is_store = is_store; -  ai.is_load = !is_store; -  ai.addr = uc->uc_mcontext.regs[0]; -  if (size_log == 0xf) -    ai.size = uc->uc_mcontext.regs[1]; -  else -    ai.size = 1U << size_log; -  ai.recover = recover; -  return ai; -}  #else -static AccessInfo GetAccessInfo(siginfo_t *info, ucontext_t *uc) { -  return AccessInfo{0, 0, false, false}; -} +# error Unsupported architecture  #endif -static bool HwasanOnSIGILL(int signo, siginfo_t *info, ucontext_t *uc) { -  SignalContext sig{info, uc}; +  return AccessInfo{addr, size, is_store, !is_store, recover}; +} + +static bool HwasanOnSIGTRAP(int signo, siginfo_t *info, ucontext_t *uc) {    AccessInfo ai = GetAccessInfo(info, uc);    if (!ai.is_store && !ai.is_load)      return false; -  InternalScopedBuffer<BufferedStackTrace> stack_buffer(1); +  InternalMmapVector<BufferedStackTrace> stack_buffer(1);    BufferedStackTrace *stack = stack_buffer.data();    stack->Reset(); +  SignalContext sig{info, uc};    GetStackTrace(stack, kStackTraceMax, sig.pc, sig.bp, uc,                  common_flags()->fast_unwind_on_fatal); @@ -230,7 +349,12 @@ static bool HwasanOnSIGILL(int signo, siginfo_t *info, ucontext_t *uc) {    if (flags()->halt_on_error || !ai.recover)      Die(); +#if defined(__aarch64__)    uc->uc_mcontext.pc += 4; +#elif defined(__x86_64__) +#else +# error Unsupported architecture +#endif    return true;  } @@ -242,8 +366,8 @@ static void OnStackUnwind(const SignalContext &sig, const void *,  void HwasanOnDeadlySignal(int signo, void *info, void *context) {    // Probably a tag mismatch. -  if (signo == SIGILL) -    if (HwasanOnSIGILL(signo, (siginfo_t *)info, (ucontext_t*)context)) +  if (signo == SIGTRAP) +    if (HwasanOnSIGTRAP(signo, (siginfo_t *)info, (ucontext_t*)context))        return;    HandleDeadlySignal(info, context, GetTid(), &OnStackUnwind, nullptr); diff --git a/lib/hwasan/hwasan_mapping.h b/lib/hwasan/hwasan_mapping.h new file mode 100644 index 0000000000000..650a5aefcb2d4 --- /dev/null +++ b/lib/hwasan/hwasan_mapping.h @@ -0,0 +1,85 @@ +//===-- hwasan_mapping.h ----------------------------------------*- C++ -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file is a part of HWAddressSanitizer and defines memory mapping. +/// +//===----------------------------------------------------------------------===// + +#ifndef HWASAN_MAPPING_H +#define HWASAN_MAPPING_H + +#include "sanitizer_common/sanitizer_internal_defs.h" + +// Typical mapping on Linux/x86_64 with fixed shadow mapping: +// || [0x080000000000, 0x7fffffffffff] || HighMem    || +// || [0x008000000000, 0x07ffffffffff] || HighShadow || +// || [0x000100000000, 0x007fffffffff] || ShadowGap  || +// || [0x000010000000, 0x0000ffffffff] || LowMem     || +// || [0x000001000000, 0x00000fffffff] || LowShadow  || +// || [0x000000000000, 0x000000ffffff] || ShadowGap  || +// +// and with dynamic shadow mapped at [0x770d59f40000, 0x7f0d59f40000]: +// || [0x7f0d59f40000, 0x7fffffffffff] || HighMem    || +// || [0x7efe2f934000, 0x7f0d59f3ffff] || HighShadow || +// || [0x7e7e2f934000, 0x7efe2f933fff] || ShadowGap  || +// || [0x770d59f40000, 0x7e7e2f933fff] || LowShadow  || +// || [0x000000000000, 0x770d59f3ffff] || LowMem     || + +// Typical mapping on Android/AArch64 (39-bit VMA): +// || [0x001000000000, 0x007fffffffff] || HighMem    || +// || [0x000800000000, 0x000fffffffff] || ShadowGap  || +// || [0x000100000000, 0x0007ffffffff] || HighShadow || +// || [0x000010000000, 0x0000ffffffff] || LowMem     || +// || [0x000001000000, 0x00000fffffff] || LowShadow  || +// || [0x000000000000, 0x000000ffffff] || ShadowGap  || +// +// and with dynamic shadow mapped: [0x007477480000, 0x007c77480000]: +// || [0x007c77480000, 0x007fffffffff] || HighMem    || +// || [0x007c3ebc8000, 0x007c7747ffff] || HighShadow || +// || [0x007bbebc8000, 0x007c3ebc7fff] || ShadowGap  || +// || [0x007477480000, 0x007bbebc7fff] || LowShadow  || +// || [0x000000000000, 0x00747747ffff] || LowMem     || + +static constexpr __sanitizer::u64 kDefaultShadowSentinel = ~(__sanitizer::u64)0; + +// Reasonable values are 4 (for 1/16th shadow) and 6 (for 1/64th). +constexpr __sanitizer::uptr kShadowScale = 4; +constexpr __sanitizer::uptr kShadowAlignment = 1ULL << kShadowScale; + +#if SANITIZER_ANDROID +# define HWASAN_FIXED_MAPPING 0 +#else +# define HWASAN_FIXED_MAPPING 1 +#endif + +#if HWASAN_FIXED_MAPPING +# define SHADOW_OFFSET (0) +# define HWASAN_PREMAP_SHADOW 0 +#else +# define SHADOW_OFFSET (__hwasan_shadow_memory_dynamic_address) +# define HWASAN_PREMAP_SHADOW 1 +#endif + +#define SHADOW_GRANULARITY (1ULL << kShadowScale) + +#define MEM_TO_SHADOW(mem) (((uptr)(mem) >> kShadowScale) + SHADOW_OFFSET) +#define SHADOW_TO_MEM(shadow) (((uptr)(shadow) - SHADOW_OFFSET) << kShadowScale) + +#define MEM_TO_SHADOW_SIZE(size) ((uptr)(size) >> kShadowScale) + +#define MEM_IS_APP(mem) MemIsApp((uptr)(mem)) + +namespace __hwasan { + +bool MemIsApp(uptr p); + +}  // namespace __hwasan + +#endif  // HWASAN_MAPPING_H diff --git a/lib/hwasan/hwasan_new_delete.cc b/lib/hwasan/hwasan_new_delete.cc index 3ccc26734bf66..63ca74edd481c 100644 --- a/lib/hwasan/hwasan_new_delete.cc +++ b/lib/hwasan/hwasan_new_delete.cc @@ -1,4 +1,4 @@ -//===-- hwasan_new_delete.cc ------------------------------------------------===// +//===-- hwasan_new_delete.cc ----------------------------------------------===//  //  //                     The LLVM Compiler Infrastructure  // @@ -15,6 +15,7 @@  #include "hwasan.h"  #include "interception/interception.h"  #include "sanitizer_common/sanitizer_allocator.h" +#include "sanitizer_common/sanitizer_allocator_report.h"  #if HWASAN_REPLACE_OPERATORS_NEW_AND_DELETE @@ -32,7 +33,7 @@ namespace std {  #define OPERATOR_NEW_BODY(nothrow) \    GET_MALLOC_STACK_TRACE; \    void *res = hwasan_malloc(size, &stack);\ -  if (!nothrow && UNLIKELY(!res)) DieOnFailure::OnOOM();\ +  if (!nothrow && UNLIKELY(!res)) ReportOutOfMemory(size, &stack);\    return res  INTERCEPTOR_ATTRIBUTE diff --git a/lib/hwasan/hwasan_poisoning.cc b/lib/hwasan/hwasan_poisoning.cc index 411fd05b10d56..b99d8ed0be792 100644 --- a/lib/hwasan/hwasan_poisoning.cc +++ b/lib/hwasan/hwasan_poisoning.cc @@ -13,6 +13,7 @@  #include "hwasan_poisoning.h" +#include "hwasan_mapping.h"  #include "interception/interception.h"  #include "sanitizer_common/sanitizer_common.h" @@ -22,7 +23,7 @@ uptr TagMemoryAligned(uptr p, uptr size, tag_t tag) {    CHECK(IsAligned(p, kShadowAlignment));    CHECK(IsAligned(size, kShadowAlignment));    uptr shadow_start = MEM_TO_SHADOW(p); -  uptr shadow_size = MEM_TO_SHADOW_OFFSET(size); +  uptr shadow_size = MEM_TO_SHADOW_SIZE(size);    internal_memset((void *)shadow_start, tag, shadow_size);    return AddTagToPointer(p, tag);  } diff --git a/lib/hwasan/hwasan_report.cc b/lib/hwasan/hwasan_report.cc index a3c6709491d3e..16e9016ea35b3 100644 --- a/lib/hwasan/hwasan_report.cc +++ b/lib/hwasan/hwasan_report.cc @@ -1,4 +1,4 @@ -//===-- hwasan_report.cc ----------------------------------------------------===// +//===-- hwasan_report.cc --------------------------------------------------===//  //  //                     The LLVM Compiler Infrastructure  // @@ -14,6 +14,7 @@  #include "hwasan.h"  #include "hwasan_allocator.h" +#include "hwasan_mapping.h"  #include "sanitizer_common/sanitizer_allocator_internal.h"  #include "sanitizer_common/sanitizer_common.h"  #include "sanitizer_common/sanitizer_flags.h" @@ -36,9 +37,9 @@ static StackTrace GetStackTraceFromId(u32 id) {  class Decorator: public __sanitizer::SanitizerCommonDecorator {   public:    Decorator() : SanitizerCommonDecorator() { } -  const char *Allocation() { return Magenta(); } -  const char *Origin() { return Magenta(); } -  const char *Name() { return Green(); } +  const char *Allocation() const { return Magenta(); } +  const char *Origin() const { return Magenta(); } +  const char *Name() const { return Green(); }  };  struct HeapAddressDescription { @@ -129,5 +130,4 @@ void ReportTagMismatch(StackTrace *stack, uptr addr, uptr access_size,    ReportErrorSummary("tag-mismatch", stack);  } -  }  // namespace __hwasan diff --git a/lib/hwasan/hwasan_report.h b/lib/hwasan/hwasan_report.h new file mode 100644 index 0000000000000..bb33f1a87308f --- /dev/null +++ b/lib/hwasan/hwasan_report.h @@ -0,0 +1,36 @@ +//===-- hwasan_report.h -----------------------------------------*- C++ -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file is a part of HWAddressSanitizer. HWASan-private header for error +/// reporting functions. +/// +//===----------------------------------------------------------------------===// + +#ifndef HWASAN_REPORT_H +#define HWASAN_REPORT_H + +#include "sanitizer_common/sanitizer_internal_defs.h" +#include "sanitizer_common/sanitizer_stacktrace.h" + +namespace __hwasan { + +void ReportInvalidAccess(StackTrace *stack, u32 origin); +void ReportStats(); +void ReportInvalidAccessInsideAddressRange(const char *what, const void *start, +                                           uptr size, uptr offset); +void ReportTagMismatch(StackTrace *stack, uptr addr, uptr access_size, +                       bool is_store); + +void ReportAtExitStatistics(); + + +}  // namespace __hwasan + +#endif  // HWASAN_REPORT_H diff --git a/lib/hwasan/hwasan_thread.cc b/lib/hwasan/hwasan_thread.cc index d6551ffc6fdce..b50c0fc76be42 100644 --- a/lib/hwasan/hwasan_thread.cc +++ b/lib/hwasan/hwasan_thread.cc @@ -1,5 +1,6 @@  #include "hwasan.h" +#include "hwasan_mapping.h"  #include "hwasan_thread.h"  #include "hwasan_poisoning.h"  #include "hwasan_interface_internal.h" @@ -8,6 +9,19 @@  namespace __hwasan { +static u32 RandomSeed() { +  u32 seed; +  do { +    if (UNLIKELY(!GetRandom(reinterpret_cast<void *>(&seed), sizeof(seed), +                            /*blocking=*/false))) { +      seed = static_cast<u32>( +          (NanoTime() >> 12) ^ +          (reinterpret_cast<uptr>(__builtin_frame_address(0)) >> 4)); +    } +  } while (!seed); +  return seed; +} +  HwasanThread *HwasanThread::Create(thread_callback_t start_routine,                                 void *arg) {    uptr PageSize = GetPageSizeCached(); @@ -16,6 +30,7 @@ HwasanThread *HwasanThread::Create(thread_callback_t start_routine,    thread->start_routine_ = start_routine;    thread->arg_ = arg;    thread->destructor_iterations_ = GetPthreadDestructorIterations(); +  thread->random_state_ = flags()->random_tags ? RandomSeed() : 0;    return thread;  } @@ -72,4 +87,28 @@ thread_return_t HwasanThread::ThreadStart() {    return res;  } +static u32 xorshift(u32 state) { +  state ^= state << 13; +  state ^= state >> 17; +  state ^= state << 5; +  return state; +} + +// Generate a (pseudo-)random non-zero tag. +tag_t HwasanThread::GenerateRandomTag() { +  tag_t tag; +  do { +    if (flags()->random_tags) { +      if (!random_buffer_) +        random_buffer_ = random_state_ = xorshift(random_state_); +      CHECK(random_buffer_); +      tag = random_buffer_ & 0xFF; +      random_buffer_ >>= 8; +    } else { +      tag = random_state_ = (random_state_ + 1) & 0xFF; +    } +  } while (!tag); +  return tag; +} +  } // namespace __hwasan diff --git a/lib/hwasan/hwasan_thread.h b/lib/hwasan/hwasan_thread.h index 96f1bb813adf1..1e482adeac844 100644 --- a/lib/hwasan/hwasan_thread.h +++ b/lib/hwasan/hwasan_thread.h @@ -52,6 +52,8 @@ class HwasanThread {    HwasanThreadLocalMallocStorage &malloc_storage() { return malloc_storage_; } +  tag_t GenerateRandomTag(); +    int destructor_iterations_;   private: @@ -70,6 +72,9 @@ class HwasanThread {    unsigned in_symbolizer_;    unsigned in_interceptor_scope_; +  u32 random_state_; +  u32 random_buffer_; +    HwasanThreadLocalMallocStorage malloc_storage_;  }; diff --git a/lib/interception/.clang-format b/lib/interception/.clang-format index f6cb8ad931f54..560308c91deec 100644 --- a/lib/interception/.clang-format +++ b/lib/interception/.clang-format @@ -1 +1,2 @@  BasedOnStyle: Google +AllowShortIfStatementsOnASingleLine: false diff --git a/lib/interception/CMakeLists.txt b/lib/interception/CMakeLists.txt index 18d25948105d7..c0ac974d726ae 100644 --- a/lib/interception/CMakeLists.txt +++ b/lib/interception/CMakeLists.txt @@ -4,8 +4,13 @@ set(INTERCEPTION_SOURCES    interception_linux.cc    interception_mac.cc    interception_win.cc -  interception_type_test.cc -  ) +  interception_type_test.cc) + +set(INTERCEPTION_HEADERS +  interception.h +  interception_linux.h +  interception_mac.h +  interception_win.h)  include_directories(..) @@ -16,6 +21,7 @@ add_compiler_rt_object_libraries(RTInterception      OS ${SANITIZER_COMMON_SUPPORTED_OS}      ARCHS ${SANITIZER_COMMON_SUPPORTED_ARCH}      SOURCES ${INTERCEPTION_SOURCES} +    ADDITIONAL_HEADERS ${INTERCEPTION_HEADERS}      CFLAGS ${INTERCEPTION_CFLAGS})  if(COMPILER_RT_INCLUDE_TESTS) diff --git a/lib/interception/interception.h b/lib/interception/interception.h index cba484936eac6..ddd6ec20979ba 100644 --- a/lib/interception/interception.h +++ b/lib/interception/interception.h @@ -18,8 +18,8 @@  #include "sanitizer_common/sanitizer_internal_defs.h"  #if !SANITIZER_LINUX && !SANITIZER_FREEBSD && !SANITIZER_MAC && \ -    !SANITIZER_NETBSD && !SANITIZER_WINDOWS && !SANITIZER_FUCHSIA && \ -    !SANITIZER_SOLARIS +    !SANITIZER_NETBSD && !SANITIZER_OPENBSD && !SANITIZER_WINDOWS && \ +    !SANITIZER_FUCHSIA && !SANITIZER_RTEMS && !SANITIZER_SOLARIS  # error "Interception doesn't work on this operating system."  #endif @@ -130,6 +130,11 @@ const interpose_substitution substitution_##func_name[] \      extern "C" ret_type func(__VA_ARGS__);  # define DECLARE_WRAPPER_WINAPI(ret_type, func, ...) \      extern "C" __declspec(dllimport) ret_type __stdcall func(__VA_ARGS__); +#elif SANITIZER_RTEMS +# define WRAP(x) x +# define WRAPPER_NAME(x) #x +# define INTERCEPTOR_ATTRIBUTE +# define DECLARE_WRAPPER(ret_type, func, ...)  #elif SANITIZER_FREEBSD || SANITIZER_NETBSD  # define WRAP(x) __interceptor_ ## x  # define WRAPPER_NAME(x) "__interceptor_" #x @@ -157,6 +162,10 @@ const interpose_substitution substitution_##func_name[] \  # define INTERCEPTOR_ATTRIBUTE __attribute__((visibility("default")))  # define REAL(x) __unsanitized_##x  # define DECLARE_REAL(ret_type, func, ...) +#elif SANITIZER_RTEMS +# define REAL(x) __real_ ## x +# define DECLARE_REAL(ret_type, func, ...) \ +    extern "C" ret_type REAL(func)(__VA_ARGS__);  #elif !SANITIZER_MAC  # define PTR_TO_REAL(x) real_##x  # define REAL(x) __interception::PTR_TO_REAL(x) @@ -175,7 +184,7 @@ const interpose_substitution substitution_##func_name[] \  # define ASSIGN_REAL(x, y)  #endif  // SANITIZER_MAC -#if !SANITIZER_FUCHSIA +#if !SANITIZER_FUCHSIA && !SANITIZER_RTEMS  #define DECLARE_REAL_AND_INTERCEPTOR(ret_type, func, ...) \    DECLARE_REAL(ret_type, func, __VA_ARGS__) \    extern "C" ret_type WRAP(func)(__VA_ARGS__); @@ -187,7 +196,7 @@ const interpose_substitution substitution_##func_name[] \  // macros does its job. In exceptional cases you may need to call REAL(foo)  // without defining INTERCEPTOR(..., foo, ...). For example, if you override  // foo with an interceptor for other function. -#if !SANITIZER_MAC && !SANITIZER_FUCHSIA +#if !SANITIZER_MAC && !SANITIZER_FUCHSIA && !SANITIZER_RTEMS  # define DEFINE_REAL(ret_type, func, ...) \      typedef ret_type (*FUNC_TYPE(func))(__VA_ARGS__); \      namespace __interception { \ @@ -266,7 +275,7 @@ typedef unsigned long uptr;  // NOLINT  #define INCLUDED_FROM_INTERCEPTION_LIB  #if SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD || \ -    SANITIZER_SOLARIS +    SANITIZER_OPENBSD || SANITIZER_SOLARIS  # include "interception_linux.h"  # define INTERCEPT_FUNCTION(func) INTERCEPT_FUNCTION_LINUX_OR_FREEBSD(func) diff --git a/lib/interception/interception_linux.cc b/lib/interception/interception_linux.cc index c991550a4f728..26bfcd8f6794d 100644 --- a/lib/interception/interception_linux.cc +++ b/lib/interception/interception_linux.cc @@ -15,7 +15,7 @@  #include "interception.h"  #if SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD || \ -    SANITIZER_SOLARIS +    SANITIZER_OPENBSD || SANITIZER_SOLARIS  #include <dlfcn.h>   // for dlsym() and dlvsym() @@ -43,7 +43,7 @@ bool GetRealFunctionAddress(const char *func_name, uptr *func_addr,  }  // Android and Solaris do not have dlvsym -#if !SANITIZER_ANDROID && !SANITIZER_SOLARIS +#if !SANITIZER_ANDROID && !SANITIZER_SOLARIS && !SANITIZER_OPENBSD  void *GetFuncAddrVer(const char *func_name, const char *ver) {    return dlvsym(RTLD_NEXT, func_name, ver);  } @@ -52,4 +52,4 @@ void *GetFuncAddrVer(const char *func_name, const char *ver) {  }  // namespace __interception  #endif  // SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD || -        // SANITIZER_SOLARIS +        // SANITIZER_OPENBSD || SANITIZER_SOLARIS diff --git a/lib/interception/interception_linux.h b/lib/interception/interception_linux.h index 98fe51b858fcb..942c25609ccb7 100644 --- a/lib/interception/interception_linux.h +++ b/lib/interception/interception_linux.h @@ -13,7 +13,7 @@  //===----------------------------------------------------------------------===//  #if SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD || \ -    SANITIZER_SOLARIS +    SANITIZER_OPENBSD || SANITIZER_SOLARIS  #if !defined(INCLUDED_FROM_INTERCEPTION_LIB)  # error "interception_linux.h should be included from interception library only" @@ -35,8 +35,8 @@ void *GetFuncAddrVer(const char *func_name, const char *ver);        (::__interception::uptr) & (func),                                   \        (::__interception::uptr) & WRAP(func)) -// Android and Solaris do not have dlvsym -#if !SANITIZER_ANDROID && !SANITIZER_SOLARIS +// Android,  Solaris and OpenBSD do not have dlvsym +#if !SANITIZER_ANDROID && !SANITIZER_SOLARIS && !SANITIZER_OPENBSD  #define INTERCEPT_FUNCTION_VER_LINUX_OR_FREEBSD(func, symver) \    (::__interception::real_##func = (func##_f)(                \         unsigned long)::__interception::GetFuncAddrVer(#func, symver)) @@ -47,4 +47,4 @@ void *GetFuncAddrVer(const char *func_name, const char *ver);  #endif  // INTERCEPTION_LINUX_H  #endif  // SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD || -        // SANITIZER_SOLARIS +        // SANITIZER_OPENBSD || SANITIZER_SOLARIS diff --git a/lib/interception/interception_win.cc b/lib/interception/interception_win.cc index dc3fe35242ef1..bd4ad7274dded 100644 --- a/lib/interception/interception_win.cc +++ b/lib/interception/interception_win.cc @@ -453,6 +453,7 @@ static size_t GetInstructionSize(uptr address, size_t* rel_offset = nullptr) {    }    switch (*(u16*)(address)) { +    case 0x018A:  // 8A 01 : mov al, byte ptr [ecx]      case 0xFF8B:  // 8B FF : mov edi, edi      case 0xEC8B:  // 8B EC : mov ebp, esp      case 0xc889:  // 89 C8 : mov eax, ecx diff --git a/lib/lsan/.clang-format b/lib/lsan/.clang-format index f6cb8ad931f54..560308c91deec 100644 --- a/lib/lsan/.clang-format +++ b/lib/lsan/.clang-format @@ -1 +1,2 @@  BasedOnStyle: Google +AllowShortIfStatementsOnASingleLine: false diff --git a/lib/lsan/CMakeLists.txt b/lib/lsan/CMakeLists.txt index 60da3e1868716..34f686135ac47 100644 --- a/lib/lsan/CMakeLists.txt +++ b/lib/lsan/CMakeLists.txt @@ -18,12 +18,20 @@ set(LSAN_SOURCES    lsan_preinit.cc    lsan_thread.cc) +set(LSAN_HEADERS +  lsan.h +  lsan_allocator.h +  lsan_common.h +  lsan_flags.inc +  lsan_thread.h) +  set(LSAN_SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR})  add_compiler_rt_object_libraries(RTLSanCommon      OS ${SANITIZER_COMMON_SUPPORTED_OS}      ARCHS ${LSAN_COMMON_SUPPORTED_ARCH}      SOURCES ${LSAN_COMMON_SOURCES} +    ADDITIONAL_HEADERS ${LSAN_HEADERS}      CFLAGS ${LSAN_CFLAGS})  if(COMPILER_RT_HAS_LSAN) @@ -39,10 +47,13 @@ if(COMPILER_RT_HAS_LSAN)        OS ${SANITIZER_COMMON_SUPPORTED_OS}        ARCHS ${LSAN_SUPPORTED_ARCH}        SOURCES ${LSAN_SOURCES} +      ADDITIONAL_HEADERS ${LSAN_HEADERS}        OBJECT_LIBS RTLSanCommon                    RTInterception                    RTSanitizerCommon                    RTSanitizerCommonLibc +                  RTSanitizerCommonCoverage +                  RTSanitizerCommonSymbolizer        CFLAGS ${LSAN_CFLAGS}        LINK_FLAGS ${SANITIZER_COMMON_LINK_FLAGS} ${WEAK_SYMBOL_LINK_FLAGS}        LINK_LIBS ${LSAN_LINK_LIBS} @@ -56,7 +67,10 @@ if(COMPILER_RT_HAS_LSAN)                  $<TARGET_OBJECTS:RTInterception.${arch}>                  $<TARGET_OBJECTS:RTSanitizerCommon.${arch}>                  $<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}> +                $<TARGET_OBJECTS:RTSanitizerCommonCoverage.${arch}> +                $<TARGET_OBJECTS:RTSanitizerCommonSymbolizer.${arch}>                  $<TARGET_OBJECTS:RTLSanCommon.${arch}> +        ADDITIONAL_HEADERS ${LSAN_HEADERS}          CFLAGS ${LSAN_CFLAGS}          PARENT_TARGET lsan)      endforeach() diff --git a/lib/lsan/lsan.cc b/lib/lsan/lsan.cc index a9f7e399e14cf..93bced0459c25 100644 --- a/lib/lsan/lsan.cc +++ b/lib/lsan/lsan.cc @@ -66,6 +66,8 @@ static void InitializeFlags() {    if (Verbosity()) ReportUnrecognizedFlags();    if (common_flags()->help) parser.PrintFlagDescriptions(); + +  __sanitizer_set_report_path(common_flags()->log_path);  }  static void OnStackUnwind(const SignalContext &sig, const void *, diff --git a/lib/lsan/lsan_allocator.cc b/lib/lsan/lsan_allocator.cc index 2df58b44f6b85..c58c3548002f1 100644 --- a/lib/lsan/lsan_allocator.cc +++ b/lib/lsan/lsan_allocator.cc @@ -17,6 +17,7 @@  #include "sanitizer_common/sanitizer_allocator.h"  #include "sanitizer_common/sanitizer_allocator_checks.h"  #include "sanitizer_common/sanitizer_allocator_interface.h" +#include "sanitizer_common/sanitizer_allocator_report.h"  #include "sanitizer_common/sanitizer_errno.h"  #include "sanitizer_common/sanitizer_internal_defs.h"  #include "sanitizer_common/sanitizer_stackdepot.h" @@ -70,15 +71,27 @@ static void RegisterDeallocation(void *p) {    atomic_store(reinterpret_cast<atomic_uint8_t *>(m), 0, memory_order_relaxed);  } +static void *ReportAllocationSizeTooBig(uptr size, const StackTrace &stack) { +  if (AllocatorMayReturnNull()) { +    Report("WARNING: LeakSanitizer failed to allocate 0x%zx bytes\n", size); +    return nullptr; +  } +  ReportAllocationSizeTooBig(size, kMaxAllowedMallocSize, &stack); +} +  void *Allocate(const StackTrace &stack, uptr size, uptr alignment,                 bool cleared) {    if (size == 0)      size = 1; -  if (size > kMaxAllowedMallocSize) { -    Report("WARNING: LeakSanitizer failed to allocate %zu bytes\n", size); -    return Allocator::FailureHandler::OnBadRequest(); -  } +  if (size > kMaxAllowedMallocSize) +    return ReportAllocationSizeTooBig(size, stack);    void *p = allocator.Allocate(GetAllocatorCache(), size, alignment); +  if (UNLIKELY(!p)) { +    SetAllocatorOutOfMemory(); +    if (AllocatorMayReturnNull()) +      return nullptr; +    ReportOutOfMemory(size, &stack); +  }    // Do not rely on the allocator to clear the memory (it's slow).    if (cleared && allocator.FromPrimary(p))      memset(p, 0, size); @@ -89,8 +102,11 @@ void *Allocate(const StackTrace &stack, uptr size, uptr alignment,  }  static void *Calloc(uptr nmemb, uptr size, const StackTrace &stack) { -  if (UNLIKELY(CheckForCallocOverflow(size, nmemb))) -    return Allocator::FailureHandler::OnBadRequest(); +  if (UNLIKELY(CheckForCallocOverflow(size, nmemb))) { +    if (AllocatorMayReturnNull()) +      return nullptr; +    ReportCallocOverflow(nmemb, size, &stack); +  }    size *= nmemb;    return Allocate(stack, size, 1, true);  } @@ -106,9 +122,8 @@ void *Reallocate(const StackTrace &stack, void *p, uptr new_size,                   uptr alignment) {    RegisterDeallocation(p);    if (new_size > kMaxAllowedMallocSize) { -    Report("WARNING: LeakSanitizer failed to allocate %zu bytes\n", new_size);      allocator.Deallocate(GetAllocatorCache(), p); -    return Allocator::FailureHandler::OnBadRequest(); +    return ReportAllocationSizeTooBig(new_size, stack);    }    p = allocator.Reallocate(GetAllocatorCache(), p, new_size, alignment);    RegisterAllocation(stack, p, new_size); @@ -126,10 +141,38 @@ uptr GetMallocUsableSize(const void *p) {    return m->requested_size;  } +int lsan_posix_memalign(void **memptr, uptr alignment, uptr size, +                        const StackTrace &stack) { +  if (UNLIKELY(!CheckPosixMemalignAlignment(alignment))) { +    if (AllocatorMayReturnNull()) +      return errno_EINVAL; +    ReportInvalidPosixMemalignAlignment(alignment, &stack); +  } +  void *ptr = Allocate(stack, size, alignment, kAlwaysClearMemory); +  if (UNLIKELY(!ptr)) +    // OOM error is already taken care of by Allocate. +    return errno_ENOMEM; +  CHECK(IsAligned((uptr)ptr, alignment)); +  *memptr = ptr; +  return 0; +} + +void *lsan_aligned_alloc(uptr alignment, uptr size, const StackTrace &stack) { +  if (UNLIKELY(!CheckAlignedAllocAlignmentAndSize(alignment, size))) { +    errno = errno_EINVAL; +    if (AllocatorMayReturnNull()) +      return nullptr; +    ReportInvalidAlignedAllocAlignment(size, alignment, &stack); +  } +  return SetErrnoOnNull(Allocate(stack, size, alignment, kAlwaysClearMemory)); +} +  void *lsan_memalign(uptr alignment, uptr size, const StackTrace &stack) {    if (UNLIKELY(!IsPowerOfTwo(alignment))) {      errno = errno_EINVAL; -    return Allocator::FailureHandler::OnBadRequest(); +    if (AllocatorMayReturnNull()) +      return nullptr; +    ReportInvalidAllocationAlignment(alignment, &stack);    }    return SetErrnoOnNull(Allocate(stack, size, alignment, kAlwaysClearMemory));  } @@ -155,6 +198,19 @@ void *lsan_valloc(uptr size, const StackTrace &stack) {        Allocate(stack, size, GetPageSizeCached(), kAlwaysClearMemory));  } +void *lsan_pvalloc(uptr size, const StackTrace &stack) { +  uptr PageSize = GetPageSizeCached(); +  if (UNLIKELY(CheckForPvallocOverflow(size, PageSize))) { +    errno = errno_ENOMEM; +    if (AllocatorMayReturnNull()) +      return nullptr; +    ReportPvallocOverflow(size, &stack); +  } +  // pvalloc(0) should allocate one page. +  size = size ? RoundUpTo(size, PageSize) : PageSize; +  return SetErrnoOnNull(Allocate(stack, size, PageSize, kAlwaysClearMemory)); +} +  uptr lsan_mz_size(const void *p) {    return GetMallocUsableSize(p);  } diff --git a/lib/lsan/lsan_allocator.h b/lib/lsan/lsan_allocator.h index 4006f79292692..7c70bb6d97660 100644 --- a/lib/lsan/lsan_allocator.h +++ b/lib/lsan/lsan_allocator.h @@ -90,12 +90,16 @@ typedef SizeClassAllocatorLocalCache<PrimaryAllocator> AllocatorCache;  AllocatorCache *GetAllocatorCache(); +int lsan_posix_memalign(void **memptr, uptr alignment, uptr size, +                        const StackTrace &stack); +void *lsan_aligned_alloc(uptr alignment, uptr size, const StackTrace &stack);  void *lsan_memalign(uptr alignment, uptr size, const StackTrace &stack);  void *lsan_malloc(uptr size, const StackTrace &stack);  void lsan_free(void *p);  void *lsan_realloc(void *p, uptr size, const StackTrace &stack);  void *lsan_calloc(uptr nmemb, uptr size, const StackTrace &stack);  void *lsan_valloc(uptr size, const StackTrace &stack); +void *lsan_pvalloc(uptr size, const StackTrace &stack);  uptr lsan_mz_size(const void *p);  }  // namespace __lsan diff --git a/lib/lsan/lsan_common.cc b/lib/lsan/lsan_common.cc index 69ffda539a266..012a673c3b25c 100644 --- a/lib/lsan/lsan_common.cc +++ b/lib/lsan/lsan_common.cc @@ -15,14 +15,15 @@  #include "lsan_common.h"  #include "sanitizer_common/sanitizer_common.h" -#include "sanitizer_common/sanitizer_flags.h"  #include "sanitizer_common/sanitizer_flag_parser.h" +#include "sanitizer_common/sanitizer_flags.h"  #include "sanitizer_common/sanitizer_placement_new.h"  #include "sanitizer_common/sanitizer_procmaps.h" +#include "sanitizer_common/sanitizer_report_decorator.h"  #include "sanitizer_common/sanitizer_stackdepot.h"  #include "sanitizer_common/sanitizer_stacktrace.h"  #include "sanitizer_common/sanitizer_suppressions.h" -#include "sanitizer_common/sanitizer_report_decorator.h" +#include "sanitizer_common/sanitizer_thread_registry.h"  #include "sanitizer_common/sanitizer_tls_get_addr.h"  #if CAN_SANITIZE_LEAKS @@ -99,12 +100,14 @@ static SuppressionContext *GetSuppressionContext() {  static InternalMmapVector<RootRegion> *root_regions; +static uptr initialized_for_pid; +  InternalMmapVector<RootRegion> const *GetRootRegions() { return root_regions; }  void InitializeRootRegions() {    CHECK(!root_regions);    ALIGNED(64) static char placeholder[sizeof(InternalMmapVector<RootRegion>)]; -  root_regions = new(placeholder) InternalMmapVector<RootRegion>(1); +  root_regions = new (placeholder) InternalMmapVector<RootRegion>();  // NOLINT  }  const char *MaybeCallLsanDefaultOptions() { @@ -112,6 +115,7 @@ const char *MaybeCallLsanDefaultOptions() {  }  void InitCommonLsan() { +  initialized_for_pid = internal_getpid();    InitializeRootRegions();    if (common_flags()->detect_leaks) {      // Initialization which can fail or print warnings should only be done if @@ -214,9 +218,10 @@ void ForEachExtraStackRangeCb(uptr begin, uptr end, void* arg) {  // Scans thread data (stacks and TLS) for heap pointers.  static void ProcessThreads(SuspendedThreadsList const &suspended_threads,                             Frontier *frontier) { -  InternalScopedBuffer<uptr> registers(suspended_threads.RegisterCount()); +  InternalMmapVector<uptr> registers(suspended_threads.RegisterCount());    uptr registers_begin = reinterpret_cast<uptr>(registers.data()); -  uptr registers_end = registers_begin + registers.size(); +  uptr registers_end = +      reinterpret_cast<uptr>(registers.data() + registers.size());    for (uptr i = 0; i < suspended_threads.ThreadCount(); i++) {      tid_t os_id = static_cast<tid_t>(suspended_threads.GetThreadID(i));      LOG_THREADS("Processing thread %d.\n", os_id); @@ -444,7 +449,7 @@ void ProcessPC(Frontier *frontier) {  // Sets the appropriate tag on each chunk.  static void ClassifyAllChunks(SuspendedThreadsList const &suspended_threads) {    // Holds the flood fill frontier. -  Frontier frontier(1); +  Frontier frontier;    ForEachChunk(CollectIgnoredCb, &frontier);    ProcessGlobalRegions(&frontier); @@ -506,7 +511,7 @@ static void CollectLeaksCb(uptr chunk, void *arg) {  }  static void PrintMatchedSuppressions() { -  InternalMmapVector<Suppression *> matched(1); +  InternalMmapVector<Suppression *> matched;    GetSuppressionContext()->GetMatched(&matched);    if (!matched.size())      return; @@ -525,11 +530,36 @@ struct CheckForLeaksParam {    LeakReport leak_report;  }; +static void ReportIfNotSuspended(ThreadContextBase *tctx, void *arg) { +  const InternalMmapVector<tid_t> &suspended_threads = +      *(const InternalMmapVector<tid_t> *)arg; +  if (tctx->status == ThreadStatusRunning) { +    uptr i = InternalLowerBound(suspended_threads, 0, suspended_threads.size(), +                                tctx->os_id, CompareLess<int>()); +    if (i >= suspended_threads.size() || suspended_threads[i] != tctx->os_id) +      Report("Running thread %d was not suspended. False leaks are possible.\n", +             tctx->os_id); +  }; +} + +static void ReportUnsuspendedThreads( +    const SuspendedThreadsList &suspended_threads) { +  InternalMmapVector<tid_t> threads(suspended_threads.ThreadCount()); +  for (uptr i = 0; i < suspended_threads.ThreadCount(); ++i) +    threads[i] = suspended_threads.GetThreadID(i); + +  Sort(threads.data(), threads.size()); + +  GetThreadRegistryLocked()->RunCallbackForEachThreadLocked( +      &ReportIfNotSuspended, &threads); +} +  static void CheckForLeaksCallback(const SuspendedThreadsList &suspended_threads,                                    void *arg) {    CheckForLeaksParam *param = reinterpret_cast<CheckForLeaksParam *>(arg);    CHECK(param);    CHECK(!param->success); +  ReportUnsuspendedThreads(suspended_threads);    ClassifyAllChunks(suspended_threads);    ForEachChunk(CollectLeaksCb, ¶m->leak_report);    // Clean up for subsequent leak checks. This assumes we did not overwrite any @@ -541,6 +571,12 @@ static void CheckForLeaksCallback(const SuspendedThreadsList &suspended_threads,  static bool CheckForLeaks() {    if (&__lsan_is_turned_off && __lsan_is_turned_off())        return false; +  if (initialized_for_pid != internal_getpid()) { +    // If process was forked and it had threads we fail to detect references +    // from other threads. +    Report("WARNING: LeakSanitizer is disabled in forked process.\n"); +    return false; +  }    EnsureMainThreadIDIsCorrect();    CheckForLeaksParam param;    param.success = false; @@ -684,7 +720,7 @@ void LeakReport::ReportTopLeaks(uptr num_leaks_to_report) {    uptr unsuppressed_count = UnsuppressedLeakCount();    if (num_leaks_to_report > 0 && num_leaks_to_report < unsuppressed_count)      Printf("The %zu top leak(s):\n", num_leaks_to_report); -  InternalSort(&leaks_, leaks_.size(), LeakComparator); +  Sort(leaks_.data(), leaks_.size(), &LeakComparator);    uptr leaks_reported = 0;    for (uptr i = 0; i < leaks_.size(); i++) {      if (leaks_[i].is_suppressed) continue; diff --git a/lib/lsan/lsan_common.h b/lib/lsan/lsan_common.h index f3863309d8930..1d1e1e4624357 100644 --- a/lib/lsan/lsan_common.h +++ b/lib/lsan/lsan_common.h @@ -47,6 +47,7 @@  namespace __sanitizer {  class FlagParser; +class ThreadRegistry;  struct DTLS;  } @@ -95,7 +96,7 @@ struct LeakedObject {  // Aggregates leaks by stack trace prefix.  class LeakReport {   public: -  LeakReport() : next_id_(0), leaks_(1), leaked_objects_(1) {} +  LeakReport() {}    void AddLeakedChunk(uptr chunk, u32 stack_trace_id, uptr leaked_size,                        ChunkTag tag);    void ReportTopLeaks(uptr max_leaks); @@ -103,12 +104,11 @@ class LeakReport {    void ApplySuppressions();    uptr UnsuppressedLeakCount(); -   private:    void PrintReportForLeak(uptr index);    void PrintLeakedObjectsForLeak(uptr index); -  u32 next_id_; +  u32 next_id_ = 0;    InternalMmapVector<Leak> leaks_;    InternalMmapVector<LeakedObject> leaked_objects_;  }; @@ -205,6 +205,7 @@ bool WordIsPoisoned(uptr addr);  // Wrappers for ThreadRegistry access.  void LockThreadRegistry();  void UnlockThreadRegistry(); +ThreadRegistry *GetThreadRegistryLocked();  bool GetThreadRangesLocked(tid_t os_id, uptr *stack_begin, uptr *stack_end,                             uptr *tls_begin, uptr *tls_end, uptr *cache_begin,                             uptr *cache_end, DTLS **dtls); diff --git a/lib/lsan/lsan_common_mac.cc b/lib/lsan/lsan_common_mac.cc index ac27c7af6e356..2508c1dbd873f 100644 --- a/lib/lsan/lsan_common_mac.cc +++ b/lib/lsan/lsan_common_mac.cc @@ -24,6 +24,13 @@  #include <mach/mach.h> +// Only introduced in Mac OS X 10.9. +#ifdef VM_MEMORY_OS_ALLOC_ONCE +static const int kSanitizerVmMemoryOsAllocOnce = VM_MEMORY_OS_ALLOC_ONCE; +#else +static const int kSanitizerVmMemoryOsAllocOnce = 73; +#endif +  namespace __lsan {  typedef struct { @@ -112,7 +119,8 @@ void ProcessGlobalRegions(Frontier *frontier) {    for (auto name : kSkippedSecNames) CHECK(ARRAY_SIZE(name) < kMaxSegName);    MemoryMappingLayout memory_mapping(false); -  InternalMmapVector<LoadedModule> modules(/*initial_capacity*/ 128); +  InternalMmapVector<LoadedModule> modules; +  modules.reserve(128);    memory_mapping.DumpListOfModules(&modules);    for (uptr i = 0; i < modules.size(); ++i) {      // Even when global scanning is disabled, we still need to scan @@ -157,7 +165,7 @@ void ProcessPlatformSpecificAllocations(Frontier *frontier) {      // libxpc stashes some pointers in the Kernel Alloc Once page,      // make sure not to report those as leaks. -    if (info.user_tag == VM_MEMORY_OS_ALLOC_ONCE) { +    if (info.user_tag == kSanitizerVmMemoryOsAllocOnce) {        ScanRangeForPointers(address, end_address, frontier, "GLOBAL",                             kReachable); diff --git a/lib/lsan/lsan_interceptors.cc b/lib/lsan/lsan_interceptors.cc index b3e73e3896d51..fde52e496164d 100644 --- a/lib/lsan/lsan_interceptors.cc +++ b/lib/lsan/lsan_interceptors.cc @@ -14,6 +14,7 @@  #include "interception/interception.h"  #include "sanitizer_common/sanitizer_allocator.h" +#include "sanitizer_common/sanitizer_allocator_report.h"  #include "sanitizer_common/sanitizer_atomic.h"  #include "sanitizer_common/sanitizer_common.h"  #include "sanitizer_common/sanitizer_flags.h" @@ -86,9 +87,7 @@ INTERCEPTOR(void*, realloc, void *q, uptr size) {  INTERCEPTOR(int, posix_memalign, void **memptr, uptr alignment, uptr size) {    ENSURE_LSAN_INITED;    GET_STACK_TRACE_MALLOC; -  *memptr = lsan_memalign(alignment, size, stack); -  // FIXME: Return ENOMEM if user requested more than max alloc size. -  return 0; +  return lsan_posix_memalign(memptr, alignment, size, stack);  }  INTERCEPTOR(void*, valloc, uptr size) { @@ -123,7 +122,7 @@ INTERCEPTOR(void *, __libc_memalign, uptr alignment, uptr size) {  INTERCEPTOR(void*, aligned_alloc, uptr alignment, uptr size) {    ENSURE_LSAN_INITED;    GET_STACK_TRACE_MALLOC; -  return lsan_memalign(alignment, size, stack); +  return lsan_aligned_alloc(alignment, size, stack);  }  #define LSAN_MAYBE_INTERCEPT_ALIGNED_ALLOC INTERCEPT_FUNCTION(aligned_alloc)  #else @@ -166,13 +165,7 @@ INTERCEPTOR(int, mallopt, int cmd, int value) {  INTERCEPTOR(void*, pvalloc, uptr size) {    ENSURE_LSAN_INITED;    GET_STACK_TRACE_MALLOC; -  uptr PageSize = GetPageSizeCached(); -  size = RoundUpTo(size, PageSize); -  if (size == 0) { -    // pvalloc(0) should allocate one page. -    size = PageSize; -  } -  return Allocate(stack, size, GetPageSizeCached(), kAlwaysClearMemory); +  return lsan_pvalloc(size, stack);  }  #define LSAN_MAYBE_INTERCEPT_PVALLOC INTERCEPT_FUNCTION(pvalloc)  #else @@ -202,21 +195,21 @@ INTERCEPTOR(int, mprobe, void *ptr) {  // TODO(alekseys): throw std::bad_alloc instead of dying on OOM. -#define OPERATOR_NEW_BODY(nothrow)                         \ -  ENSURE_LSAN_INITED;                                      \ -  GET_STACK_TRACE_MALLOC;                                  \ -  void *res = lsan_malloc(size, stack);                    \ -  if (!nothrow && UNLIKELY(!res)) DieOnFailure::OnOOM();   \ +#define OPERATOR_NEW_BODY(nothrow)\ +  ENSURE_LSAN_INITED;\ +  GET_STACK_TRACE_MALLOC;\ +  void *res = lsan_malloc(size, stack);\ +  if (!nothrow && UNLIKELY(!res)) ReportOutOfMemory(size, &stack);\    return res; -#define OPERATOR_NEW_BODY_ALIGN(nothrow)                   \ -  ENSURE_LSAN_INITED;                                      \ -  GET_STACK_TRACE_MALLOC;                                  \ -  void *res = lsan_memalign((uptr)align, size, stack);     \ -  if (!nothrow && UNLIKELY(!res)) DieOnFailure::OnOOM();   \ +#define OPERATOR_NEW_BODY_ALIGN(nothrow)\ +  ENSURE_LSAN_INITED;\ +  GET_STACK_TRACE_MALLOC;\ +  void *res = lsan_memalign((uptr)align, size, stack);\ +  if (!nothrow && UNLIKELY(!res)) ReportOutOfMemory(size, &stack);\    return res; -#define OPERATOR_DELETE_BODY \ -  ENSURE_LSAN_INITED;        \ +#define OPERATOR_DELETE_BODY\ +  ENSURE_LSAN_INITED;\    lsan_free(ptr);  // On OS X it's not enough to just provide our own 'operator new' and @@ -309,7 +302,7 @@ INTERCEPTOR(void, _ZdaPvRKSt9nothrow_t, void *ptr, std::nothrow_t const&)  ///// Thread initialization and finalization. ///// -#if !SANITIZER_NETBSD +#if !SANITIZER_NETBSD && !SANITIZER_FREEBSD  static unsigned g_thread_finalize_key;  static void thread_finalize(void *v) { @@ -336,6 +329,17 @@ INTERCEPTOR(void, _lwp_exit) {  #define LSAN_MAYBE_INTERCEPT__LWP_EXIT  #endif +#if SANITIZER_INTERCEPT_THR_EXIT +INTERCEPTOR(void, thr_exit, tid_t *state) { +  ENSURE_LSAN_INITED; +  ThreadFinish(); +  REAL(thr_exit)(state); +} +#define LSAN_MAYBE_INTERCEPT_THR_EXIT INTERCEPT_FUNCTION(thr_exit) +#else +#define LSAN_MAYBE_INTERCEPT_THR_EXIT +#endif +  struct ThreadParam {    void *(*callback)(void *arg);    void *param; @@ -348,7 +352,7 @@ extern "C" void *__lsan_thread_start_func(void *arg) {    void *param = p->param;    // Wait until the last iteration to maximize the chance that we are the last    // destructor to run. -#if !SANITIZER_NETBSD +#if !SANITIZER_NETBSD && !SANITIZER_FREEBSD    if (pthread_setspecific(g_thread_finalize_key,                            (void*)GetPthreadDestructorIterations())) {      Report("LeakSanitizer: failed to set thread key.\n"); @@ -443,8 +447,9 @@ void InitializeInterceptors() {    INTERCEPT_FUNCTION(_exit);    LSAN_MAYBE_INTERCEPT__LWP_EXIT; +  LSAN_MAYBE_INTERCEPT_THR_EXIT; -#if !SANITIZER_NETBSD +#if !SANITIZER_NETBSD && !SANITIZER_FREEBSD    if (pthread_key_create(&g_thread_finalize_key, &thread_finalize)) {      Report("LeakSanitizer: failed to create thread key.\n");      Die(); diff --git a/lib/lsan/lsan_malloc_mac.cc b/lib/lsan/lsan_malloc_mac.cc index 9c1dacc055bd2..94ffb6d02539e 100644 --- a/lib/lsan/lsan_malloc_mac.cc +++ b/lib/lsan/lsan_malloc_mac.cc @@ -37,6 +37,9 @@ using namespace __lsan;  #define COMMON_MALLOC_CALLOC(count, size) \    GET_STACK_TRACE_MALLOC; \    void *p = lsan_calloc(count, size, stack) +#define COMMON_MALLOC_POSIX_MEMALIGN(memptr, alignment, size) \ +  GET_STACK_TRACE_MALLOC; \ +  int res = lsan_posix_memalign(memptr, alignment, size, stack)  #define COMMON_MALLOC_VALLOC(size) \    GET_STACK_TRACE_MALLOC; \    void *p = lsan_valloc(size, stack) diff --git a/lib/lsan/lsan_thread.cc b/lib/lsan/lsan_thread.cc index 4404c8cc51d23..a25aff3799611 100644 --- a/lib/lsan/lsan_thread.cc +++ b/lib/lsan/lsan_thread.cc @@ -155,4 +155,9 @@ void UnlockThreadRegistry() {    thread_registry->Unlock();  } +ThreadRegistry *GetThreadRegistryLocked() { +  thread_registry->CheckLocked(); +  return thread_registry; +} +  } // namespace __lsan diff --git a/lib/msan/.clang-format b/lib/msan/.clang-format index f6cb8ad931f54..560308c91deec 100644 --- a/lib/msan/.clang-format +++ b/lib/msan/.clang-format @@ -1 +1,2 @@  BasedOnStyle: Google +AllowShortIfStatementsOnASingleLine: false diff --git a/lib/msan/CMakeLists.txt b/lib/msan/CMakeLists.txt index 598ae54588c19..15cc513c20e94 100644 --- a/lib/msan/CMakeLists.txt +++ b/lib/msan/CMakeLists.txt @@ -15,10 +15,26 @@ set(MSAN_RTL_SOURCES  set(MSAN_RTL_CXX_SOURCES    msan_new_delete.cc) +set(MSAN_RTL_HEADERS +  msan.h +  msan_allocator.h +  msan_chained_origin_depot.h +  msan_flags.h +  msan_flags.inc +  msan_interface_internal.h +  msan_origin.h +  msan_poisoning.h +  msan_report.h +  msan_thread.h)  set(MSAN_RTL_CFLAGS ${SANITIZER_COMMON_CFLAGS}) +if(CMAKE_SYSTEM_NAME MATCHES "FreeBSD") +  append_list_if(COMPILER_RT_HAS_FTLS_MODEL_INITIAL_EXEC -ftls-model=initial-exec MSAN_RTL_CFLAGS) +endif()  append_rtti_flag(OFF MSAN_RTL_CFLAGS) -append_list_if(COMPILER_RT_HAS_FPIE_FLAG -fPIE MSAN_RTL_CFLAGS) +if(NOT CMAKE_SYSTEM_NAME MATCHES "FreeBSD") +  append_list_if(COMPILER_RT_HAS_FPIE_FLAG -fPIE MSAN_RTL_CFLAGS) +endif()  # Prevent clang from generating libc calls.  append_list_if(COMPILER_RT_HAS_FFREESTANDING_FLAG -ffreestanding MSAN_RTL_CFLAGS) @@ -35,7 +51,10 @@ foreach(arch ${MSAN_SUPPORTED_ARCH})              $<TARGET_OBJECTS:RTInterception.${arch}>              $<TARGET_OBJECTS:RTSanitizerCommon.${arch}>              $<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}> +            $<TARGET_OBJECTS:RTSanitizerCommonCoverage.${arch}> +            $<TARGET_OBJECTS:RTSanitizerCommonSymbolizer.${arch}>              $<TARGET_OBJECTS:RTUbsan.${arch}> +    ADDITIONAL_HEADERS ${MSAN_RTL_HEADERS}      CFLAGS ${MSAN_RTL_CFLAGS}      PARENT_TARGET msan)    add_compiler_rt_runtime(clang_rt.msan_cxx @@ -43,11 +62,12 @@ foreach(arch ${MSAN_SUPPORTED_ARCH})      ARCHS ${arch}      SOURCES ${MSAN_RTL_CXX_SOURCES}              $<TARGET_OBJECTS:RTUbsan_cxx.${arch}> +    ADDITIONAL_HEADERS ${MSAN_RTL_HEADERS}      CFLAGS ${MSAN_RTL_CFLAGS}      PARENT_TARGET msan)    list(APPEND MSAN_RUNTIME_LIBRARIES clang_rt.msan-${arch}                                       clang_rt.msan_cxx-${arch}) -  if(UNIX) +  if(SANITIZER_USE_SYMBOLS)      add_sanitizer_rt_symbols(clang_rt.msan        ARCHS ${arch}        EXTRA msan.syms.extra) diff --git a/lib/msan/msan.cc b/lib/msan/msan.cc index e6226ba7670fa..06bcbdf886917 100644 --- a/lib/msan/msan.cc +++ b/lib/msan/msan.cc @@ -15,6 +15,7 @@  #include "msan.h"  #include "msan_chained_origin_depot.h"  #include "msan_origin.h" +#include "msan_report.h"  #include "msan_thread.h"  #include "msan_poisoning.h"  #include "sanitizer_common/sanitizer_atomic.h" @@ -379,6 +380,14 @@ static void MsanOnDeadlySignal(int signo, void *siginfo, void *context) {    HandleDeadlySignal(siginfo, context, GetTid(), &OnStackUnwind, nullptr);  } +static void MsanCheckFailed(const char *file, int line, const char *cond, +                            u64 v1, u64 v2) { +  Report("MemorySanitizer CHECK failed: %s:%d \"%s\" (0x%zx, 0x%zx)\n", file, +         line, cond, (uptr)v1, (uptr)v2); +  PRINT_CURRENT_STACK_CHECK(); +  Die(); +} +  void __msan_init() {    CHECK(!msan_init_is_running);    if (msan_inited) return; @@ -386,14 +395,18 @@ void __msan_init() {    SanitizerToolName = "MemorySanitizer";    AvoidCVE_2016_2143(); -  InitTlsSize();    CacheBinaryName(); +  CheckASLR();    InitializeFlags(); +  // Install tool-specific callbacks in sanitizer_common. +  SetCheckFailedCallback(MsanCheckFailed); +    __sanitizer_set_report_path(common_flags()->log_path);    InitializeInterceptors(); +  InitTlsSize();    InstallDeadlySignalHandlers(MsanOnDeadlySignal);    InstallAtExitHandler(); // Needs __cxa_atexit interceptor. diff --git a/lib/msan/msan.h b/lib/msan/msan.h index cbae444127eed..4c2e9f9e24a07 100644 --- a/lib/msan/msan.h +++ b/lib/msan/msan.h @@ -316,14 +316,6 @@ void PrintWarningWithOrigin(uptr pc, uptr bp, u32 origin);  void GetStackTrace(BufferedStackTrace *stack, uptr max_s, uptr pc, uptr bp,                     void *context, bool request_fast_unwind); -void ReportUMR(StackTrace *stack, u32 origin); -void ReportExpectedUMRNotFound(StackTrace *stack); -void ReportStats(); -void ReportAtExitStatistics(); -void DescribeMemoryRange(const void *x, uptr size); -void ReportUMRInsideAddressRange(const char *what, const void *start, uptr size, -                                 uptr offset); -  // Unpoison first n function arguments.  void UnpoisonParam(uptr n);  void UnpoisonThreadLocalState(); @@ -356,14 +348,23 @@ const int STACK_TRACE_TAG_POISON = StackTrace::TAG_CUSTOM + 1;                      common_flags()->fast_unwind_on_malloc);               \    } +#define GET_STORE_STACK_TRACE \ +  GET_STORE_STACK_TRACE_PC_BP(StackTrace::GetCurrentPc(), GET_CURRENT_FRAME()) +  #define GET_FATAL_STACK_TRACE_PC_BP(pc, bp)              \    BufferedStackTrace stack;                              \    if (msan_inited)                                       \    GetStackTrace(&stack, kStackTraceMax, pc, bp, nullptr, \                  common_flags()->fast_unwind_on_fatal) -#define GET_STORE_STACK_TRACE \ -  GET_STORE_STACK_TRACE_PC_BP(StackTrace::GetCurrentPc(), GET_CURRENT_FRAME()) +#define GET_FATAL_STACK_TRACE_HERE \ +  GET_FATAL_STACK_TRACE_PC_BP(StackTrace::GetCurrentPc(), GET_CURRENT_FRAME()) + +#define PRINT_CURRENT_STACK_CHECK() \ +  {                                 \ +    GET_FATAL_STACK_TRACE_HERE;     \ +    stack.Print();                  \ +  }  class ScopedThreadLocalStateBackup {   public: diff --git a/lib/msan/msan_allocator.cc b/lib/msan/msan_allocator.cc index 0f99423249318..36f0497a9d836 100644 --- a/lib/msan/msan_allocator.cc +++ b/lib/msan/msan_allocator.cc @@ -15,6 +15,7 @@  #include "sanitizer_common/sanitizer_allocator.h"  #include "sanitizer_common/sanitizer_allocator_checks.h"  #include "sanitizer_common/sanitizer_allocator_interface.h" +#include "sanitizer_common/sanitizer_allocator_report.h"  #include "sanitizer_common/sanitizer_errno.h"  #include "msan.h"  #include "msan_allocator.h" @@ -119,7 +120,7 @@ typedef CombinedAllocator<PrimaryAllocator, AllocatorCache,  static Allocator allocator;  static AllocatorCache fallback_allocator_cache; -static SpinMutex fallback_mutex; +static StaticSpinMutex fallback_mutex;  void MsanAllocatorInit() {    SetAllocatorMayReturnNull(common_flags()->allocator_may_return_null); @@ -139,9 +140,11 @@ void MsanThreadLocalMallocStorage::CommitBack() {  static void *MsanAllocate(StackTrace *stack, uptr size, uptr alignment,                            bool zeroise) {    if (size > kMaxAllowedMallocSize) { -    Report("WARNING: MemorySanitizer failed to allocate %p bytes\n", -           (void *)size); -    return Allocator::FailureHandler::OnBadRequest(); +    if (AllocatorMayReturnNull()) { +      Report("WARNING: MemorySanitizer failed to allocate 0x%zx bytes\n", size); +      return nullptr; +    } +    ReportAllocationSizeTooBig(size, kMaxAllowedMallocSize, stack);    }    MsanThread *t = GetCurrentThread();    void *allocated; @@ -153,6 +156,12 @@ static void *MsanAllocate(StackTrace *stack, uptr size, uptr alignment,      AllocatorCache *cache = &fallback_allocator_cache;      allocated = allocator.Allocate(cache, size, alignment);    } +  if (UNLIKELY(!allocated)) { +    SetAllocatorOutOfMemory(); +    if (AllocatorMayReturnNull()) +      return nullptr; +    ReportOutOfMemory(size, stack); +  }    Metadata *meta =        reinterpret_cast<Metadata *>(allocator.GetMetaData(allocated));    meta->requested_size = size; @@ -222,6 +231,15 @@ void *MsanReallocate(StackTrace *stack, void *old_p, uptr new_size,    return new_p;  } +void *MsanCalloc(StackTrace *stack, uptr nmemb, uptr size) { +  if (UNLIKELY(CheckForCallocOverflow(size, nmemb))) { +    if (AllocatorMayReturnNull()) +      return nullptr; +    ReportCallocOverflow(nmemb, size, stack); +  } +  return MsanAllocate(stack, nmemb * size, sizeof(u64), true); +} +  static uptr AllocationSize(const void *p) {    if (!p) return 0;    const void *beg = allocator.GetBlockBegin(p); @@ -235,9 +253,7 @@ void *msan_malloc(uptr size, StackTrace *stack) {  }  void *msan_calloc(uptr nmemb, uptr size, StackTrace *stack) { -  if (UNLIKELY(CheckForCallocOverflow(size, nmemb))) -    return SetErrnoOnNull(Allocator::FailureHandler::OnBadRequest()); -  return SetErrnoOnNull(MsanAllocate(stack, nmemb * size, sizeof(u64), true)); +  return SetErrnoOnNull(MsanCalloc(stack, nmemb, size));  }  void *msan_realloc(void *ptr, uptr size, StackTrace *stack) { @@ -258,7 +274,9 @@ void *msan_pvalloc(uptr size, StackTrace *stack) {    uptr PageSize = GetPageSizeCached();    if (UNLIKELY(CheckForPvallocOverflow(size, PageSize))) {      errno = errno_ENOMEM; -    return Allocator::FailureHandler::OnBadRequest(); +    if (AllocatorMayReturnNull()) +      return nullptr; +    ReportPvallocOverflow(size, stack);    }    // pvalloc(0) should allocate one page.    size = size ? RoundUpTo(size, PageSize) : PageSize; @@ -268,7 +286,9 @@ void *msan_pvalloc(uptr size, StackTrace *stack) {  void *msan_aligned_alloc(uptr alignment, uptr size, StackTrace *stack) {    if (UNLIKELY(!CheckAlignedAllocAlignmentAndSize(alignment, size))) {      errno = errno_EINVAL; -    return Allocator::FailureHandler::OnBadRequest(); +    if (AllocatorMayReturnNull()) +      return nullptr; +    ReportInvalidAlignedAllocAlignment(size, alignment, stack);    }    return SetErrnoOnNull(MsanAllocate(stack, size, alignment, false));  } @@ -276,7 +296,9 @@ void *msan_aligned_alloc(uptr alignment, uptr size, StackTrace *stack) {  void *msan_memalign(uptr alignment, uptr size, StackTrace *stack) {    if (UNLIKELY(!IsPowerOfTwo(alignment))) {      errno = errno_EINVAL; -    return Allocator::FailureHandler::OnBadRequest(); +    if (AllocatorMayReturnNull()) +      return nullptr; +    ReportInvalidAllocationAlignment(alignment, stack);    }    return SetErrnoOnNull(MsanAllocate(stack, size, alignment, false));  } @@ -284,11 +306,13 @@ void *msan_memalign(uptr alignment, uptr size, StackTrace *stack) {  int msan_posix_memalign(void **memptr, uptr alignment, uptr size,                          StackTrace *stack) {    if (UNLIKELY(!CheckPosixMemalignAlignment(alignment))) { -    Allocator::FailureHandler::OnBadRequest(); -    return errno_EINVAL; +    if (AllocatorMayReturnNull()) +      return errno_EINVAL; +    ReportInvalidPosixMemalignAlignment(alignment, stack);    }    void *ptr = MsanAllocate(stack, size, alignment, false);    if (UNLIKELY(!ptr)) +    // OOM error is already taken care of by MsanAllocate.      return errno_ENOMEM;    CHECK(IsAligned((uptr)ptr, alignment));    *memptr = ptr; diff --git a/lib/msan/msan_interceptors.cc b/lib/msan/msan_interceptors.cc index a7fe09b25ffb5..b3429bcf06b52 100644 --- a/lib/msan/msan_interceptors.cc +++ b/lib/msan/msan_interceptors.cc @@ -19,6 +19,7 @@  #include "msan.h"  #include "msan_chained_origin_depot.h"  #include "msan_origin.h" +#include "msan_report.h"  #include "msan_thread.h"  #include "msan_poisoning.h"  #include "sanitizer_common/sanitizer_platform_limits_posix.h" @@ -35,6 +36,7 @@  #include "sanitizer_common/sanitizer_tls_get_addr.h"  #if SANITIZER_NETBSD +#define fstat __fstat50  #define gettimeofday __gettimeofday50  #define getrusage __getrusage50  #endif @@ -58,6 +60,9 @@ DECLARE_REAL(void *, memset, void *dest, int c, uptr n)  // True if this is a nested interceptor.  static THREADLOCAL int in_interceptor_scope; +void __msan_scoped_disable_interceptor_checks() { ++in_interceptor_scope; } +void __msan_scoped_enable_interceptor_checks() { --in_interceptor_scope; } +  struct InterceptorScope {    InterceptorScope() { ++in_interceptor_scope; }    ~InterceptorScope() { --in_interceptor_scope; } @@ -137,15 +142,6 @@ INTERCEPTOR(SIZE_T, fread_unlocked, void *ptr, SIZE_T size, SIZE_T nmemb,  #define MSAN_MAYBE_INTERCEPT_FREAD_UNLOCKED  #endif -INTERCEPTOR(SSIZE_T, readlink, const char *path, char *buf, SIZE_T bufsiz) { -  ENSURE_MSAN_INITED(); -  CHECK_UNPOISONED_STRING(path, 0); -  SSIZE_T res = REAL(readlink)(path, buf, bufsiz); -  if (res > 0) -    __msan_unpoison(buf, res); -  return res; -} -  #if !SANITIZER_NETBSD  INTERCEPTOR(void *, mempcpy, void *dest, const void *src, SIZE_T n) {    return (char *)__msan_memcpy(dest, src, n) + n; @@ -489,39 +485,9 @@ INTERCEPTOR(int, swprintf, void *str, uptr size, void *format, ...) {    return res;  } -INTERCEPTOR(SIZE_T, strxfrm, char *dest, const char *src, SIZE_T n) { -  ENSURE_MSAN_INITED(); -  CHECK_UNPOISONED(src, REAL(strlen)(src) + 1); -  SIZE_T res = REAL(strxfrm)(dest, src, n); -  if (res < n) __msan_unpoison(dest, res + 1); -  return res; -} - -INTERCEPTOR(SIZE_T, strxfrm_l, char *dest, const char *src, SIZE_T n, -            void *loc) { -  ENSURE_MSAN_INITED(); -  CHECK_UNPOISONED(src, REAL(strlen)(src) + 1); -  SIZE_T res = REAL(strxfrm_l)(dest, src, n, loc); -  if (res < n) __msan_unpoison(dest, res + 1); -  return res; -} - -#if SANITIZER_LINUX -INTERCEPTOR(SIZE_T, __strxfrm_l, char *dest, const char *src, SIZE_T n, -            void *loc) { -  ENSURE_MSAN_INITED(); -  CHECK_UNPOISONED(src, REAL(strlen)(src) + 1); -  SIZE_T res = REAL(__strxfrm_l)(dest, src, n, loc); -  if (res < n) __msan_unpoison(dest, res + 1); -  return res; -} -#define MSAN_MAYBE_INTERCEPT___STRXFRM_L INTERCEPT_FUNCTION(__strxfrm_l) -#else -#define MSAN_MAYBE_INTERCEPT___STRXFRM_L -#endif -  #define INTERCEPTOR_STRFTIME_BODY(char_type, ret_type, func, s, ...) \    ENSURE_MSAN_INITED();                                              \ +  InterceptorScope interceptor_scope;                                \    ret_type res = REAL(func)(s, __VA_ARGS__);                         \    if (s) __msan_unpoison(s, sizeof(char_type) * (res + 1));          \    return res; @@ -688,6 +654,19 @@ INTERCEPTOR(int, putenv, char *string) {    return res;  } +#if SANITIZER_FREEBSD || SANITIZER_NETBSD +INTERCEPTOR(int, fstat, int fd, void *buf) { +  ENSURE_MSAN_INITED(); +  int res = REAL(fstat)(fd, buf); +  if (!res) +    __msan_unpoison(buf, __sanitizer::struct_stat_sz); +  return res; +} +#define MSAN_MAYBE_INTERCEPT_FSTAT INTERCEPT_FUNCTION(fstat) +#else +#define MSAN_MAYBE_INTERCEPT_FSTAT +#endif +  #if !SANITIZER_FREEBSD && !SANITIZER_NETBSD  INTERCEPTOR(int, __fxstat, int magic, int fd, void *buf) {    ENSURE_MSAN_INITED(); @@ -772,14 +751,6 @@ INTERCEPTOR(int, socketpair, int domain, int type, int protocol, int sv[2]) {    return res;  } -INTERCEPTOR(char *, fgets, char *s, int size, void *stream) { -  ENSURE_MSAN_INITED(); -  char *res = REAL(fgets)(s, size, stream); -  if (res) -    __msan_unpoison(s, REAL(strlen)(s) + 1); -  return res; -} -  #if !SANITIZER_FREEBSD && !SANITIZER_NETBSD  INTERCEPTOR(char *, fgets_unlocked, char *s, int size, void *stream) {    ENSURE_MSAN_INITED(); @@ -964,11 +935,9 @@ void __sanitizer_dtor_callback(const void *data, uptr size) {    }  } -INTERCEPTOR(void *, mmap, void *addr, SIZE_T length, int prot, int flags, -            int fd, OFF_T offset) { -  if (msan_init_is_running) -    return REAL(mmap)(addr, length, prot, flags, fd, offset); -  ENSURE_MSAN_INITED(); +template <class Mmap> +static void *mmap_interceptor(Mmap real_mmap, void *addr, SIZE_T length, +                              int prot, int flags, int fd, OFF64_T offset) {    if (addr && !MEM_IS_APP(addr)) {      if (flags & map_fixed) {        errno = errno_EINVAL; @@ -977,34 +946,11 @@ INTERCEPTOR(void *, mmap, void *addr, SIZE_T length, int prot, int flags,        addr = nullptr;      }    } -  void *res = REAL(mmap)(addr, length, prot, flags, fd, offset); -  if (res != (void*)-1) -    __msan_unpoison(res, RoundUpTo(length, GetPageSize())); +  void *res = real_mmap(addr, length, prot, flags, fd, offset); +  if (res != (void *)-1) __msan_unpoison(res, RoundUpTo(length, GetPageSize()));    return res;  } -#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD -INTERCEPTOR(void *, mmap64, void *addr, SIZE_T length, int prot, int flags, -            int fd, OFF64_T offset) { -  ENSURE_MSAN_INITED(); -  if (addr && !MEM_IS_APP(addr)) { -    if (flags & map_fixed) { -      errno = errno_EINVAL; -      return (void *)-1; -    } else { -      addr = nullptr; -    } -  } -  void *res = REAL(mmap64)(addr, length, prot, flags, fd, offset); -  if (res != (void*)-1) -    __msan_unpoison(res, RoundUpTo(length, GetPageSize())); -  return res; -} -#define MSAN_MAYBE_INTERCEPT_MMAP64 INTERCEPT_FUNCTION(mmap64) -#else -#define MSAN_MAYBE_INTERCEPT_MMAP64 -#endif -  INTERCEPTOR(int, getrusage, int who, void *usage) {    ENSURE_MSAN_INITED();    int res = REAL(getrusage)(who, usage); @@ -1175,6 +1121,9 @@ INTERCEPTOR(int, fork, void) {    return pid;  } +// NetBSD ships with openpty(3) in -lutil, that needs to be prebuilt explicitly +// with MSan. +#if SANITIZER_LINUX  INTERCEPTOR(int, openpty, int *amaster, int *aslave, char *name,              const void *termp, const void *winp) {    ENSURE_MSAN_INITED(); @@ -1186,7 +1135,14 @@ INTERCEPTOR(int, openpty, int *amaster, int *aslave, char *name,    }    return res;  } +#define MSAN_MAYBE_INTERCEPT_OPENPTY INTERCEPT_FUNCTION(openpty) +#else +#define MSAN_MAYBE_INTERCEPT_OPENPTY +#endif +// NetBSD ships with forkpty(3) in -lutil, that needs to be prebuilt explicitly +// with MSan. +#if SANITIZER_LINUX  INTERCEPTOR(int, forkpty, int *amaster, char *name, const void *termp,              const void *winp) {    ENSURE_MSAN_INITED(); @@ -1196,6 +1152,10 @@ INTERCEPTOR(int, forkpty, int *amaster, char *name, const void *termp,      __msan_unpoison(amaster, sizeof(*amaster));    return res;  } +#define MSAN_MAYBE_INTERCEPT_FORKPTY INTERCEPT_FUNCTION(forkpty) +#else +#define MSAN_MAYBE_INTERCEPT_FORKPTY +#endif  struct MSanInterceptorContext {    bool in_interceptor_scope; @@ -1308,6 +1268,12 @@ int OnExit() {      __msan_unpoison(to + size, 1);                          \    } while (false) +#define COMMON_INTERCEPTOR_MMAP_IMPL(ctx, mmap, addr, length, prot, flags, fd, \ +                                     offset)                                   \ +  do {                                                                         \ +    return mmap_interceptor(REAL(mmap), addr, sz, prot, flags, fd, off);       \ +  } while (false) +  #include "sanitizer_common/sanitizer_platform_interceptors.h"  #include "sanitizer_common/sanitizer_common_interceptors.inc" @@ -1321,6 +1287,7 @@ static int sigaction_impl(int signo, const __sanitizer_sigaction *act,  #define SIGNAL_INTERCEPTOR_SIGNAL_IMPL(func, signo, handler) \    {                                                          \      handler = signal_impl(signo, handler);                   \ +    InterceptorScope interceptor_scope;                      \      return REAL(func)(signo, handler);                       \    } @@ -1387,6 +1354,7 @@ static uptr signal_impl(int signo, uptr cb) {    } while (false)  #define COMMON_SYSCALL_POST_WRITE_RANGE(p, s) __msan_unpoison(p, s)  #include "sanitizer_common/sanitizer_common_syscalls.inc" +#include "sanitizer_common/sanitizer_syscalls_netbsd.inc"  struct dlinfo {    char *dli_fname; @@ -1555,8 +1523,6 @@ void InitializeInterceptors() {    InitializeCommonInterceptors();    InitializeSignalInterceptors(); -  INTERCEPT_FUNCTION(mmap); -  MSAN_MAYBE_INTERCEPT_MMAP64;    INTERCEPT_FUNCTION(posix_memalign);    MSAN_MAYBE_INTERCEPT_MEMALIGN;    MSAN_MAYBE_INTERCEPT___LIBC_MEMALIGN; @@ -1573,7 +1539,6 @@ void InitializeInterceptors() {    MSAN_MAYBE_INTERCEPT_MALLOC_STATS;    INTERCEPT_FUNCTION(fread);    MSAN_MAYBE_INTERCEPT_FREAD_UNLOCKED; -  INTERCEPT_FUNCTION(readlink);    INTERCEPT_FUNCTION(memccpy);    MSAN_MAYBE_INTERCEPT_MEMPCPY;    INTERCEPT_FUNCTION(bcopy); @@ -1611,9 +1576,6 @@ void InitializeInterceptors() {    INTERCEPT_FUNCTION(vswprintf);    INTERCEPT_FUNCTION(swprintf);  #endif -  INTERCEPT_FUNCTION(strxfrm); -  INTERCEPT_FUNCTION(strxfrm_l); -  MSAN_MAYBE_INTERCEPT___STRXFRM_L;    INTERCEPT_FUNCTION(strftime);    INTERCEPT_FUNCTION(strftime_l);    MSAN_MAYBE_INTERCEPT___STRFTIME_L; @@ -1633,6 +1595,7 @@ void InitializeInterceptors() {    INTERCEPT_FUNCTION(putenv);    INTERCEPT_FUNCTION(gettimeofday);    MSAN_MAYBE_INTERCEPT_FCVT; +  MSAN_MAYBE_INTERCEPT_FSTAT;    MSAN_MAYBE_INTERCEPT___FXSTAT;    MSAN_INTERCEPT_FSTATAT;    MSAN_MAYBE_INTERCEPT___FXSTAT64; @@ -1640,7 +1603,6 @@ void InitializeInterceptors() {    INTERCEPT_FUNCTION(pipe);    INTERCEPT_FUNCTION(pipe2);    INTERCEPT_FUNCTION(socketpair); -  INTERCEPT_FUNCTION(fgets);    MSAN_MAYBE_INTERCEPT_FGETS_UNLOCKED;    INTERCEPT_FUNCTION(getrlimit);    MSAN_MAYBE_INTERCEPT_GETRLIMIT64; @@ -1670,8 +1632,8 @@ void InitializeInterceptors() {    INTERCEPT_FUNCTION(__cxa_atexit);    INTERCEPT_FUNCTION(shmat);    INTERCEPT_FUNCTION(fork); -  INTERCEPT_FUNCTION(openpty); -  INTERCEPT_FUNCTION(forkpty); +  MSAN_MAYBE_INTERCEPT_OPENPTY; +  MSAN_MAYBE_INTERCEPT_FORKPTY;    inited = 1;  } diff --git a/lib/msan/msan_interface_internal.h b/lib/msan/msan_interface_internal.h index c6990db243c11..9a67cbc9b5f8b 100644 --- a/lib/msan/msan_interface_internal.h +++ b/lib/msan/msan_interface_internal.h @@ -174,6 +174,12 @@ void __msan_set_death_callback(void (*callback)(void));  SANITIZER_INTERFACE_ATTRIBUTE  void __msan_copy_shadow(void *dst, const void *src, uptr size); + +SANITIZER_INTERFACE_ATTRIBUTE +void __msan_scoped_disable_interceptor_checks(); + +SANITIZER_INTERFACE_ATTRIBUTE +void __msan_scoped_enable_interceptor_checks();  }  // extern "C"  #endif  // MSAN_INTERFACE_INTERNAL_H diff --git a/lib/msan/msan_linux.cc b/lib/msan/msan_linux.cc index 4e6321fcb9187..385a650c4afc6 100644 --- a/lib/msan/msan_linux.cc +++ b/lib/msan/msan_linux.cc @@ -16,6 +16,7 @@  #if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD  #include "msan.h" +#include "msan_report.h"  #include "msan_thread.h"  #include <elf.h> @@ -142,7 +143,7 @@ bool InitShadow(bool init_origins) {      if (map) {        if (!CheckMemoryRangeAvailability(start, size))          return false; -      if ((uptr)MmapFixedNoReserve(start, size, kMemoryLayout[i].name) != start) +      if (!MmapFixedNoReserve(start, size, kMemoryLayout[i].name))          return false;        if (common_flags()->use_madv_dontdump)          DontDumpShadowMemory(start, size); diff --git a/lib/msan/msan_new_delete.cc b/lib/msan/msan_new_delete.cc index 5cc76e4bc08c3..a0959aec5eb0c 100644 --- a/lib/msan/msan_new_delete.cc +++ b/lib/msan/msan_new_delete.cc @@ -15,6 +15,7 @@  #include "msan.h"  #include "interception/interception.h"  #include "sanitizer_common/sanitizer_allocator.h" +#include "sanitizer_common/sanitizer_allocator_report.h"  #if MSAN_REPLACE_OPERATORS_NEW_AND_DELETE @@ -33,12 +34,12 @@ namespace std {  #define OPERATOR_NEW_BODY(nothrow) \    GET_MALLOC_STACK_TRACE; \    void *res = msan_malloc(size, &stack);\ -  if (!nothrow && UNLIKELY(!res)) DieOnFailure::OnOOM();\ +  if (!nothrow && UNLIKELY(!res)) ReportOutOfMemory(size, &stack);\    return res  #define OPERATOR_NEW_BODY_ALIGN(nothrow) \    GET_MALLOC_STACK_TRACE;\    void *res = msan_memalign((uptr)align, size, &stack);\ -  if (!nothrow && UNLIKELY(!res)) DieOnFailure::OnOOM();\ +  if (!nothrow && UNLIKELY(!res)) ReportOutOfMemory(size, &stack);\    return res;  INTERCEPTOR_ATTRIBUTE diff --git a/lib/msan/msan_poisoning.cc b/lib/msan/msan_poisoning.cc index 92134f6a15b81..7420d946928be 100644 --- a/lib/msan/msan_poisoning.cc +++ b/lib/msan/msan_poisoning.cc @@ -139,7 +139,8 @@ void SetShadow(const void *ptr, uptr size, u8 value) {        if (page_end != shadow_end) {          REAL(memset)((void *)page_end, 0, shadow_end - page_end);        } -      MmapFixedNoReserve(page_beg, page_end - page_beg); +      if (!MmapFixedNoReserve(page_beg, page_end - page_beg)) +        Die();      }    }  } diff --git a/lib/msan/msan_report.cc b/lib/msan/msan_report.cc index 28c9bbabb3e9f..2f0cc8d370ee7 100644 --- a/lib/msan/msan_report.cc +++ b/lib/msan/msan_report.cc @@ -15,6 +15,7 @@  #include "msan.h"  #include "msan_chained_origin_depot.h"  #include "msan_origin.h" +#include "msan_report.h"  #include "sanitizer_common/sanitizer_allocator_internal.h"  #include "sanitizer_common/sanitizer_common.h"  #include "sanitizer_common/sanitizer_flags.h" @@ -30,8 +31,8 @@ namespace __msan {  class Decorator: public __sanitizer::SanitizerCommonDecorator {   public:    Decorator() : SanitizerCommonDecorator() { } -  const char *Origin()     { return Magenta(); } -  const char *Name()   { return Green(); } +  const char *Origin() const { return Magenta(); } +  const char *Name() const { return Green(); }  };  static void DescribeStackOrigin(const char *so, uptr pc) { diff --git a/lib/msan/msan_report.h b/lib/msan/msan_report.h new file mode 100644 index 0000000000000..73840e417505a --- /dev/null +++ b/lib/msan/msan_report.h @@ -0,0 +1,34 @@ +//===-- msan_report.h -------------------------------------------*- C++ -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file is a part of MemorySanitizer. MSan-private header for error +/// reporting functions. +/// +//===----------------------------------------------------------------------===// + +#ifndef MSAN_REPORT_H +#define MSAN_REPORT_H + +#include "sanitizer_common/sanitizer_internal_defs.h" +#include "sanitizer_common/sanitizer_stacktrace.h" + +namespace __msan { + +void ReportUMR(StackTrace *stack, u32 origin); +void ReportExpectedUMRNotFound(StackTrace *stack); +void ReportStats(); +void ReportAtExitStatistics(); +void DescribeMemoryRange(const void *x, uptr size); +void ReportUMRInsideAddressRange(const char *what, const void *start, uptr size, +                                 uptr offset); + +}  // namespace __msan + +#endif  // MSAN_REPORT_H diff --git a/lib/msan/tests/CMakeLists.txt b/lib/msan/tests/CMakeLists.txt index b460231783b87..e9f4e34bfe617 100644 --- a/lib/msan/tests/CMakeLists.txt +++ b/lib/msan/tests/CMakeLists.txt @@ -37,6 +37,9 @@ set(MSAN_UNITTEST_COMMON_CFLAGS    -Werror=sign-compare    -Wno-gnu-zero-variadic-macro-arguments  ) +# Remove -stdlib= which is unused when passing -nostdinc++. +string(REGEX REPLACE "-stdlib=[a-zA-Z+]*" "" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS}) +  set(MSAN_UNITTEST_INSTRUMENTED_CFLAGS    ${MSAN_UNITTEST_COMMON_CFLAGS}    -fsanitize=memory @@ -106,7 +109,7 @@ macro(add_msan_tests_for_arch arch kind cflags)                     DEPS ${MSAN_INST_LOADABLE_OBJECTS})    set(MSAN_TEST_OBJECTS ${MSAN_INST_TEST_OBJECTS} ${MSAN_INST_GTEST}) -  set(MSAN_TEST_DEPS ${MSAN_TEST_OBJECTS} libcxx_msan_${arch} +  set(MSAN_TEST_DEPS ${MSAN_TEST_OBJECTS} libcxx_msan_${arch}-build                       ${MSAN_LOADABLE_SO})    if(NOT COMPILER_RT_STANDALONE_BUILD)      list(APPEND MSAN_TEST_DEPS msan) @@ -128,7 +131,8 @@ if(COMPILER_RT_CAN_EXECUTE_TESTS AND COMPILER_RT_LIBCXX_PATH)      set(LIBCXX_PREFIX ${CMAKE_CURRENT_BINARY_DIR}/../libcxx_msan_${arch})      add_custom_libcxx(libcxx_msan_${arch} ${LIBCXX_PREFIX}        DEPS ${MSAN_RUNTIME_LIBRARIES} -      CFLAGS ${MSAN_LIBCXX_CFLAGS} ${TARGET_CFLAGS}) +      CFLAGS ${MSAN_LIBCXX_CFLAGS} ${TARGET_CFLAGS} +      USE_TOOLCHAIN)      set(MSAN_LIBCXX_SO ${LIBCXX_PREFIX}/lib/libc++.so)      add_msan_tests_for_arch(${arch} "" "") diff --git a/lib/msan/tests/msan_test.cc b/lib/msan/tests/msan_test.cc index 074a2f609eda3..29260f16e704e 100644 --- a/lib/msan/tests/msan_test.cc +++ b/lib/msan/tests/msan_test.cc @@ -65,16 +65,15 @@ int shmdt(const void *);  #include <sys/ipc.h>  #include <sys/shm.h> -#if !defined(__FreeBSD__) -# include <malloc.h> -# include <sys/sysinfo.h> -# include <sys/vfs.h> -# include <mntent.h> -# include <netinet/ether.h> -# if defined(__linux__) -#  include <sys/uio.h> -# endif -#else +#if defined(__NetBSD__) +# include <signal.h> +# include <netinet/in.h> +# include <sys/uio.h> +# include <sys/mount.h> +# include <sys/sysctl.h> +# include <net/if.h> +# include <net/if_ether.h> +#elif defined(__FreeBSD__)  # include <signal.h>  # include <netinet/in.h>  # include <pthread_np.h> @@ -90,6 +89,15 @@ extern "C" {  // ordinary function, we can declare it here to complete the tests.  void *mempcpy(void *dest, const void *src, size_t n);  } +#else +# include <malloc.h> +# include <sys/sysinfo.h> +# include <sys/vfs.h> +# include <mntent.h> +# include <netinet/ether.h> +# if defined(__linux__) +#  include <sys/uio.h> +# endif  #endif  #if defined(__i386__) || defined(__x86_64__) @@ -103,8 +111,7 @@ void *mempcpy(void *dest, const void *src, size_t n);  # include <immintrin.h>  #endif -// On FreeBSD procfs is not enabled by default. -#if defined(__FreeBSD__) +#if defined(__FreeBSD__) || defined(__NetBSD__)  # define FILE_TO_READ "/bin/cat"  # define DIR_TO_READ "/bin"  # define SUBFILE_TO_READ "cat" @@ -717,6 +724,13 @@ TEST(MemorySanitizer, readlink) {    delete [] x;  } +TEST(MemorySanitizer, readlinkat) { +  char *x = new char[1000]; +  readlinkat(AT_FDCWD, SYMLINK_TO_READ, x, 1000); +  EXPECT_NOT_POISONED(x[0]); +  delete[] x; +} +  TEST(MemorySanitizer, stat) {    struct stat* st = new struct stat;    int res = stat(FILE_TO_READ, st); @@ -738,6 +752,7 @@ TEST(MemorySanitizer, fstatat) {    close(dirfd);  } +#if !defined(__NetBSD__)  TEST(MemorySanitizer, statfs) {    struct statfs st;    int res = statfs("/", &st); @@ -746,6 +761,7 @@ TEST(MemorySanitizer, statfs) {    EXPECT_NOT_POISONED(st.f_bfree);    EXPECT_NOT_POISONED(st.f_namelen);  } +#endif  TEST(MemorySanitizer, statvfs) {    struct statvfs st; @@ -822,8 +838,7 @@ TEST(MemorySanitizer, poll) {    close(pipefd[1]);  } -// There is no ppoll() on FreeBSD. -#if !defined (__FreeBSD__) +#if !defined (__FreeBSD__) && !defined (__NetBSD__)  TEST(MemorySanitizer, ppoll) {    int* pipefd = new int[2];    int res = pipe(pipefd); @@ -1161,6 +1176,7 @@ TEST(MemorySanitizer, gethostbyaddr) {    EXPECT_HOSTENT_NOT_POISONED(he);  } +#if !defined(__NetBSD__)  TEST(MemorySanitizer, gethostent_r) {    char buf[2000];    struct hostent he; @@ -1173,7 +1189,9 @@ TEST(MemorySanitizer, gethostent_r) {    EXPECT_HOSTENT_NOT_POISONED(result);    EXPECT_NOT_POISONED(err);  } +#endif +#if !defined(__NetBSD__)  TEST(MemorySanitizer, gethostbyname_r) {    char buf[2000];    struct hostent he; @@ -1186,7 +1204,9 @@ TEST(MemorySanitizer, gethostbyname_r) {    EXPECT_HOSTENT_NOT_POISONED(result);    EXPECT_NOT_POISONED(err);  } +#endif +#if !defined(__NetBSD__)  TEST(MemorySanitizer, gethostbyname_r_bad_host_name) {    char buf[2000];    struct hostent he; @@ -1196,7 +1216,9 @@ TEST(MemorySanitizer, gethostbyname_r_bad_host_name) {    ASSERT_EQ((struct hostent *)0, result);    EXPECT_NOT_POISONED(err);  } +#endif +#if !defined(__NetBSD__)  TEST(MemorySanitizer, gethostbyname_r_erange) {    char buf[5];    struct hostent he; @@ -1206,7 +1228,9 @@ TEST(MemorySanitizer, gethostbyname_r_erange) {    ASSERT_EQ(ERANGE, errno);    EXPECT_NOT_POISONED(err);  } +#endif +#if !defined(__NetBSD__)  TEST(MemorySanitizer, gethostbyname2_r) {    char buf[2000];    struct hostent he; @@ -1220,7 +1244,9 @@ TEST(MemorySanitizer, gethostbyname2_r) {    EXPECT_HOSTENT_NOT_POISONED(result);    EXPECT_NOT_POISONED(err);  } +#endif +#if !defined(__NetBSD__)  TEST(MemorySanitizer, gethostbyaddr_r) {    char buf[2000];    struct hostent he; @@ -1236,6 +1262,7 @@ TEST(MemorySanitizer, gethostbyaddr_r) {    EXPECT_HOSTENT_NOT_POISONED(result);    EXPECT_NOT_POISONED(err);  } +#endif  TEST(MemorySanitizer, getsockopt) {    int sock = socket(AF_UNIX, SOCK_STREAM, 0); @@ -1262,8 +1289,7 @@ TEST(MemorySanitizer, getcwd_gnu) {    free(res);  } -// There's no get_current_dir_name() on FreeBSD. -#if !defined(__FreeBSD__) +#if !defined(__FreeBSD__) && !defined(__NetBSD__)  TEST(MemorySanitizer, get_current_dir_name) {    char* res = get_current_dir_name();    ASSERT_TRUE(res != NULL); @@ -1281,8 +1307,7 @@ TEST(MemorySanitizer, shmctl) {    ASSERT_GT(res, -1);    EXPECT_NOT_POISONED(ds); -  // FreeBSD does not support shmctl(IPC_INFO) and shmctl(SHM_INFO). -#if !defined(__FreeBSD__) +#if !defined(__FreeBSD__) && !defined(__NetBSD__)    struct shminfo si;    res = shmctl(id, IPC_INFO, (struct shmid_ds *)&si);    ASSERT_GT(res, -1); @@ -1330,8 +1355,7 @@ TEST(MemorySanitizer, shmat) {    ASSERT_GT(res, -1);  } -// There's no random_r() on FreeBSD. -#if !defined(__FreeBSD__) +#if !defined(__FreeBSD__) && !defined(__NetBSD__)  TEST(MemorySanitizer, random_r) {    int32_t x;    char z[64]; @@ -1411,8 +1435,7 @@ TEST(MemorySanitizer, realpath_null) {    free(res);  } -// There's no canonicalize_file_name() on FreeBSD. -#if !defined(__FreeBSD__) +#if !defined(__FreeBSD__) && !defined(__NetBSD__)  TEST(MemorySanitizer, canonicalize_file_name) {    const char* relpath = ".";    char* res = canonicalize_file_name(relpath); @@ -1870,8 +1893,7 @@ TEST(MemorySanitizer, modfl) {    EXPECT_NOT_POISONED(y);  } -// There's no sincos() on FreeBSD. -#if !defined(__FreeBSD__) +#if !defined(__FreeBSD__) && !defined(__NetBSD__)  TEST(MemorySanitizer, sincos) {    double s, c;    sincos(0.2, &s, &c); @@ -1880,8 +1902,7 @@ TEST(MemorySanitizer, sincos) {  }  #endif -// There's no sincosf() on FreeBSD. -#if !defined(__FreeBSD__) +#if !defined(__FreeBSD__) && !defined(__NetBSD__)  TEST(MemorySanitizer, sincosf) {    float s, c;    sincosf(0.2, &s, &c); @@ -1890,8 +1911,7 @@ TEST(MemorySanitizer, sincosf) {  }  #endif -// There's no sincosl() on FreeBSD. -#if !defined(__FreeBSD__) +#if !defined(__FreeBSD__) && !defined(__NetBSD__)  TEST(MemorySanitizer, sincosl) {    long double s, c;    sincosl(0.2, &s, &c); @@ -1953,8 +1973,7 @@ TEST(MemorySanitizer, lgammaf_r) {    EXPECT_NOT_POISONED(sgn);  } -// There's no lgammal_r() on FreeBSD. -#if !defined(__FreeBSD__) +#if !defined(__FreeBSD__) && !defined(__NetBSD__)  TEST(MemorySanitizer, lgammal_r) {    int sgn;    long double res = lgammal_r(1.1, &sgn); @@ -1963,8 +1982,7 @@ TEST(MemorySanitizer, lgammal_r) {  }  #endif -// There's no drand48_r() on FreeBSD. -#if !defined(__FreeBSD__) +#if !defined(__FreeBSD__) && !defined(__NetBSD__)  TEST(MemorySanitizer, drand48_r) {    struct drand48_data buf;    srand48_r(0, &buf); @@ -1974,8 +1992,7 @@ TEST(MemorySanitizer, drand48_r) {  }  #endif -// There's no lrand48_r() on FreeBSD. -#if !defined(__FreeBSD__) +#if !defined(__FreeBSD__) && !defined(__NetBSD__)  TEST(MemorySanitizer, lrand48_r) {    struct drand48_data buf;    srand48_r(0, &buf); @@ -2260,7 +2277,7 @@ TEST(MemorySanitizer, localtime_r) {    EXPECT_NE(0U, strlen(time.tm_zone));  } -#if !defined(__FreeBSD__) +#if !defined(__FreeBSD__) && !defined(__NetBSD__)  /* Creates a temporary file with contents similar to /etc/fstab to be used     with getmntent{_r}.  */  class TempFstabFile { @@ -2298,8 +2315,7 @@ class TempFstabFile {  };  #endif -// There's no getmntent() on FreeBSD. -#if !defined(__FreeBSD__) +#if !defined(__FreeBSD__) && !defined(__NetBSD__)  TEST(MemorySanitizer, getmntent) {    TempFstabFile fstabtmp;    ASSERT_TRUE(fstabtmp.Create()); @@ -2317,8 +2333,7 @@ TEST(MemorySanitizer, getmntent) {  }  #endif -// There's no getmntent_r() on FreeBSD. -#if !defined(__FreeBSD__) +#if !defined(__FreeBSD__) && !defined(__NetBSD__)  TEST(MemorySanitizer, getmntent_r) {    TempFstabFile fstabtmp;    ASSERT_TRUE(fstabtmp.Create()); @@ -2338,6 +2353,7 @@ TEST(MemorySanitizer, getmntent_r) {  }  #endif +#if !defined(__NetBSD__)  TEST(MemorySanitizer, ether) {    const char *asc = "11:22:33:44:55:66";    struct ether_addr *paddr = ether_aton(asc); @@ -2356,6 +2372,7 @@ TEST(MemorySanitizer, ether) {    ASSERT_EQ(s, buf);    ASSERT_NE(0U, strlen(buf));  } +#endif  TEST(MemorySanitizer, mmap) {    const int size = 4096; @@ -2376,8 +2393,7 @@ TEST(MemorySanitizer, mmap) {    }  } -// There's no fcvt() on FreeBSD. -#if !defined(__FreeBSD__) +#if !defined(__FreeBSD__) && !defined(__NetBSD__)  // FIXME: enable and add ecvt.  // FIXME: check why msandr does nt handle fcvt.  TEST(MemorySanitizer, fcvt) { @@ -2395,8 +2411,7 @@ TEST(MemorySanitizer, fcvt) {  }  #endif -// There's no fcvt_long() on FreeBSD. -#if !defined(__FreeBSD__) +#if !defined(__FreeBSD__) && !defined(__NetBSD__)  TEST(MemorySanitizer, fcvt_long) {    int a, b;    break_optimization(&a); @@ -2471,11 +2486,15 @@ void SigactionHandler(int signo, siginfo_t* si, void* uc) {    ASSERT_TRUE(si != NULL);    EXPECT_NOT_POISONED(si->si_errno);    EXPECT_NOT_POISONED(si->si_pid); -#if __linux__ -# if defined(__x86_64__) +#ifdef _UC_MACHINE_PC +  EXPECT_NOT_POISONED(_UC_MACHINE_PC((ucontext_t*)uc)); +#else +# if __linux__ +#  if defined(__x86_64__)    EXPECT_NOT_POISONED(((ucontext_t*)uc)->uc_mcontext.gregs[REG_RIP]); -# elif defined(__i386__) +#  elif defined(__i386__)    EXPECT_NOT_POISONED(((ucontext_t*)uc)->uc_mcontext.gregs[REG_EIP]); +#  endif  # endif  #endif    ++cnt; @@ -3005,7 +3024,9 @@ TEST(MemorySanitizer, LongStruct) {    EXPECT_POISONED(s2.a8);  } -#ifdef __GLIBC__ +#if defined(__FreeBSD__) || defined(__NetBSD__) +#define MSAN_TEST_PRLIMIT 0 +#elif defined(__GLIBC__)  #define MSAN_TEST_PRLIMIT __GLIBC_PREREQ(2, 13)  #else  #define MSAN_TEST_PRLIMIT 1 @@ -3056,9 +3077,13 @@ TEST(MemorySanitizer, getrusage) {    EXPECT_NOT_POISONED(usage.ru_nivcsw);  } -#if defined(__FreeBSD__) +#if defined(__FreeBSD__) || defined(__NetBSD__)  static void GetProgramPath(char *buf, size_t sz) { +#if defined(__FreeBSD__)    int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 }; +#elif defined(__NetBSD__) +  int mib[4] = { CTL_KERN, KERN_PROC_ARGS, -1, KERN_PROC_PATHNAME}; +#endif    int res = sysctl(mib, 4, buf, &sz, NULL, 0);    ASSERT_EQ(0, res);  } @@ -3180,8 +3205,7 @@ TEST(MemorySanitizer, dlopenFailed) {  #endif // MSAN_TEST_DISABLE_DLOPEN -// There's no sched_getaffinity() on FreeBSD. -#if !defined(__FreeBSD__) +#if !defined(__FreeBSD__) && !defined(__NetBSD__)  TEST(MemorySanitizer, sched_getaffinity) {    cpu_set_t mask;    int res = sched_getaffinity(getpid(), sizeof(mask), &mask); @@ -3329,12 +3353,14 @@ TEST(MemorySanitizer, pthread_attr_get) {      EXPECT_NOT_POISONED(v);      EXPECT_NOT_POISONED(w);    } +#if !defined(__NetBSD__)    {      cpu_set_t v;      res = pthread_attr_getaffinity_np(&attr, sizeof(v), &v);      ASSERT_EQ(0, res);      EXPECT_NOT_POISONED(v);    } +#endif    res = pthread_attr_destroy(&attr);    ASSERT_EQ(0, res);  } @@ -3426,8 +3452,7 @@ TEST(MemorySanitizer, posix_memalign) {    free(p);  } -// There's no memalign() on FreeBSD. -#if !defined(__FreeBSD__) +#if !defined(__FreeBSD__) && !defined(__NetBSD__)  TEST(MemorySanitizer, memalign) {    void *p = memalign(4096, 13);    EXPECT_EQ(0U, (uintptr_t)p % 4096); @@ -3442,8 +3467,7 @@ TEST(MemorySanitizer, valloc) {    free(a);  } -// There's no pvalloc() on FreeBSD. -#if !defined(__FreeBSD__) +#if !defined(__FreeBSD__) && !defined(__NetBSD__)  TEST(MemorySanitizer, pvalloc) {    uintptr_t PageSize = GetPageSize();    void *p = pvalloc(PageSize + 100); @@ -3500,8 +3524,7 @@ TEST(MemorySanitizer, gethostname) {    EXPECT_NOT_POISONED(strlen(buf));  } -// There's no sysinfo() on FreeBSD. -#if !defined(__FreeBSD__) +#if !defined(__FreeBSD__) && !defined(__NetBSD__)  TEST(MemorySanitizer, sysinfo) {    struct sysinfo info;    int res = sysinfo(&info); @@ -3598,8 +3621,7 @@ TEST(MemorySanitizer, getpwent_r) {    EXPECT_NOT_POISONED(pwdres);  } -// There's no fgetpwent() on FreeBSD. -#if !defined(__FreeBSD__) +#if !defined(__FreeBSD__) && !defined(__NetBSD__)  TEST(MemorySanitizer, fgetpwent) {    FILE *fp = fopen("/etc/passwd", "r");    struct passwd *p = fgetpwent(fp); @@ -3622,8 +3644,7 @@ TEST(MemorySanitizer, getgrent) {    EXPECT_NOT_POISONED(p->gr_gid);  } -// There's no fgetgrent() on FreeBSD. -#if !defined(__FreeBSD__) +#if !defined(__FreeBSD__) && !defined(__NetBSD__)  TEST(MemorySanitizer, fgetgrent) {    FILE *fp = fopen("/etc/group", "r");    struct group *grp = fgetgrent(fp); @@ -3654,7 +3675,6 @@ TEST(MemorySanitizer, getgrent_r) {    EXPECT_NOT_POISONED(grpres);  } -// There's no fgetgrent_r() on FreeBSD and NetBSD.  #if !defined(__FreeBSD__) && !defined(__NetBSD__)  TEST(MemorySanitizer, fgetgrent_r) {    FILE *fp = fopen("/etc/group", "r"); @@ -4037,7 +4057,6 @@ typedef U4 V2x32 __attribute__((__vector_size__(8)));  typedef U2 V4x16 __attribute__((__vector_size__(8)));  typedef U1 V8x8 __attribute__((__vector_size__(8))); -  V8x16 shift_sse2_left_scalar(V8x16 x, U4 y) {    return _mm_slli_epi16(x, y);  } @@ -4385,12 +4404,14 @@ void MemCpyTest() {    EXPECT_POISONED_O(y[N/2], ox);    EXPECT_POISONED_O(y[N-1], ox);    EXPECT_NOT_POISONED(x); +#if !defined(__NetBSD__)    void *res = mempcpy(q, x, N * sizeof(T));    ASSERT_EQ(q + N, res);    EXPECT_POISONED_O(q[0], ox);    EXPECT_POISONED_O(q[N/2], ox);    EXPECT_POISONED_O(q[N-1], ox);    EXPECT_NOT_POISONED(x); +#endif    memmove(z, x, N * sizeof(T));    EXPECT_POISONED_O(z[0], ox);    EXPECT_POISONED_O(z[N/2], ox); diff --git a/lib/profile/CMakeLists.txt b/lib/profile/CMakeLists.txt index 91d67ec365c5a..488673dd2c227 100644 --- a/lib/profile/CMakeLists.txt +++ b/lib/profile/CMakeLists.txt @@ -59,16 +59,25 @@ set(PROFILE_SOURCES    InstrProfilingNameVar.c    InstrProfilingWriter.c    InstrProfilingPlatformDarwin.c +  InstrProfilingPlatformFuchsia.c    InstrProfilingPlatformLinux.c    InstrProfilingPlatformOther.c    InstrProfilingRuntime.cc    InstrProfilingUtil.c) +set(PROFILE_HEADERS +  InstrProfData.inc +  InstrProfiling.h +  InstrProfilingInternal.h +  InstrProfilingPort.h +  InstrProfilingUtil.h +  WindowsMMap.h) +  if(WIN32)      list(APPEND PROFILE_SOURCES WindowsMMap.c)  endif() -if(UNIX) +if(FUCHSIA OR UNIX)   set(EXTRA_FLAGS       -fPIC       -Wno-pedantic) @@ -104,6 +113,7 @@ if(APPLE)      ARCHS ${PROFILE_SUPPORTED_ARCH}      CFLAGS ${EXTRA_FLAGS}      SOURCES ${PROFILE_SOURCES} +    ADDITIONAL_HEADERS ${PROFILE_HEADERS}      PARENT_TARGET profile)  else()    add_compiler_rt_runtime(clang_rt.profile @@ -111,5 +121,6 @@ else()      ARCHS ${PROFILE_SUPPORTED_ARCH}      CFLAGS ${EXTRA_FLAGS}      SOURCES ${PROFILE_SOURCES} +    ADDITIONAL_HEADERS ${PROFILE_HEADERS}      PARENT_TARGET profile)  endif() diff --git a/lib/profile/GCDAProfiling.c b/lib/profile/GCDAProfiling.c index ef299f002e205..cbca365510b50 100644 --- a/lib/profile/GCDAProfiling.c +++ b/lib/profile/GCDAProfiling.c @@ -20,6 +20,8 @@  |*  \*===----------------------------------------------------------------------===*/ +#if !defined(__Fuchsia__) +  #include <errno.h>  #include <fcntl.h>  #include <stdio.h> @@ -79,38 +81,83 @@ static FILE *output_file = NULL;   * Buffer that we write things into.   */  #define WRITE_BUFFER_SIZE (128 * 1024) -static char *write_buffer = NULL; +static unsigned char *write_buffer = NULL;  static uint64_t cur_buffer_size = 0;  static uint64_t cur_pos = 0;  static uint64_t file_size = 0;  static int new_file = 0;  static int fd = -1; -/* - * A list of functions to write out the data. - */ -typedef void (*writeout_fn)(); +typedef void (*fn_ptr)(); + +typedef void* dynamic_object_id; +// The address of this variable identifies a given dynamic object. +static dynamic_object_id current_id; +#define CURRENT_ID (¤t_id) -struct writeout_fn_node { -  writeout_fn fn; -  struct writeout_fn_node *next; +struct fn_node { +  dynamic_object_id id; +  fn_ptr fn; +  struct fn_node* next;  }; -static struct writeout_fn_node *writeout_fn_head = NULL; -static struct writeout_fn_node *writeout_fn_tail = NULL; +struct fn_list { +  struct fn_node *head, *tail; +};  /* - *  A list of flush functions that our __gcov_flush() function should call. + * A list of functions to write out the data, shared between all dynamic objects.   */ -typedef void (*flush_fn)(); +struct fn_list writeout_fn_list; -struct flush_fn_node { -  flush_fn fn; -  struct flush_fn_node *next; -}; +/* + *  A list of flush functions that our __gcov_flush() function should call, shared between all dynamic objects. + */ +struct fn_list flush_fn_list; + +static void fn_list_insert(struct fn_list* list, fn_ptr fn) { +  struct fn_node* new_node = malloc(sizeof(struct fn_node)); +  new_node->fn = fn; +  new_node->next = NULL; +  new_node->id = CURRENT_ID; -static struct flush_fn_node *flush_fn_head = NULL; -static struct flush_fn_node *flush_fn_tail = NULL; +  if (!list->head) { +    list->head = list->tail = new_node; +  } else { +    list->tail->next = new_node; +    list->tail = new_node; +  } +} + +static void fn_list_remove(struct fn_list* list) { +  struct fn_node* curr = list->head; +  struct fn_node* prev = NULL; +  struct fn_node* next = NULL; + +  while (curr) { +    next = curr->next; + +    if (curr->id == CURRENT_ID) { +      if (curr == list->head) { +        list->head = next; +      } + +      if (curr == list->tail) { +        list->tail = prev; +      } + +      if (prev) { +        prev->next = next; +      } + +      free(curr); +    } else { +      prev = curr; +    } + +    curr = next; +  } +}  static void resize_write_buffer(uint64_t size) {    if (!new_file) return; @@ -133,7 +180,12 @@ static void write_32bit_value(uint32_t i) {  }  static void write_64bit_value(uint64_t i) { -  write_bytes((char*)&i, 8); +  // GCOV uses a lo-/hi-word format even on big-endian systems. +  // See also GCOVBuffer::readInt64 in LLVM. +  uint32_t lo = (uint32_t) i; +  uint32_t hi = (uint32_t) (i >> 32); +  write_32bit_value(lo); +  write_32bit_value(hi);  }  static uint32_t length_of_string(const char *s) { @@ -158,17 +210,26 @@ static uint32_t read_32bit_value() {    return val;  } -static uint64_t read_64bit_value() { -  uint64_t val; +static uint32_t read_le_32bit_value() { +  uint32_t val = 0; +  int i;    if (new_file) -    return (uint64_t)-1; +    return (uint32_t)-1; -  val = *(uint64_t*)&write_buffer[cur_pos]; -  cur_pos += 8; +  for (i = 0; i < 4; i++) +    val |= write_buffer[cur_pos++] << (8*i);    return val;  } +static uint64_t read_64bit_value() { +  // GCOV uses a lo-/hi-word format even on big-endian systems. +  // See also GCOVBuffer::readInt64 in LLVM. +  uint32_t lo = read_32bit_value(); +  uint32_t hi = read_32bit_value(); +  return ((uint64_t)hi << 32) | ((uint64_t)lo); +} +  static char *mangle_filename(const char *orig_filename) {    char *new_filename;    size_t prefix_len; @@ -228,6 +289,7 @@ static void unmap_file() {   * profiling enabled will emit to a different file. Only one file may be   * started at a time.   */ +COMPILER_RT_VISIBILITY  void llvm_gcda_start_file(const char *orig_filename, const char version[4],                            uint32_t checksum) {    const char *mode = "r+b"; @@ -295,6 +357,7 @@ void llvm_gcda_start_file(const char *orig_filename, const char version[4],  /* Given an array of pointers to counters (counters), increment the n-th one,   * where we're also given a pointer to n (predecessor).   */ +COMPILER_RT_VISIBILITY  void llvm_gcda_increment_indirect_counter(uint32_t *predecessor,                                            uint64_t **counters) {    uint64_t *counter; @@ -317,6 +380,7 @@ void llvm_gcda_increment_indirect_counter(uint32_t *predecessor,  #endif  } +COMPILER_RT_VISIBILITY  void llvm_gcda_emit_function(uint32_t ident, const char *function_name,                               uint32_t func_checksum, uint8_t use_extra_checksum,                               uint32_t cfg_checksum) { @@ -343,6 +407,7 @@ void llvm_gcda_emit_function(uint32_t ident, const char *function_name,      write_string(function_name);  } +COMPILER_RT_VISIBILITY  void llvm_gcda_emit_arcs(uint32_t num_counters, uint64_t *counters) {    uint32_t i;    uint64_t *old_ctrs = NULL; @@ -351,7 +416,7 @@ void llvm_gcda_emit_arcs(uint32_t num_counters, uint64_t *counters) {    if (!output_file) return; -  val = read_32bit_value(); +  val = read_le_32bit_value();    if (val != (uint32_t)-1) {      /* There are counters present in the file. Merge them. */ @@ -394,16 +459,18 @@ void llvm_gcda_emit_arcs(uint32_t num_counters, uint64_t *counters) {  #endif  } +COMPILER_RT_VISIBILITY  void llvm_gcda_summary_info() {    const uint32_t obj_summary_len = 9; /* Length for gcov compatibility. */    uint32_t i;    uint32_t runs = 1; +  static uint32_t run_counted = 0; // We only want to increase the run count once.    uint32_t val = 0;    uint64_t save_cur_pos = cur_pos;    if (!output_file) return; -  val = read_32bit_value(); +  val = read_le_32bit_value();    if (val != (uint32_t)-1) {      /* There are counters present in the file. Merge them. */ @@ -424,7 +491,9 @@ void llvm_gcda_summary_info() {      read_32bit_value(); /* checksum, unused */      read_32bit_value(); /* num, unused */ -    runs += read_32bit_value(); /* Add previous run count to new counter. */ +    uint32_t prev_runs = read_32bit_value(); +    /* Add previous run count to new counter, if not already counted before. */ +    runs = run_counted ? prev_runs : prev_runs + 1;    }    cur_pos = save_cur_pos; @@ -442,11 +511,14 @@ void llvm_gcda_summary_info() {    write_bytes("\0\0\0\xa3", 4); /* tag indicates 1 program */    write_32bit_value(0); /* 0 length */ +  run_counted = 1; +  #ifdef DEBUG_GCDAPROFILING    fprintf(stderr, "llvmgcda:   %u runs\n", runs);  #endif  } +COMPILER_RT_VISIBILITY  void llvm_gcda_end_file() {    /* Write out EOF record. */    if (output_file) { @@ -459,6 +531,7 @@ void llvm_gcda_end_file() {        unmap_file();      } +    fflush(output_file);      lprofUnlockFd(fd);      fclose(output_file);      output_file = NULL; @@ -471,53 +544,35 @@ void llvm_gcda_end_file() {  #endif  } -void llvm_register_writeout_function(writeout_fn fn) { -  struct writeout_fn_node *new_node = malloc(sizeof(struct writeout_fn_node)); -  new_node->fn = fn; -  new_node->next = NULL; - -  if (!writeout_fn_head) { -    writeout_fn_head = writeout_fn_tail = new_node; -  } else { -    writeout_fn_tail->next = new_node; -    writeout_fn_tail = new_node; -  } +COMPILER_RT_VISIBILITY +void llvm_register_writeout_function(fn_ptr fn) { +  fn_list_insert(&writeout_fn_list, fn);  } +COMPILER_RT_VISIBILITY  void llvm_writeout_files(void) { -  struct writeout_fn_node *curr = writeout_fn_head; +  struct fn_node *curr = writeout_fn_list.head;    while (curr) { -    curr->fn(); +    if (curr->id == CURRENT_ID) { +      curr->fn(); +    }      curr = curr->next;    }  } +COMPILER_RT_VISIBILITY  void llvm_delete_writeout_function_list(void) { -  while (writeout_fn_head) { -    struct writeout_fn_node *node = writeout_fn_head; -    writeout_fn_head = writeout_fn_head->next; -    free(node); -  } -   -  writeout_fn_head = writeout_fn_tail = NULL; +  fn_list_remove(&writeout_fn_list);  } -void llvm_register_flush_function(flush_fn fn) { -  struct flush_fn_node *new_node = malloc(sizeof(struct flush_fn_node)); -  new_node->fn = fn; -  new_node->next = NULL; - -  if (!flush_fn_head) { -    flush_fn_head = flush_fn_tail = new_node; -  } else { -    flush_fn_tail->next = new_node; -    flush_fn_tail = new_node; -  } +COMPILER_RT_VISIBILITY +void llvm_register_flush_function(fn_ptr fn) { +  fn_list_insert(&flush_fn_list, fn);  }  void __gcov_flush() { -  struct flush_fn_node *curr = flush_fn_head; +  struct fn_node* curr = flush_fn_list.head;    while (curr) {      curr->fn(); @@ -525,17 +580,13 @@ void __gcov_flush() {    }  } +COMPILER_RT_VISIBILITY  void llvm_delete_flush_function_list(void) { -  while (flush_fn_head) { -    struct flush_fn_node *node = flush_fn_head; -    flush_fn_head = flush_fn_head->next; -    free(node); -  } - -  flush_fn_head = flush_fn_tail = NULL; +  fn_list_remove(&flush_fn_list);  } -void llvm_gcov_init(writeout_fn wfn, flush_fn ffn) { +COMPILER_RT_VISIBILITY +void llvm_gcov_init(fn_ptr wfn, fn_ptr ffn) {    static int atexit_ran = 0;    if (wfn) @@ -553,3 +604,5 @@ void llvm_gcov_init(writeout_fn wfn, flush_fn ffn) {      atexit(llvm_writeout_files);    }  } + +#endif diff --git a/lib/profile/InstrProfData.inc b/lib/profile/InstrProfData.inc index 6a98dc7b9b853..eb4a792ce82d9 100644 --- a/lib/profile/InstrProfData.inc +++ b/lib/profile/InstrProfData.inc @@ -178,7 +178,7 @@ VALUE_PROF_FUNC_PARAM(uint64_t, LargeValue, Type::getInt64Ty(Ctx))   * functions are profiled by the instrumented code. The target addresses are   * written in the raw profile data and converted to target function name's MD5   * hash by the profile reader during deserialization.  Typically, this happens - * when the the raw profile data is read during profile merging. + * when the raw profile data is read during profile merging.   *   * For this remapping the ProfData is used.  ProfData contains both the function   * name hash and the function address. diff --git a/lib/profile/InstrProfiling.h b/lib/profile/InstrProfiling.h index 945f1c4ac38d8..3ef7eacf06be4 100644 --- a/lib/profile/InstrProfiling.h +++ b/lib/profile/InstrProfiling.h @@ -106,6 +106,10 @@ void INSTR_PROF_VALUE_PROF_FUNC(  #include "InstrProfData.inc"      ); +void __llvm_profile_instrument_target_value(uint64_t TargetValue, void *Data, +                                            uint32_t CounterIndex, +                                            uint64_t CounterValue); +  /*!   * \brief Write instrumentation data to the current file.   * @@ -166,6 +170,14 @@ void __llvm_profile_initialize_file(void);   */  const char *__llvm_profile_get_path_prefix(); +/*! + * \brief Return filename (including path) of the profile data. Note that if the + * user calls __llvm_profile_set_filename later after invoking this interface, + * the actual file name may differ from what is returned here. + * Side-effect: this API call will invoke malloc with dynamic memory allocation. + */ +const char *__llvm_profile_get_filename(); +  /*! \brief Get the magic token for the file format. */  uint64_t __llvm_profile_get_magic(void); diff --git a/lib/profile/InstrProfilingFile.c b/lib/profile/InstrProfilingFile.c index d7c0abbc16e3f..c4cf3ccd70c29 100644 --- a/lib/profile/InstrProfilingFile.c +++ b/lib/profile/InstrProfilingFile.c @@ -7,6 +7,8 @@  |*  \*===----------------------------------------------------------------------===*/ +#if !defined(__Fuchsia__) +  #include <errno.h>  #include <stdio.h>  #include <stdlib.h> @@ -19,6 +21,7 @@  #include "WindowsMMap.h"  /* For _chsize_s */  #include <io.h> +#include <process.h>  #else  #include <sys/file.h>  #include <sys/mman.h> @@ -68,6 +71,7 @@ typedef struct lprofFilename {     * by runtime. */    unsigned OwnsFilenamePat;    const char *ProfilePathPrefix; +  const char *Filename;    char PidChars[MAX_PID_SIZE];    char Hostname[COMPILER_RT_MAX_HOSTLEN];    unsigned NumPids; @@ -83,11 +87,11 @@ typedef struct lprofFilename {    ProfileNameSpecifier PNS;  } lprofFilename; -COMPILER_RT_WEAK lprofFilename lprofCurFilename = {0, 0, 0, {0}, {0}, -                                                   0, 0, 0, PNS_unknown}; +COMPILER_RT_WEAK lprofFilename lprofCurFilename = {0,   0, 0, 0, {0}, +                                                   {0}, 0, 0, 0, PNS_unknown};  static int getCurFilenameLength(); -static const char *getCurFilename(char *FilenameBuf); +static const char *getCurFilename(char *FilenameBuf, int ForceUseBuf);  static unsigned doMerging() { return lprofCurFilename.MergePoolSize; }  /* Return 1 if there is an error, otherwise return  0.  */ @@ -183,8 +187,12 @@ static int doProfileMerging(FILE *ProfileFile, int *MergeDone) {    /* Now start merging */    __llvm_profile_merge_from_buffer(ProfileBuffer, ProfileFileSize); -  (void)munmap(ProfileBuffer, ProfileFileSize); +  // Truncate the file in case merging of value profile did not happend to +  // prevent from leaving garbage data at the end of the profile file. +  COMPILER_RT_FTRUNCATE(ProfileFile, __llvm_profile_get_size_for_buffer()); + +  (void)munmap(ProfileBuffer, ProfileFileSize);    *MergeDone = 1;    return 0; @@ -234,6 +242,7 @@ static int writeFile(const char *OutputName) {    FILE *OutputFile;    int MergeDone = 0; +  VPMergeHook = &lprofMergeValueProfData;    if (!doMerging())      OutputFile = fopen(OutputName, "ab");    else @@ -260,7 +269,7 @@ static void truncateCurrentFile(void) {    Length = getCurFilenameLength();    FilenameBuf = (char *)COMPILER_RT_ALLOCA(Length + 1); -  Filename = getCurFilename(FilenameBuf); +  Filename = getCurFilename(FilenameBuf, 0);    if (!Filename)      return; @@ -305,15 +314,18 @@ static int parseFilenamePattern(const char *FilenamePat,    char *Hostname = &lprofCurFilename.Hostname[0];    int MergingEnabled = 0; -  /* Clean up cached prefix.  */ +  /* Clean up cached prefix and filename.  */    if (lprofCurFilename.ProfilePathPrefix)      free((void *)lprofCurFilename.ProfilePathPrefix); -  memset(&lprofCurFilename, 0, sizeof(lprofCurFilename)); +  if (lprofCurFilename.Filename) +    free((void *)lprofCurFilename.Filename);    if (lprofCurFilename.FilenamePat && lprofCurFilename.OwnsFilenamePat) {      free((void *)lprofCurFilename.FilenamePat);    } +  memset(&lprofCurFilename, 0, sizeof(lprofCurFilename)); +    if (!CopyFilenamePat)      lprofCurFilename.FilenamePat = FilenamePat;    else { @@ -422,17 +434,25 @@ static int getCurFilenameLength() {  /* Return the pointer to the current profile file name (after substituting   * PIDs and Hostnames in filename pattern. \p FilenameBuf is the buffer   * to store the resulting filename. If no substitution is needed, the - * current filename pattern string is directly returned. */ -static const char *getCurFilename(char *FilenameBuf) { -  int I, J, PidLength, HostNameLength; + * current filename pattern string is directly returned, unless ForceUseBuf + * is enabled. */ +static const char *getCurFilename(char *FilenameBuf, int ForceUseBuf) { +  int I, J, PidLength, HostNameLength, FilenamePatLength;    const char *FilenamePat = lprofCurFilename.FilenamePat;    if (!lprofCurFilename.FilenamePat || !lprofCurFilename.FilenamePat[0])      return 0;    if (!(lprofCurFilename.NumPids || lprofCurFilename.NumHosts || -        lprofCurFilename.MergePoolSize)) -    return lprofCurFilename.FilenamePat; +        lprofCurFilename.MergePoolSize)) { +    if (!ForceUseBuf) +      return lprofCurFilename.FilenamePat; + +    FilenamePatLength = strlen(lprofCurFilename.FilenamePat); +    memcpy(FilenameBuf, lprofCurFilename.FilenamePat, FilenamePatLength); +    FilenameBuf[FilenamePatLength] = '\0'; +    return FilenameBuf; +  }    PidLength = strlen(lprofCurFilename.PidChars);    HostNameLength = strlen(lprofCurFilename.Hostname); @@ -486,7 +506,7 @@ const char *__llvm_profile_get_path_prefix(void) {    Length = getCurFilenameLength();    FilenameBuf = (char *)COMPILER_RT_ALLOCA(Length + 1); -  Filename = getCurFilename(FilenameBuf); +  Filename = getCurFilename(FilenameBuf, 0);    if (!Filename)      return "\0"; @@ -506,6 +526,29 @@ const char *__llvm_profile_get_path_prefix(void) {    return Prefix;  } +COMPILER_RT_VISIBILITY +const char *__llvm_profile_get_filename(void) { +  int Length; +  char *FilenameBuf; +  const char *Filename; + +  if (lprofCurFilename.Filename) +    return lprofCurFilename.Filename; + +  Length = getCurFilenameLength(); +  FilenameBuf = (char *)malloc(Length + 1); +  if (!FilenameBuf) { +    PROF_ERR("Failed to %s\n", "allocate memory."); +    return "\0"; +  } +  Filename = getCurFilename(FilenameBuf, 1); +  if (!Filename) +    return "\0"; + +  lprofCurFilename.Filename = FilenameBuf; +  return FilenameBuf; +} +  /* This method is invoked by the runtime initialization hook   * InstrProfilingRuntime.o if it is linked in. Both user specified   * profile path via -fprofile-instr-generate= and LLVM_PROFILE_FILE @@ -562,7 +605,7 @@ int __llvm_profile_write_file(void) {    Length = getCurFilenameLength();    FilenameBuf = (char *)COMPILER_RT_ALLOCA(Length + 1); -  Filename = getCurFilename(FilenameBuf); +  Filename = getCurFilename(FilenameBuf, 0);    /* Check the filename. */    if (!Filename) { @@ -620,3 +663,5 @@ int __llvm_profile_register_write_file_atexit(void) {    HasBeenRegistered = 1;    return atexit(writeFileWithoutReturn);  } + +#endif diff --git a/lib/profile/InstrProfilingMerge.c b/lib/profile/InstrProfilingMerge.c index a2021154df734..2397250fb1225 100644 --- a/lib/profile/InstrProfilingMerge.c +++ b/lib/profile/InstrProfilingMerge.c @@ -17,8 +17,9 @@  #define INSTR_PROF_VALUE_PROF_DATA  #include "InstrProfData.inc" -COMPILER_RT_WEAK void (*VPMergeHook)(ValueProfData *, -                                     __llvm_profile_data *) = NULL; +COMPILER_RT_VISIBILITY +void (*VPMergeHook)(ValueProfData *, __llvm_profile_data *); +  COMPILER_RT_VISIBILITY  uint64_t lprofGetLoadModuleSignature() {    /* A very fast way to compute a module signature.  */ diff --git a/lib/profile/InstrProfilingMergeFile.c b/lib/profile/InstrProfilingMergeFile.c index ac5ee9fbedc67..dc1bc97626769 100644 --- a/lib/profile/InstrProfilingMergeFile.c +++ b/lib/profile/InstrProfilingMergeFile.c @@ -10,6 +10,8 @@  |* stored in files.  \*===----------------------------------------------------------------------===*/ +#if !defined(__Fuchsia__) +  #include "InstrProfiling.h"  #include "InstrProfilingInternal.h"  #include "InstrProfilingUtil.h" @@ -17,25 +19,27 @@  #define INSTR_PROF_VALUE_PROF_DATA  #include "InstrProfData.inc" -void (*VPMergeHook)(ValueProfData *, -                    __llvm_profile_data *) = &lprofMergeValueProfData; -  /* Merge value profile data pointed to by SrcValueProfData into   * in-memory profile counters pointed by to DstData.  */  void lprofMergeValueProfData(ValueProfData *SrcValueProfData,                               __llvm_profile_data *DstData) { -  unsigned I, S, V, C; +  unsigned I, S, V, DstIndex = 0;    InstrProfValueData *VData;    ValueProfRecord *VR = getFirstValueProfRecord(SrcValueProfData);    for (I = 0; I < SrcValueProfData->NumValueKinds; I++) {      VData = getValueProfRecordValueData(VR); +    unsigned SrcIndex = 0;      for (S = 0; S < VR->NumValueSites; S++) {        uint8_t NV = VR->SiteCountArray[S];        for (V = 0; V < NV; V++) { -        for (C = 0; C < VData[V].Count; C++) -          __llvm_profile_instrument_target(VData[V].Value, DstData, S); +        __llvm_profile_instrument_target_value(VData[SrcIndex].Value, DstData, +                                               DstIndex, VData[SrcIndex].Count); +        ++SrcIndex;        } +      ++DstIndex;      }      VR = getValueProfRecordNext(VR);    }  } + +#endif diff --git a/lib/profile/InstrProfilingPlatformFuchsia.c b/lib/profile/InstrProfilingPlatformFuchsia.c new file mode 100644 index 0000000000000..a50602dede7d4 --- /dev/null +++ b/lib/profile/InstrProfilingPlatformFuchsia.c @@ -0,0 +1,183 @@ +/*===- InstrProfilingPlatformFuchsia.c - Profile data Fuchsia platform ----===*\ +|* +|*                     The LLVM Compiler Infrastructure +|* +|* This file is distributed under the University of Illinois Open Source +|* License. See LICENSE.TXT for details. +|* +\*===----------------------------------------------------------------------===*/ +/* + * This file implements the profiling runtime for Fuchsia and defines the + * shared profile runtime interface. Each module (executable or DSO) statically + * links in the whole profile runtime to satisfy the calls from its + * instrumented code. Several modules in the same program might be separately + * compiled and even use different versions of the instrumentation ABI and data + * format. All they share in common is the VMO and the offset, which live in + * exported globals so that exactly one definition will be shared across all + * modules. Each module has its own independent runtime that registers its own + * atexit hook to append its own data into the shared VMO which is published + * via the data sink hook provided by Fuchsia's dynamic linker. + */ + +#if defined(__Fuchsia__) + +#include <inttypes.h> +#include <stdarg.h> +#include <stdbool.h> +#include <stdlib.h> + +#include <zircon/process.h> +#include <zircon/sanitizer.h> +#include <zircon/syscalls.h> + +#include "InstrProfiling.h" +#include "InstrProfilingInternal.h" +#include "InstrProfilingUtil.h" + +/* VMO that contains the coverage data shared across all modules. This symbol + * has default visibility and is exported in each module (executable or DSO) + * that statically links in the profiling runtime. + */ +zx_handle_t __llvm_profile_vmo; +/* Current offset within the VMO where data should be written next. This symbol + * has default visibility and is exported in each module (executable or DSO) + * that statically links in the profiling runtime. + */ +uint64_t __llvm_profile_offset; + +static const char ProfileSinkName[] = "llvm-profile"; + +static inline void lprofWrite(const char *fmt, ...) { +  char s[256]; + +  va_list ap; +  va_start(ap, fmt); +  int ret = vsnprintf(s, sizeof(s), fmt, ap); +  va_end(ap); + +  __sanitizer_log_write(s, ret + 1); +} + +static uint32_t lprofVMOWriter(ProfDataWriter *This, ProfDataIOVec *IOVecs, +                               uint32_t NumIOVecs) { +  /* Allocate VMO if it hasn't been created yet. */ +  if (__llvm_profile_vmo == ZX_HANDLE_INVALID) { +    /* Get information about the current process. */ +    zx_info_handle_basic_t Info; +    zx_status_t Status = +        _zx_object_get_info(_zx_process_self(), ZX_INFO_HANDLE_BASIC, &Info, +                            sizeof(Info), NULL, NULL); +    if (Status != ZX_OK) +      return -1; + +    /* Create VMO to hold the profile data. */ +    Status = _zx_vmo_create(0, 0, &__llvm_profile_vmo); +    if (Status != ZX_OK) +      return -1; + +    /* Give the VMO a name including our process KOID so it's easy to spot. */ +    char VmoName[ZX_MAX_NAME_LEN]; +    snprintf(VmoName, sizeof(VmoName), "%s.%" PRIu64, ProfileSinkName, +             Info.koid); +    _zx_object_set_property(__llvm_profile_vmo, ZX_PROP_NAME, VmoName, +                            strlen(VmoName)); + +    /* Duplicate the handle since __sanitizer_publish_data consumes it. */ +    zx_handle_t Handle; +    Status = +        _zx_handle_duplicate(__llvm_profile_vmo, ZX_RIGHT_SAME_RIGHTS, &Handle); +    if (Status != ZX_OK) +      return -1; + +    /* Publish the VMO which contains profile data to the system. */ +    __sanitizer_publish_data(ProfileSinkName, Handle); + +    /* Use the dumpfile symbolizer markup element to write the name of VMO. */ +    lprofWrite("LLVM Profile: {{{dumpfile:%s:%s}}}\n", +               ProfileSinkName, VmoName); +  } + +  /* Compute the total length of data to be written. */ +  size_t Length = 0; +  for (uint32_t I = 0; I < NumIOVecs; I++) +    Length += IOVecs[I].ElmSize * IOVecs[I].NumElm; + +  /* Resize the VMO to ensure there's sufficient space for the data. */ +  zx_status_t Status = +      _zx_vmo_set_size(__llvm_profile_vmo, __llvm_profile_offset + Length); +  if (Status != ZX_OK) +    return -1; + +  /* Copy the data into VMO. */ +  for (uint32_t I = 0; I < NumIOVecs; I++) { +    size_t Length = IOVecs[I].ElmSize * IOVecs[I].NumElm; +    if (IOVecs[I].Data) { +      Status = _zx_vmo_write(__llvm_profile_vmo, IOVecs[I].Data, +                             __llvm_profile_offset, Length); +      if (Status != ZX_OK) +        return -1; +    } +    __llvm_profile_offset += Length; +  } + +  return 0; +} + +static void initVMOWriter(ProfDataWriter *This) { +  This->Write = lprofVMOWriter; +  This->WriterCtx = NULL; +} + +static int dump(void) { +  if (lprofProfileDumped()) { +    lprofWrite("Profile data not published: already written.\n"); +    return 0; +  } + +  /* Check if there is llvm/runtime version mismatch. */ +  if (GET_VERSION(__llvm_profile_get_version()) != INSTR_PROF_RAW_VERSION) { +    lprofWrite("Runtime and instrumentation version mismatch : " +               "expected %d, but got %d\n", +               INSTR_PROF_RAW_VERSION, +               (int)GET_VERSION(__llvm_profile_get_version())); +    return -1; +  } + +  /* Write the profile data into the mapped region. */ +  ProfDataWriter VMOWriter; +  initVMOWriter(&VMOWriter); +  if (lprofWriteData(&VMOWriter, lprofGetVPDataReader(), 0) != 0) +    return -1; + +  return 0; +} + +COMPILER_RT_VISIBILITY +int __llvm_profile_dump(void) { +  int rc = dump(); +  lprofSetProfileDumped(); +  return rc; +} + +static void dumpWithoutReturn(void) { dump(); } + +/* This method is invoked by the runtime initialization hook + * InstrProfilingRuntime.o if it is linked in. + */ +COMPILER_RT_VISIBILITY +void __llvm_profile_initialize_file(void) {} + +COMPILER_RT_VISIBILITY +int __llvm_profile_register_write_file_atexit(void) { +  static bool HasBeenRegistered = false; + +  if (HasBeenRegistered) +    return 0; + +  lprofSetupValueProfiler(); + +  HasBeenRegistered = true; +  return atexit(dumpWithoutReturn); +} + +#endif diff --git a/lib/profile/InstrProfilingPlatformLinux.c b/lib/profile/InstrProfilingPlatformLinux.c index 89f1ab4cfedab..a517821a2fbd7 100644 --- a/lib/profile/InstrProfilingPlatformLinux.c +++ b/lib/profile/InstrProfilingPlatformLinux.c @@ -7,7 +7,7 @@  |*  \*===----------------------------------------------------------------------===*/ -#if defined(__linux__) || defined(__FreeBSD__) || \ +#if defined(__linux__) || defined(__FreeBSD__) || defined(__Fuchsia__) || \      (defined(__sun__) && defined(__svr4__))  #include <stdlib.h> diff --git a/lib/profile/InstrProfilingPort.h b/lib/profile/InstrProfilingPort.h index cd1264b0e5755..ede6aaaf78860 100644 --- a/lib/profile/InstrProfilingPort.h +++ b/lib/profile/InstrProfilingPort.h @@ -22,12 +22,14 @@  #define COMPILER_RT_ALLOCA _alloca  /* Need to include <stdio.h> and <io.h> */  #define COMPILER_RT_FTRUNCATE(f,l) _chsize(_fileno(f),l) +#define COMPILER_RT_ALWAYS_INLINE __forceinline  #elif __GNUC__  #define COMPILER_RT_ALIGNAS(x) __attribute__((aligned(x)))  #define COMPILER_RT_VISIBILITY __attribute__((visibility("hidden")))  #define COMPILER_RT_WEAK __attribute__((weak))  #define COMPILER_RT_ALLOCA __builtin_alloca  #define COMPILER_RT_FTRUNCATE(f,l) ftruncate(fileno(f),l) +#define COMPILER_RT_ALWAYS_INLINE inline __attribute((always_inline))  #endif  #if defined(__APPLE__) diff --git a/lib/profile/InstrProfilingUtil.c b/lib/profile/InstrProfilingUtil.c index 7f49d0f9fae11..d053ab160ca7b 100644 --- a/lib/profile/InstrProfilingUtil.c +++ b/lib/profile/InstrProfilingUtil.c @@ -243,23 +243,21 @@ lprofApplyPathPrefix(char *Dest, const char *PathStr, const char *Prefix,  COMPILER_RT_VISIBILITY const char *  lprofFindFirstDirSeparator(const char *Path) { -  const char *Sep; -  Sep = strchr(Path, DIR_SEPARATOR); -  if (Sep) -    return Sep; +  const char *Sep = strchr(Path, DIR_SEPARATOR);  #if defined(DIR_SEPARATOR_2) -  Sep = strchr(Path, DIR_SEPARATOR_2); +  const char *Sep2 = strchr(Path, DIR_SEPARATOR_2); +  if (Sep2 && (!Sep || Sep2 < Sep)) +    Sep = Sep2;  #endif    return Sep;  }  COMPILER_RT_VISIBILITY const char *lprofFindLastDirSeparator(const char *Path) { -  const char *Sep; -  Sep = strrchr(Path, DIR_SEPARATOR); -  if (Sep) -    return Sep; +  const char *Sep = strrchr(Path, DIR_SEPARATOR);  #if defined(DIR_SEPARATOR_2) -  Sep = strrchr(Path, DIR_SEPARATOR_2); +  const char *Sep2 = strrchr(Path, DIR_SEPARATOR_2); +  if (Sep2 && (!Sep || Sep2 > Sep)) +    Sep = Sep2;  #endif    return Sep;  } diff --git a/lib/profile/InstrProfilingValue.c b/lib/profile/InstrProfilingValue.c index 3db0de8a6723e..674a48609878a 100644 --- a/lib/profile/InstrProfilingValue.c +++ b/lib/profile/InstrProfilingValue.c @@ -132,13 +132,14 @@ static ValueProfNode *allocateOneNode(__llvm_profile_data *Data, uint32_t Index,    return Node;  } -COMPILER_RT_VISIBILITY void -__llvm_profile_instrument_target(uint64_t TargetValue, void *Data, -                                 uint32_t CounterIndex) { +static COMPILER_RT_ALWAYS_INLINE void +instrumentTargetValueImpl(uint64_t TargetValue, void *Data, +                          uint32_t CounterIndex, uint64_t CountValue) {    __llvm_profile_data *PData = (__llvm_profile_data *)Data;    if (!PData)      return; - +  if (!CountValue) +    return;    if (!PData->Values) {      if (!allocateValueProfileCounters(PData))        return; @@ -153,7 +154,7 @@ __llvm_profile_instrument_target(uint64_t TargetValue, void *Data,    uint8_t VDataCount = 0;    while (CurVNode) {      if (TargetValue == CurVNode->Value) { -      CurVNode->Count++; +      CurVNode->Count += CountValue;        return;      }      if (CurVNode->Count < MinCount) { @@ -194,11 +195,13 @@ __llvm_profile_instrument_target(uint64_t TargetValue, void *Data,       * the runtime can wipe out more than one lowest count entries       * to give space for hot targets.       */ -    if (!MinCountVNode->Count || !(--MinCountVNode->Count)) { +    if (MinCountVNode->Count <= CountValue) {        CurVNode = MinCountVNode;        CurVNode->Value = TargetValue; -      CurVNode->Count++; -    } +      CurVNode->Count = CountValue; +    } else +      MinCountVNode->Count -= CountValue; +      return;    } @@ -206,7 +209,7 @@ __llvm_profile_instrument_target(uint64_t TargetValue, void *Data,    if (!CurVNode)      return;    CurVNode->Value = TargetValue; -  CurVNode->Count++; +  CurVNode->Count += CountValue;    uint32_t Success = 0;    if (!ValueCounters[CounterIndex]) @@ -221,6 +224,18 @@ __llvm_profile_instrument_target(uint64_t TargetValue, void *Data,    }  } +COMPILER_RT_VISIBILITY void +__llvm_profile_instrument_target(uint64_t TargetValue, void *Data, +                                 uint32_t CounterIndex) { +  instrumentTargetValueImpl(TargetValue, Data, CounterIndex, 1); +} +COMPILER_RT_VISIBILITY void +__llvm_profile_instrument_target_value(uint64_t TargetValue, void *Data, +                                       uint32_t CounterIndex, +                                       uint64_t CountValue) { +  instrumentTargetValueImpl(TargetValue, Data, CounterIndex, CountValue); +} +  /*   * The target values are partitioned into multiple regions/ranges. There is one   * contiguous region which is precise -- every value in the range is tracked diff --git a/lib/safestack/.clang-format b/lib/safestack/.clang-format index f6cb8ad931f54..560308c91deec 100644 --- a/lib/safestack/.clang-format +++ b/lib/safestack/.clang-format @@ -1 +1,2 @@  BasedOnStyle: Google +AllowShortIfStatementsOnASingleLine: false diff --git a/lib/safestack/safestack.cc b/lib/safestack/safestack.cc index d783cd5a9b29d..8af93624b991b 100644 --- a/lib/safestack/safestack.cc +++ b/lib/safestack/safestack.cc @@ -171,11 +171,13 @@ static void thread_cleanup_handler(void *_iter) {    }  } +static void EnsureInterceptorsInitialized(); +  /// Intercept thread creation operation to allocate and setup the unsafe stack  INTERCEPTOR(int, pthread_create, pthread_t *thread,              const pthread_attr_t *attr,              void *(*start_routine)(void*), void *arg) { - +  EnsureInterceptorsInitialized();    size_t size = 0;    size_t guard = 0; @@ -207,6 +209,19 @@ INTERCEPTOR(int, pthread_create, pthread_t *thread,    return REAL(pthread_create)(thread, attr, thread_start, tinfo);  } +static BlockingMutex interceptor_init_lock(LINKER_INITIALIZED); +static bool interceptors_inited = false; + +static void EnsureInterceptorsInitialized() { +  BlockingMutexLock lock(&interceptor_init_lock); +  if (interceptors_inited) return; + +  // Initialize pthread interceptors for thread allocation +  INTERCEPT_FUNCTION(pthread_create); + +  interceptors_inited = true; +} +  extern "C" __attribute__((visibility("default")))  #if !SANITIZER_CAN_USE_PREINIT_ARRAY  // On ELF platforms, the constructor is invoked using .preinit_array (see below) @@ -227,9 +242,6 @@ void __safestack_init() {    unsafe_stack_setup(addr, size, guard);    pageSize = sysconf(_SC_PAGESIZE); -  // Initialize pthread interceptors for thread allocation -  INTERCEPT_FUNCTION(pthread_create); -    // Setup the cleanup handler    pthread_key_create(&thread_cleanup_key, thread_cleanup_handler);  } @@ -245,6 +257,16 @@ __attribute__((section(".preinit_array"),  #endif  extern "C" +    __attribute__((visibility("default"))) void *__get_unsafe_stack_bottom() { +  return unsafe_stack_start; +} + +extern "C" +    __attribute__((visibility("default"))) void *__get_unsafe_stack_top() { +  return (char*)unsafe_stack_start + unsafe_stack_size; +} + +extern "C"      __attribute__((visibility("default"))) void *__get_unsafe_stack_start() {    return unsafe_stack_start;  } diff --git a/lib/sanitizer_common/.clang-format b/lib/sanitizer_common/.clang-format index f6cb8ad931f54..560308c91deec 100644 --- a/lib/sanitizer_common/.clang-format +++ b/lib/sanitizer_common/.clang-format @@ -1 +1,2 @@  BasedOnStyle: Google +AllowShortIfStatementsOnASingleLine: false diff --git a/lib/sanitizer_common/CMakeLists.txt b/lib/sanitizer_common/CMakeLists.txt index e0226ae4975f9..1be99616e232a 100644 --- a/lib/sanitizer_common/CMakeLists.txt +++ b/lib/sanitizer_common/CMakeLists.txt @@ -16,29 +16,24 @@ set(SANITIZER_SOURCES_NOTERMINATION    sanitizer_linux.cc    sanitizer_linux_s390.cc    sanitizer_mac.cc +  sanitizer_openbsd.cc    sanitizer_persistent_allocator.cc    sanitizer_platform_limits_linux.cc    sanitizer_platform_limits_netbsd.cc +  sanitizer_platform_limits_openbsd.cc    sanitizer_platform_limits_posix.cc    sanitizer_platform_limits_solaris.cc    sanitizer_posix.cc    sanitizer_printf.cc    sanitizer_procmaps_common.cc -  sanitizer_procmaps_freebsd.cc +  sanitizer_procmaps_bsd.cc    sanitizer_procmaps_linux.cc    sanitizer_procmaps_mac.cc    sanitizer_procmaps_solaris.cc +  sanitizer_rtems.cc    sanitizer_solaris.cc -  sanitizer_stackdepot.cc -  sanitizer_stacktrace.cc -  sanitizer_stacktrace_printer.cc    sanitizer_stoptheworld_mac.cc    sanitizer_suppressions.cc -  sanitizer_symbolizer.cc -  sanitizer_symbolizer_fuchsia.cc -  sanitizer_symbolizer_libbacktrace.cc -  sanitizer_symbolizer_mac.cc -  sanitizer_symbolizer_win.cc    sanitizer_tls_get_addr.cc    sanitizer_thread_registry.cc    sanitizer_win.cc) @@ -62,45 +57,73 @@ set(SANITIZER_NOLIBC_SOURCES  set(SANITIZER_LIBCDEP_SOURCES    sanitizer_common_libcdep.cc    sanitizer_allocator_checks.cc -  sancov_flags.cc -  sanitizer_coverage_fuchsia.cc -  sanitizer_coverage_libcdep_new.cc -  sanitizer_coverage_win_sections.cc    sanitizer_linux_libcdep.cc    sanitizer_mac_libcdep.cc    sanitizer_posix_libcdep.cc +  sanitizer_stoptheworld_linux_libcdep.cc) + +set(SANITIZER_COVERAGE_SOURCES +  sancov_flags.cc +  sanitizer_coverage_fuchsia.cc +  sanitizer_coverage_libcdep_new.cc +  sanitizer_coverage_win_sections.cc) + +set(SANITIZER_SYMBOLIZER_SOURCES +  sanitizer_allocator_report.cc +  sanitizer_stackdepot.cc +  sanitizer_stacktrace.cc    sanitizer_stacktrace_libcdep.cc -  sanitizer_stoptheworld_linux_libcdep.cc +  sanitizer_stacktrace_printer.cc +  sanitizer_stacktrace_sparc.cc +  sanitizer_symbolizer.cc +  sanitizer_symbolizer_libbacktrace.cc    sanitizer_symbolizer_libcdep.cc +  sanitizer_symbolizer_mac.cc +  sanitizer_symbolizer_markup.cc    sanitizer_symbolizer_posix_libcdep.cc -  sanitizer_unwind_linux_libcdep.cc) +  sanitizer_symbolizer_report.cc +  sanitizer_symbolizer_win.cc +  sanitizer_unwind_linux_libcdep.cc +  sanitizer_unwind_win.cc)  # Explicitly list all sanitizer_common headers. Not all of these are  # included in sanitizer_common source files, but we need to depend on  # headers when building our custom unit tests. -set(SANITIZER_HEADERS +set(SANITIZER_IMPL_HEADERS +  sancov_flags.h +  sancov_flags.inc    sanitizer_addrhashmap.h    sanitizer_allocator.h    sanitizer_allocator_bytemap.h +  sanitizer_allocator_checks.h    sanitizer_allocator_combined.h    sanitizer_allocator_interface.h    sanitizer_allocator_internal.h    sanitizer_allocator_local_cache.h    sanitizer_allocator_primary32.h    sanitizer_allocator_primary64.h +  sanitizer_allocator_report.h    sanitizer_allocator_secondary.h    sanitizer_allocator_size_class_map.h    sanitizer_allocator_stats.h +  sanitizer_asm.h    sanitizer_atomic.h    sanitizer_atomic_clang.h +  sanitizer_atomic_clang_mips.h +  sanitizer_atomic_clang_other.h +  sanitizer_atomic_clang_x86.h    sanitizer_atomic_msvc.h    sanitizer_bitvector.h    sanitizer_bvgraph.h    sanitizer_common.h    sanitizer_common_interceptors.inc -  sanitizer_common_interceptors_ioctl.inc    sanitizer_common_interceptors_format.inc +  sanitizer_common_interceptors_ioctl.inc +  sanitizer_common_interface.inc +  sanitizer_common_interface_posix.inc    sanitizer_common_syscalls.inc +  sanitizer_coverage_interface.inc +  sanitizer_dbghelp.h    sanitizer_deadlock_detector.h    sanitizer_deadlock_detector_interface.h    sanitizer_errno.h @@ -109,7 +132,10 @@ set(SANITIZER_HEADERS    sanitizer_flag_parser.h    sanitizer_flags.h    sanitizer_flags.inc +  sanitizer_freebsd.h    sanitizer_fuchsia.h +  sanitizer_getauxval.h +  sanitizer_interceptors_ioctl_netbsd.inc    sanitizer_interface_internal.h    sanitizer_internal_defs.h    sanitizer_lfstack.h @@ -118,18 +144,22 @@ set(SANITIZER_HEADERS    sanitizer_linux.h    sanitizer_list.h    sanitizer_mac.h +  sanitizer_malloc_mac.inc    sanitizer_mutex.h    sanitizer_persistent_allocator.h    sanitizer_placement_new.h    sanitizer_platform.h    sanitizer_platform_interceptors.h    sanitizer_platform_limits_netbsd.h +  sanitizer_platform_limits_openbsd.h    sanitizer_platform_limits_posix.h    sanitizer_platform_limits_solaris.h    sanitizer_posix.h    sanitizer_procmaps.h    sanitizer_quarantine.h    sanitizer_report_decorator.h +  sanitizer_rtems.h +  sanitizer_signal_interceptors.inc    sanitizer_stackdepot.h    sanitizer_stackdepotbase.h    sanitizer_stacktrace.h @@ -137,15 +167,23 @@ set(SANITIZER_HEADERS    sanitizer_stoptheworld.h    sanitizer_suppressions.h    sanitizer_symbolizer.h +  sanitizer_symbolizer_fuchsia.h    sanitizer_symbolizer_internal.h    sanitizer_symbolizer_libbacktrace.h    sanitizer_symbolizer_mac.h +  sanitizer_symbolizer_rtems.h    sanitizer_syscall_generic.inc -  sanitizer_syscall_linux_x86_64.inc    sanitizer_syscall_linux_aarch64.inc +  sanitizer_syscall_linux_arm.inc +  sanitizer_syscall_linux_x86_64.inc +  sanitizer_syscalls_netbsd.inc    sanitizer_thread_registry.h +  sanitizer_tls_get_addr.h    sanitizer_vector.h -  sanitizer_win.h) +  sanitizer_win.h +  sanitizer_win_defs.h +  sanitizer_win_dll_thunk.h +  sanitizer_win_weak_interception.h)  include_directories(..) @@ -184,24 +222,42 @@ add_compiler_rt_object_libraries(RTSanitizerCommon    ${OS_OPTION}    ARCHS ${SANITIZER_COMMON_SUPPORTED_ARCH}    SOURCES ${SANITIZER_SOURCES} +  ADDITIONAL_HEADERS ${SANITIZER_IMPL_HEADERS}    CFLAGS ${SANITIZER_CFLAGS}    DEFS ${SANITIZER_COMMON_DEFINITIONS})  add_compiler_rt_object_libraries(RTSanitizerCommonNoTermination    ${OS_OPTION}    ARCHS ${SANITIZER_COMMON_SUPPORTED_ARCH}    SOURCES ${SANITIZER_SOURCES_NOTERMINATION} +  ADDITIONAL_HEADERS ${SANITIZER_IMPL_HEADERS}    CFLAGS ${SANITIZER_CFLAGS}    DEFS ${SANITIZER_COMMON_DEFINITIONS})  add_compiler_rt_object_libraries(RTSanitizerCommonNoLibc    ${OS_OPTION}    ARCHS ${SANITIZER_COMMON_SUPPORTED_ARCH}    SOURCES ${SANITIZER_NOLIBC_SOURCES} +  ADDITIONAL_HEADERS ${SANITIZER_IMPL_HEADERS}    CFLAGS ${SANITIZER_CFLAGS}    DEFS ${SANITIZER_COMMON_DEFINITIONS})  add_compiler_rt_object_libraries(RTSanitizerCommonLibc    ${OS_OPTION}    ARCHS ${SANITIZER_COMMON_SUPPORTED_ARCH}    SOURCES ${SANITIZER_LIBCDEP_SOURCES} +  ADDITIONAL_HEADERS ${SANITIZER_IMPL_HEADERS} +  CFLAGS ${SANITIZER_CFLAGS} +  DEFS ${SANITIZER_COMMON_DEFINITIONS}) +add_compiler_rt_object_libraries(RTSanitizerCommonCoverage +  ${OS_OPTION} +  ARCHS ${SANITIZER_COMMON_SUPPORTED_ARCH} +  SOURCES ${SANITIZER_COVERAGE_SOURCES} +  ADDITIONAL_HEADERS ${SANITIZER_IMPL_HEADERS} +  CFLAGS ${SANITIZER_CFLAGS} +  DEFS ${SANITIZER_COMMON_DEFINITIONS}) +add_compiler_rt_object_libraries(RTSanitizerCommonSymbolizer +  ${OS_OPTION} +  ARCHS ${SANITIZER_COMMON_SUPPORTED_ARCH} +  SOURCES ${SANITIZER_SYMBOLIZER_SOURCES} +  ADDITIONAL_HEADERS ${SANITIZER_IMPL_HEADERS}    CFLAGS ${SANITIZER_CFLAGS}    DEFS ${SANITIZER_COMMON_DEFINITIONS}) @@ -211,12 +267,21 @@ add_compiler_rt_object_libraries(RTSanitizerCommonNoHooks    ${OS_OPTION}    ARCHS ${SANITIZER_COMMON_SUPPORTED_ARCH}    SOURCES ${SANITIZER_SOURCES} +  ADDITIONAL_HEADERS ${SANITIZER_IMPL_HEADERS}    CFLAGS ${SANITIZER_NO_WEAK_HOOKS_CFLAGS}    DEFS ${SANITIZER_COMMON_DEFINITIONS})  add_compiler_rt_object_libraries(RTSanitizerCommonLibcNoHooks    ${OS_OPTION}    ARCHS ${SANITIZER_COMMON_SUPPORTED_ARCH}    SOURCES ${SANITIZER_LIBCDEP_SOURCES} +  ADDITIONAL_HEADERS ${SANITIZER_IMPL_HEADERS} +  CFLAGS ${SANITIZER_NO_WEAK_HOOKS_CFLAGS} +  DEFS ${SANITIZER_COMMON_DEFINITIONS}) +add_compiler_rt_object_libraries(RTSanitizerCommonSymbolizerNoHooks +  ${OS_OPTION} +  ARCHS ${SANITIZER_COMMON_SUPPORTED_ARCH} +  SOURCES ${SANITIZER_SYMBOLIZER_SOURCES} +  ADDITIONAL_HEADERS ${SANITIZER_IMPL_HEADERS}    CFLAGS ${SANITIZER_NO_WEAK_HOOKS_CFLAGS}    DEFS ${SANITIZER_COMMON_DEFINITIONS}) diff --git a/lib/sanitizer_common/sanitizer_allocator.cc b/lib/sanitizer_common/sanitizer_allocator.cc index fc4f7a75ae349..6bfd5e5eea50e 100644 --- a/lib/sanitizer_common/sanitizer_allocator.cc +++ b/lib/sanitizer_common/sanitizer_allocator.cc @@ -21,6 +21,10 @@  namespace __sanitizer { +// Default allocator names. +const char *PrimaryAllocatorName = "SizeClassAllocator"; +const char *SecondaryAllocatorName = "LargeMmapAllocator"; +  // ThreadSanitizer for Go uses libc malloc/free.  #if SANITIZER_GO || defined(SANITIZER_USE_MALLOC)  # if SANITIZER_LINUX && !SANITIZER_ANDROID @@ -136,12 +140,19 @@ static void RawInternalFree(void *ptr, InternalAllocatorCache *cache) {  const u64 kBlockMagic = 0x6A6CB03ABCEBC041ull; +static void NORETURN ReportInternalAllocatorOutOfMemory(uptr requested_size) { +  SetAllocatorOutOfMemory(); +  Report("FATAL: %s: internal allocator is out of memory trying to allocate " +         "0x%zx bytes\n", SanitizerToolName, requested_size); +  Die(); +} +  void *InternalAlloc(uptr size, InternalAllocatorCache *cache, uptr alignment) {    if (size + sizeof(u64) < size)      return nullptr;    void *p = RawInternalAlloc(size + sizeof(u64), cache, alignment); -  if (!p) -    return nullptr; +  if (UNLIKELY(!p)) +    ReportInternalAllocatorOutOfMemory(size + sizeof(u64));    ((u64*)p)[0] = kBlockMagic;    return (char*)p + sizeof(u64);  } @@ -155,16 +166,21 @@ void *InternalRealloc(void *addr, uptr size, InternalAllocatorCache *cache) {    size = size + sizeof(u64);    CHECK_EQ(kBlockMagic, ((u64*)addr)[0]);    void *p = RawInternalRealloc(addr, size, cache); -  if (!p) -    return nullptr; +  if (UNLIKELY(!p)) +    ReportInternalAllocatorOutOfMemory(size);    return (char*)p + sizeof(u64);  }  void *InternalCalloc(uptr count, uptr size, InternalAllocatorCache *cache) { -  if (UNLIKELY(CheckForCallocOverflow(count, size))) -    return InternalAllocator::FailureHandler::OnBadRequest(); +  if (UNLIKELY(CheckForCallocOverflow(count, size))) { +    Report("FATAL: %s: calloc parameters overflow: count * size (%zd * %zd) " +           "cannot be represented in type size_t\n", SanitizerToolName, count, +           size); +    Die(); +  }    void *p = InternalAlloc(count * size, cache); -  if (p) internal_memset(p, 0, count * size); +  if (LIKELY(p)) +    internal_memset(p, 0, count * size);    return p;  } @@ -210,6 +226,8 @@ void SetLowLevelAllocateCallback(LowLevelAllocateCallback callback) {    low_level_alloc_callback = callback;  } +// Allocator's OOM and other errors handling support. +  static atomic_uint8_t allocator_out_of_memory = {0};  static atomic_uint8_t allocator_may_return_null = {0}; @@ -217,13 +235,8 @@ bool IsAllocatorOutOfMemory() {    return atomic_load_relaxed(&allocator_out_of_memory);  } -// Prints error message and kills the program. -void NORETURN ReportAllocatorCannotReturnNull() { -  Report("%s's allocator is terminating the process instead of returning 0\n", -         SanitizerToolName); -  Report("If you don't like this behavior set allocator_may_return_null=1\n"); -  CHECK(0); -  Die(); +void SetAllocatorOutOfMemory() { +  atomic_store_relaxed(&allocator_out_of_memory, 1);  }  bool AllocatorMayReturnNull() { @@ -235,26 +248,9 @@ void SetAllocatorMayReturnNull(bool may_return_null) {                 memory_order_relaxed);  } -void *ReturnNullOrDieOnFailure::OnBadRequest() { -  if (AllocatorMayReturnNull()) -    return nullptr; -  ReportAllocatorCannotReturnNull(); -} - -void *ReturnNullOrDieOnFailure::OnOOM() { -  atomic_store_relaxed(&allocator_out_of_memory, 1); -  if (AllocatorMayReturnNull()) -    return nullptr; -  ReportAllocatorCannotReturnNull(); -} - -void NORETURN *DieOnFailure::OnBadRequest() { -  ReportAllocatorCannotReturnNull(); -} - -void NORETURN *DieOnFailure::OnOOM() { -  atomic_store_relaxed(&allocator_out_of_memory, 1); -  ReportAllocatorCannotReturnNull(); +void PrintHintAllocatorCannotReturnNull() { +  Report("HINT: if you don't care about these errors you may set " +         "allocator_may_return_null=1\n");  }  } // namespace __sanitizer diff --git a/lib/sanitizer_common/sanitizer_allocator.h b/lib/sanitizer_common/sanitizer_allocator.h index 38368361de6fd..9655a2264f34b 100644 --- a/lib/sanitizer_common/sanitizer_allocator.h +++ b/lib/sanitizer_common/sanitizer_allocator.h @@ -24,28 +24,23 @@  namespace __sanitizer { +// Allows the tools to name their allocations appropriately. +extern const char *PrimaryAllocatorName; +extern const char *SecondaryAllocatorName; +  // Since flags are immutable and allocator behavior can be changed at runtime  // (unit tests or ASan on Android are some examples), allocator_may_return_null  // flag value is cached here and can be altered later.  bool AllocatorMayReturnNull();  void SetAllocatorMayReturnNull(bool may_return_null); -// Allocator failure handling policies: -// Implements AllocatorMayReturnNull policy, returns null when the flag is set, -// dies otherwise. -struct ReturnNullOrDieOnFailure { -  static void *OnBadRequest(); -  static void *OnOOM(); -}; -// Always dies on the failure. -struct DieOnFailure { -  static void NORETURN *OnBadRequest(); -  static void NORETURN *OnOOM(); -}; -  // Returns true if allocator detected OOM condition. Can be used to avoid memory -// hungry operations. Set when AllocatorReturnNullOrDieOnOOM() is called. +// hungry operations.  bool IsAllocatorOutOfMemory(); +// Should be called by a particular allocator when OOM is detected. +void SetAllocatorOutOfMemory(); + +void PrintHintAllocatorCannotReturnNull();  // Allocators call these callbacks on mmap/munmap.  struct NoOpMapUnmapCallback { @@ -65,8 +60,10 @@ INLINE u32 RandN(u32 *state, u32 n) { return Rand(state) % n; }  // [0, n)  template<typename T>  INLINE void RandomShuffle(T *a, u32 n, u32 *rand_state) {    if (n <= 1) return; +  u32 state = *rand_state;    for (u32 i = n - 1; i > 0; i--) -    Swap(a[i], a[RandN(rand_state, i + 1)]); +    Swap(a[i], a[RandN(&state, i + 1)]); +  *rand_state = state;  }  #include "sanitizer_allocator_size_class_map.h" diff --git a/lib/sanitizer_common/sanitizer_allocator_bytemap.h b/lib/sanitizer_common/sanitizer_allocator_bytemap.h index 92472cdf51509..7df3e4097bf2a 100644 --- a/lib/sanitizer_common/sanitizer_allocator_bytemap.h +++ b/lib/sanitizer_common/sanitizer_allocator_bytemap.h @@ -18,7 +18,7 @@  template<u64 kSize>  class FlatByteMap {   public: -  void TestOnlyInit() { +  void Init() {      internal_memset(map_, 0, sizeof(map_));    } @@ -44,7 +44,7 @@ class FlatByteMap {  template <u64 kSize1, u64 kSize2, class MapUnmapCallback = NoOpMapUnmapCallback>  class TwoLevelByteMap {   public: -  void TestOnlyInit() { +  void Init() {      internal_memset(map1_, 0, sizeof(map1_));      mu_.Init();    } diff --git a/lib/sanitizer_common/sanitizer_allocator_checks.h b/lib/sanitizer_common/sanitizer_allocator_checks.h index b61a8b2eb3b63..61bd26e68cc67 100644 --- a/lib/sanitizer_common/sanitizer_allocator_checks.h +++ b/lib/sanitizer_common/sanitizer_allocator_checks.h @@ -44,16 +44,18 @@ INLINE void *SetErrnoOnNull(void *ptr) {  // of alignment.  INLINE bool CheckAlignedAllocAlignmentAndSize(uptr alignment, uptr size) {  #if SANITIZER_POSIX -  return IsPowerOfTwo(alignment) && (size & (alignment - 1)) == 0; +  return alignment != 0 && IsPowerOfTwo(alignment) && +         (size & (alignment - 1)) == 0;  #else -  return size % alignment == 0; +  return alignment != 0 && size % alignment == 0;  #endif  }  // Checks posix_memalign() parameters, verifies that alignment is a power of two  // and a multiple of sizeof(void *).  INLINE bool CheckPosixMemalignAlignment(uptr alignment) { -  return IsPowerOfTwo(alignment) && (alignment % sizeof(void *)) == 0; // NOLINT +  return alignment != 0 && IsPowerOfTwo(alignment) && +         (alignment % sizeof(void *)) == 0; // NOLINT  }  // Returns true if calloc(size, n) call overflows on size*n calculation. diff --git a/lib/sanitizer_common/sanitizer_allocator_combined.h b/lib/sanitizer_common/sanitizer_allocator_combined.h index 0d8a2a174bb53..1f874d60b92b2 100644 --- a/lib/sanitizer_common/sanitizer_allocator_combined.h +++ b/lib/sanitizer_common/sanitizer_allocator_combined.h @@ -24,8 +24,6 @@ template <class PrimaryAllocator, class AllocatorCache,            class SecondaryAllocator>  // NOLINT  class CombinedAllocator {   public: -  typedef typename SecondaryAllocator::FailureHandler FailureHandler; -    void InitLinkerInitialized(s32 release_to_os_interval_ms) {      primary_.Init(release_to_os_interval_ms);      secondary_.InitLinkerInitialized(); @@ -42,8 +40,12 @@ class CombinedAllocator {      // Returning 0 on malloc(0) may break a lot of code.      if (size == 0)        size = 1; -    if (size + alignment < size) -      return FailureHandler::OnBadRequest(); +    if (size + alignment < size) { +      Report("WARNING: %s: CombinedAllocator allocation overflow: " +             "0x%zx bytes with 0x%zx alignment requested\n", +             SanitizerToolName, size, alignment); +      return nullptr; +    }      uptr original_size = size;      // If alignment requirements are to be fulfilled by the frontend allocator      // rather than by the primary or secondary, passing an alignment lower than @@ -62,8 +64,6 @@ class CombinedAllocator {        res = cache->Allocate(&primary_, primary_.ClassID(size));      else        res = secondary_.Allocate(&stats_, original_size, alignment); -    if (!res) -      return FailureHandler::OnOOM();      if (alignment > 8)        CHECK_EQ(reinterpret_cast<uptr>(res) & (alignment - 1), 0);      return res; diff --git a/lib/sanitizer_common/sanitizer_allocator_internal.h b/lib/sanitizer_common/sanitizer_allocator_internal.h index a791d0d948946..c0c03d3f4345f 100644 --- a/lib/sanitizer_common/sanitizer_allocator_internal.h +++ b/lib/sanitizer_common/sanitizer_allocator_internal.h @@ -46,9 +46,12 @@ typedef SizeClassAllocator32<AP32> PrimaryInternalAllocator;  typedef SizeClassAllocatorLocalCache<PrimaryInternalAllocator>      InternalAllocatorCache; +typedef LargeMmapAllocator<NoOpMapUnmapCallback, +                           LargeMmapAllocatorPtrArrayStatic> +    SecondaryInternalAllocator; +  typedef CombinedAllocator<PrimaryInternalAllocator, InternalAllocatorCache, -                          LargeMmapAllocator<NoOpMapUnmapCallback, DieOnFailure> -                         > InternalAllocator; +                          SecondaryInternalAllocator> InternalAllocator;  void *InternalAlloc(uptr size, InternalAllocatorCache *cache = nullptr,                      uptr alignment = 0); @@ -59,15 +62,6 @@ void *InternalCalloc(uptr countr, uptr size,  void InternalFree(void *p, InternalAllocatorCache *cache = nullptr);  InternalAllocator *internal_allocator(); -enum InternalAllocEnum { -  INTERNAL_ALLOC -}; -  } // namespace __sanitizer -inline void *operator new(__sanitizer::operator_new_size_type size, -                          __sanitizer::InternalAllocEnum) { -  return __sanitizer::InternalAlloc(size); -} -  #endif // SANITIZER_ALLOCATOR_INTERNAL_H diff --git a/lib/sanitizer_common/sanitizer_allocator_local_cache.h b/lib/sanitizer_common/sanitizer_allocator_local_cache.h index 1b3c2c0c19d1d..1bb8fc27defad 100644 --- a/lib/sanitizer_common/sanitizer_allocator_local_cache.h +++ b/lib/sanitizer_common/sanitizer_allocator_local_cache.h @@ -19,8 +19,7 @@  // object per thread in TLS, is has to be POD.  template<class SizeClassAllocator>  struct SizeClassAllocatorLocalCache -    : SizeClassAllocator::AllocatorCache { -}; +    : SizeClassAllocator::AllocatorCache {};  // Cache used by SizeClassAllocator64.  template <class SizeClassAllocator> @@ -46,13 +45,12 @@ struct SizeClassAllocator64LocalCache {      if (UNLIKELY(c->count == 0)) {        if (UNLIKELY(!Refill(c, allocator, class_id)))          return nullptr; +      DCHECK_GT(c->count, 0);      } -    stats_.Add(AllocatorStatAllocated, c->class_size); -    CHECK_GT(c->count, 0);      CompactPtrT chunk = c->chunks[--c->count]; -    void *res = reinterpret_cast<void *>(allocator->CompactPtrToPointer( +    stats_.Add(AllocatorStatAllocated, c->class_size); +    return reinterpret_cast<void *>(allocator->CompactPtrToPointer(          allocator->GetRegionBeginBySizeClass(class_id), chunk)); -    return res;    }    void Deallocate(SizeClassAllocator *allocator, uptr class_id, void *p) { @@ -60,20 +58,19 @@ struct SizeClassAllocator64LocalCache {      CHECK_LT(class_id, kNumClasses);      // If the first allocator call on a new thread is a deallocation, then      // max_count will be zero, leading to check failure. -    InitCache();      PerClass *c = &per_class_[class_id]; -    stats_.Sub(AllocatorStatAllocated, c->class_size); -    CHECK_NE(c->max_count, 0UL); +    InitCache(c);      if (UNLIKELY(c->count == c->max_count))        Drain(c, allocator, class_id, c->max_count / 2);      CompactPtrT chunk = allocator->PointerToCompactPtr(          allocator->GetRegionBeginBySizeClass(class_id),          reinterpret_cast<uptr>(p));      c->chunks[c->count++] = chunk; +    stats_.Sub(AllocatorStatAllocated, c->class_size);    }    void Drain(SizeClassAllocator *allocator) { -    for (uptr i = 0; i < kNumClasses; i++) { +    for (uptr i = 1; i < kNumClasses; i++) {        PerClass *c = &per_class_[i];        while (c->count > 0)          Drain(c, allocator, i, c->count); @@ -94,20 +91,22 @@ struct SizeClassAllocator64LocalCache {    PerClass per_class_[kNumClasses];    AllocatorStats stats_; -  void InitCache() { -    if (LIKELY(per_class_[1].max_count)) +  void InitCache(PerClass *c) { +    if (LIKELY(c->max_count))        return; -    for (uptr i = 0; i < kNumClasses; i++) { +    for (uptr i = 1; i < kNumClasses; i++) {        PerClass *c = &per_class_[i]; -      c->max_count = 2 * SizeClassMap::MaxCachedHint(i); -      c->class_size = Allocator::ClassIdToSize(i); +      const uptr size = Allocator::ClassIdToSize(i); +      c->max_count = 2 * SizeClassMap::MaxCachedHint(size); +      c->class_size = size;      } +    DCHECK_NE(c->max_count, 0UL);    }    NOINLINE bool Refill(PerClass *c, SizeClassAllocator *allocator,                         uptr class_id) { -    InitCache(); -    uptr num_requested_chunks = c->max_count / 2; +    InitCache(c); +    const uptr num_requested_chunks = c->max_count / 2;      if (UNLIKELY(!allocator->GetFromAllocator(&stats_, class_id, c->chunks,                                                num_requested_chunks)))        return false; @@ -117,9 +116,8 @@ struct SizeClassAllocator64LocalCache {    NOINLINE void Drain(PerClass *c, SizeClassAllocator *allocator, uptr class_id,                        uptr count) { -    InitCache();      CHECK_GE(c->count, count); -    uptr first_idx_to_drain = c->count - count; +    const uptr first_idx_to_drain = c->count - count;      c->count -= count;      allocator->ReturnToAllocator(&stats_, class_id,                                   &c->chunks[first_idx_to_drain], count); @@ -164,12 +162,13 @@ struct SizeClassAllocator32LocalCache {      CHECK_LT(class_id, kNumClasses);      PerClass *c = &per_class_[class_id];      if (UNLIKELY(c->count == 0)) { -      if (UNLIKELY(!Refill(allocator, class_id))) +      if (UNLIKELY(!Refill(c, allocator, class_id)))          return nullptr; +      DCHECK_GT(c->count, 0);      } -    stats_.Add(AllocatorStatAllocated, c->class_size);      void *res = c->batch[--c->count];      PREFETCH(c->batch[c->count - 1]); +    stats_.Add(AllocatorStatAllocated, c->class_size);      return res;    } @@ -178,20 +177,19 @@ struct SizeClassAllocator32LocalCache {      CHECK_LT(class_id, kNumClasses);      // If the first allocator call on a new thread is a deallocation, then      // max_count will be zero, leading to check failure. -    InitCache();      PerClass *c = &per_class_[class_id]; -    stats_.Sub(AllocatorStatAllocated, c->class_size); -    CHECK_NE(c->max_count, 0UL); +    InitCache(c);      if (UNLIKELY(c->count == c->max_count)) -      Drain(allocator, class_id); +      Drain(c, allocator, class_id);      c->batch[c->count++] = p; +    stats_.Sub(AllocatorStatAllocated, c->class_size);    }    void Drain(SizeClassAllocator *allocator) { -    for (uptr i = 0; i < kNumClasses; i++) { +    for (uptr i = 1; i < kNumClasses; i++) {        PerClass *c = &per_class_[i];        while (c->count > 0) -        Drain(allocator, i); +        Drain(c, allocator, i);      }    } @@ -216,15 +214,16 @@ struct SizeClassAllocator32LocalCache {    PerClass per_class_[kNumClasses];    AllocatorStats stats_; -  void InitCache() { -    if (LIKELY(per_class_[1].max_count)) +  void InitCache(PerClass *c) { +    if (LIKELY(c->max_count))        return;      const uptr batch_class_id = SizeClassMap::ClassID(sizeof(TransferBatch)); -    for (uptr i = 0; i < kNumClasses; i++) { +    for (uptr i = 1; i < kNumClasses; i++) {        PerClass *c = &per_class_[i]; -      uptr max_cached = TransferBatch::MaxCached(i); +      const uptr size = Allocator::ClassIdToSize(i); +      const uptr max_cached = TransferBatch::MaxCached(size);        c->max_count = 2 * max_cached; -      c->class_size = Allocator::ClassIdToSize(i); +      c->class_size = size;        // Precompute the class id to use to store batches for the current class        // id. 0 means the class size is large enough to store a batch within one        // of the chunks. If using a separate size class, it will always be @@ -232,16 +231,17 @@ struct SizeClassAllocator32LocalCache {        if (kUseSeparateSizeClassForBatch) {          c->batch_class_id = (i == kBatchClassID) ? 0 : kBatchClassID;        } else { -        c->batch_class_id = (c->class_size < +        c->batch_class_id = (size <            TransferBatch::AllocationSizeRequiredForNElements(max_cached)) ?                batch_class_id : 0;        }      } +    DCHECK_NE(c->max_count, 0UL);    } -  NOINLINE bool Refill(SizeClassAllocator *allocator, uptr class_id) { -    InitCache(); -    PerClass *c = &per_class_[class_id]; +  NOINLINE bool Refill(PerClass *c, SizeClassAllocator *allocator, +                       uptr class_id) { +    InitCache(c);      TransferBatch *b = allocator->AllocateBatch(&stats_, this, class_id);      if (UNLIKELY(!b))        return false; @@ -252,21 +252,21 @@ struct SizeClassAllocator32LocalCache {      return true;    } -  NOINLINE void Drain(SizeClassAllocator *allocator, uptr class_id) { -    InitCache(); -    PerClass *c = &per_class_[class_id]; -    uptr cnt = Min(c->max_count / 2, c->count); -    uptr first_idx_to_drain = c->count - cnt; +  NOINLINE void Drain(PerClass *c, SizeClassAllocator *allocator, +                      uptr class_id) { +    const uptr count = Min(c->max_count / 2, c->count); +    const uptr first_idx_to_drain = c->count - count;      TransferBatch *b = CreateBatch(          class_id, allocator, (TransferBatch *)c->batch[first_idx_to_drain]);      // Failure to allocate a batch while releasing memory is non recoverable.      // TODO(alekseys): Figure out how to do it without allocating a new batch. -    if (UNLIKELY(!b)) -      DieOnFailure::OnOOM(); -    b->SetFromArray(allocator->GetRegionBeginBySizeClass(class_id), -                    &c->batch[first_idx_to_drain], cnt); -    c->count -= cnt; +    if (UNLIKELY(!b)) { +      Report("FATAL: Internal error: %s's allocator failed to allocate a " +             "transfer batch.\n", SanitizerToolName); +      Die(); +    } +    b->SetFromArray(&c->batch[first_idx_to_drain], count); +    c->count -= count;      allocator->DeallocateBatch(&stats_, class_id, b);    }  }; - diff --git a/lib/sanitizer_common/sanitizer_allocator_primary32.h b/lib/sanitizer_common/sanitizer_allocator_primary32.h index 6c682aff64a23..67970e95b31e5 100644 --- a/lib/sanitizer_common/sanitizer_allocator_primary32.h +++ b/lib/sanitizer_common/sanitizer_allocator_primary32.h @@ -63,9 +63,9 @@ class SizeClassAllocator32 {    struct TransferBatch {      static const uptr kMaxNumCached = SizeClassMap::kMaxNumCachedHint - 2; -    void SetFromArray(uptr region_beg_unused, void *batch[], uptr count) { +    void SetFromArray(void *batch[], uptr count) { +      DCHECK_LE(count, kMaxNumCached);        count_ = count; -      CHECK_LE(count_, kMaxNumCached);        for (uptr i = 0; i < count; i++)          batch_[i] = batch[i];      } @@ -73,9 +73,9 @@ class SizeClassAllocator32 {      void Clear() { count_ = 0; }      void Add(void *ptr) {        batch_[count_++] = ptr; -      CHECK_LE(count_, kMaxNumCached); +      DCHECK_LE(count_, kMaxNumCached);      } -    void CopyToArray(void *to_batch[]) { +    void CopyToArray(void *to_batch[]) const {        for (uptr i = 0, n = Count(); i < n; i++)          to_batch[i] = batch_[i];      } @@ -84,8 +84,8 @@ class SizeClassAllocator32 {      static uptr AllocationSizeRequiredForNElements(uptr n) {        return sizeof(uptr) * 2 + sizeof(void *) * n;      } -    static uptr MaxCached(uptr class_id) { -      return Min(kMaxNumCached, SizeClassMap::MaxCachedHint(class_id)); +    static uptr MaxCached(uptr size) { +      return Min(kMaxNumCached, SizeClassMap::MaxCachedHint(size));      }      TransferBatch *next; @@ -108,7 +108,7 @@ class SizeClassAllocator32 {    typedef SizeClassAllocator32LocalCache<ThisT> AllocatorCache;    void Init(s32 release_to_os_interval_ms) { -    possible_regions.TestOnlyInit(); +    possible_regions.Init();      internal_memset(size_class_info_array, 0, sizeof(size_class_info_array));    } @@ -125,7 +125,7 @@ class SizeClassAllocator32 {    }    void *MapWithCallback(uptr size) { -    void *res = MmapOrDie(size, "SizeClassAllocator32"); +    void *res = MmapOrDie(size, PrimaryAllocatorName);      MapUnmapCallback().OnMap((uptr)res, size);      return res;    } @@ -153,13 +153,14 @@ class SizeClassAllocator32 {    NOINLINE TransferBatch *AllocateBatch(AllocatorStats *stat, AllocatorCache *c,                                          uptr class_id) { -    CHECK_LT(class_id, kNumClasses); +    DCHECK_LT(class_id, kNumClasses);      SizeClassInfo *sci = GetSizeClassInfo(class_id);      SpinMutexLock l(&sci->mutex); -    if (sci->free_list.empty() && -        UNLIKELY(!PopulateFreeList(stat, c, sci, class_id))) -      return nullptr; -    CHECK(!sci->free_list.empty()); +    if (sci->free_list.empty()) { +      if (UNLIKELY(!PopulateFreeList(stat, c, sci, class_id))) +        return nullptr; +      DCHECK(!sci->free_list.empty()); +    }      TransferBatch *b = sci->free_list.front();      sci->free_list.pop_front();      return b; @@ -167,15 +168,13 @@ class SizeClassAllocator32 {    NOINLINE void DeallocateBatch(AllocatorStats *stat, uptr class_id,                                  TransferBatch *b) { -    CHECK_LT(class_id, kNumClasses); +    DCHECK_LT(class_id, kNumClasses);      CHECK_GT(b->Count(), 0);      SizeClassInfo *sci = GetSizeClassInfo(class_id);      SpinMutexLock l(&sci->mutex);      sci->free_list.push_front(b);    } -  uptr GetRegionBeginBySizeClass(uptr class_id) { return 0; } -    bool PointerIsMine(const void *p) {      uptr mem = reinterpret_cast<uptr>(p);      if (mem < kSpaceBeg || mem >= kSpaceBeg + kSpaceSize) @@ -251,12 +250,9 @@ class SizeClassAllocator32 {        }    } -  void PrintStats() { -  } +  void PrintStats() {} -  static uptr AdditionalSize() { -    return 0; -  } +  static uptr AdditionalSize() { return 0; }    typedef SizeClassMap SizeClassMapT;    static const uptr kNumClasses = SizeClassMap::kNumClasses; @@ -265,17 +261,15 @@ class SizeClassAllocator32 {    static const uptr kRegionSize = 1 << kRegionSizeLog;    static const uptr kNumPossibleRegions = kSpaceSize / kRegionSize; -  struct SizeClassInfo { -    SpinMutex mutex; +  struct ALIGNED(SANITIZER_CACHE_LINE_SIZE) SizeClassInfo { +    StaticSpinMutex mutex;      IntrusiveList<TransferBatch> free_list;      u32 rand_state; -    char padding[kCacheLineSize - 2 * sizeof(uptr) - -                 sizeof(IntrusiveList<TransferBatch>)];    }; -  COMPILER_CHECK(sizeof(SizeClassInfo) == kCacheLineSize); +  COMPILER_CHECK(sizeof(SizeClassInfo) % kCacheLineSize == 0);    uptr ComputeRegionId(uptr mem) { -    uptr res = mem >> kRegionSizeLog; +    const uptr res = mem >> kRegionSizeLog;      CHECK_LT(res, kNumPossibleRegions);      return res;    } @@ -285,9 +279,9 @@ class SizeClassAllocator32 {    }    uptr AllocateRegion(AllocatorStats *stat, uptr class_id) { -    CHECK_LT(class_id, kNumClasses); -    uptr res = reinterpret_cast<uptr>(MmapAlignedOrDieOnFatalError( -        kRegionSize, kRegionSize, "SizeClassAllocator32")); +    DCHECK_LT(class_id, kNumClasses); +    const uptr res = reinterpret_cast<uptr>(MmapAlignedOrDieOnFatalError( +        kRegionSize, kRegionSize, PrimaryAllocatorName));      if (UNLIKELY(!res))        return 0;      MapUnmapCallback().OnMap(res, kRegionSize); @@ -298,7 +292,7 @@ class SizeClassAllocator32 {    }    SizeClassInfo *GetSizeClassInfo(uptr class_id) { -    CHECK_LT(class_id, kNumClasses); +    DCHECK_LT(class_id, kNumClasses);      return &size_class_info_array[class_id];    } @@ -329,22 +323,22 @@ class SizeClassAllocator32 {    bool PopulateFreeList(AllocatorStats *stat, AllocatorCache *c,                          SizeClassInfo *sci, uptr class_id) { -    uptr size = ClassIdToSize(class_id); -    uptr reg = AllocateRegion(stat, class_id); -    if (UNLIKELY(!reg)) +    const uptr region = AllocateRegion(stat, class_id); +    if (UNLIKELY(!region))        return false;      if (kRandomShuffleChunks)        if (UNLIKELY(sci->rand_state == 0))          // The random state is initialized from ASLR (PIE) and time.          sci->rand_state = reinterpret_cast<uptr>(sci) ^ NanoTime(); -    uptr n_chunks = kRegionSize / (size + kMetadataSize); -    uptr max_count = TransferBatch::MaxCached(class_id); -    CHECK_GT(max_count, 0); +    const uptr size = ClassIdToSize(class_id); +    const uptr n_chunks = kRegionSize / (size + kMetadataSize); +    const uptr max_count = TransferBatch::MaxCached(size); +    DCHECK_GT(max_count, 0);      TransferBatch *b = nullptr; -    const uptr kShuffleArraySize = 48; +    constexpr uptr kShuffleArraySize = 48;      uptr shuffle_array[kShuffleArraySize];      uptr count = 0; -    for (uptr i = reg; i < reg + n_chunks * size; i += size) { +    for (uptr i = region; i < region + n_chunks * size; i += size) {        shuffle_array[count++] = i;        if (count == kShuffleArraySize) {          if (UNLIKELY(!PopulateBatches(c, sci, class_id, &b, max_count, diff --git a/lib/sanitizer_common/sanitizer_allocator_primary64.h b/lib/sanitizer_common/sanitizer_allocator_primary64.h index 651a64b04f2ea..6acb4f8bc56dd 100644 --- a/lib/sanitizer_common/sanitizer_allocator_primary64.h +++ b/lib/sanitizer_common/sanitizer_allocator_primary64.h @@ -72,14 +72,17 @@ class SizeClassAllocator64 {    void Init(s32 release_to_os_interval_ms) {      uptr TotalSpaceSize = kSpaceSize + AdditionalSize();      if (kUsingConstantSpaceBeg) { -      CHECK_EQ(kSpaceBeg, address_range.Init(TotalSpaceSize, AllocatorName(), -                                             kSpaceBeg)); +      CHECK_EQ(kSpaceBeg, address_range.Init(TotalSpaceSize, +                                             PrimaryAllocatorName, kSpaceBeg));      } else { -      NonConstSpaceBeg = address_range.Init(TotalSpaceSize, AllocatorName()); +      NonConstSpaceBeg = address_range.Init(TotalSpaceSize, +                                            PrimaryAllocatorName);        CHECK_NE(NonConstSpaceBeg, ~(uptr)0);      }      SetReleaseToOSIntervalMs(release_to_os_interval_ms);      MapWithCallbackOrDie(SpaceEnd(), AdditionalSize()); +    // Check that the RegionInfo array is aligned on the CacheLine size. +    DCHECK_EQ(SpaceEnd() % kCacheLineSize, 0);    }    s32 ReleaseToOSIntervalMs() const { @@ -115,8 +118,12 @@ class SizeClassAllocator64 {      // Failure to allocate free array space while releasing memory is non      // recoverable.      if (UNLIKELY(!EnsureFreeArraySpace(region, region_beg, -                                       new_num_freed_chunks))) -      DieOnFailure::OnOOM(); +                                       new_num_freed_chunks))) { +      Report("FATAL: Internal error: %s's allocator exhausted the free list " +             "space for size class %zd (%zd bytes).\n", SanitizerToolName, +             class_id, ClassIdToSize(class_id)); +      Die(); +    }      for (uptr i = 0; i < n_chunks; i++)        free_array[old_num_chunks + i] = chunks[i];      region->num_freed_chunks = new_num_freed_chunks; @@ -544,7 +551,6 @@ class SizeClassAllocator64 {    friend class MemoryMapper;    ReservedAddressRange address_range; -  static const char *AllocatorName() { return "sanitizer_allocator"; }    static const uptr kRegionSize = kSpaceSize / kNumClassesRounded;    // FreeArray is the array of free-d chunks (stored as 4-byte offsets). @@ -584,7 +590,7 @@ class SizeClassAllocator64 {      u64 last_released_bytes;    }; -  struct RegionInfo { +  struct ALIGNED(SANITIZER_CACHE_LINE_SIZE) RegionInfo {      BlockingMutex mutex;      uptr num_freed_chunks;  // Number of elements in the freearray.      uptr mapped_free_array;  // Bytes mapped for freearray. @@ -597,12 +603,11 @@ class SizeClassAllocator64 {      Stats stats;      ReleaseToOsInfo rtoi;    }; -  COMPILER_CHECK(sizeof(RegionInfo) >= kCacheLineSize); +  COMPILER_CHECK(sizeof(RegionInfo) % kCacheLineSize == 0);    RegionInfo *GetRegionInfo(uptr class_id) const { -    CHECK_LT(class_id, kNumClasses); -    RegionInfo *regions = -        reinterpret_cast<RegionInfo *>(SpaceBeg() + kSpaceSize); +    DCHECK_LT(class_id, kNumClasses); +    RegionInfo *regions = reinterpret_cast<RegionInfo *>(SpaceEnd());      return ®ions[class_id];    } diff --git a/lib/sanitizer_common/sanitizer_allocator_report.cc b/lib/sanitizer_common/sanitizer_allocator_report.cc new file mode 100644 index 0000000000000..e93f90c2a4b73 --- /dev/null +++ b/lib/sanitizer_common/sanitizer_allocator_report.cc @@ -0,0 +1,125 @@ +//===-- sanitizer_allocator_report.cc ---------------------------*- C++ -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Shared allocator error reporting for ThreadSanitizer, MemorySanitizer, etc. +/// +//===----------------------------------------------------------------------===// + +#include "sanitizer_allocator.h" +#include "sanitizer_allocator_report.h" +#include "sanitizer_common.h" +#include "sanitizer_report_decorator.h" + +namespace __sanitizer { + +class ScopedAllocatorErrorReport { + public: +  ScopedAllocatorErrorReport(const char *error_summary_, +                             const StackTrace *stack_) +      : error_summary(error_summary_), +        stack(stack_) { +    Printf("%s", d.Error()); +  } +  ~ScopedAllocatorErrorReport() { +    Printf("%s", d.Default()); +    stack->Print(); +    PrintHintAllocatorCannotReturnNull(); +    ReportErrorSummary(error_summary, stack); +  } + + private: +  ScopedErrorReportLock lock; +  const char *error_summary; +  const StackTrace* const stack; +  const SanitizerCommonDecorator d; +}; + +void NORETURN ReportCallocOverflow(uptr count, uptr size, +                                   const StackTrace *stack) { +  { +    ScopedAllocatorErrorReport report("calloc-overflow", stack); +    Report("ERROR: %s: calloc parameters overflow: count * size (%zd * %zd) " +           "cannot be represented in type size_t\n", SanitizerToolName, count, +           size); +  } +  Die(); +} + +void NORETURN ReportPvallocOverflow(uptr size, const StackTrace *stack) { +  { +    ScopedAllocatorErrorReport report("pvalloc-overflow", stack); +    Report("ERROR: %s: pvalloc parameters overflow: size 0x%zx rounded up to " +           "system page size 0x%zx cannot be represented in type size_t\n", +           SanitizerToolName, size, GetPageSizeCached()); +  } +  Die(); +} + +void NORETURN ReportInvalidAllocationAlignment(uptr alignment, +                                               const StackTrace *stack) { +  { +    ScopedAllocatorErrorReport report("invalid-allocation-alignment", stack); +    Report("ERROR: %s: invalid allocation alignment: %zd, alignment must be a " +           "power of two\n", SanitizerToolName, alignment); +  } +  Die(); +} + +void NORETURN ReportInvalidAlignedAllocAlignment(uptr size, uptr alignment, +                                                 const StackTrace *stack) { +  { +    ScopedAllocatorErrorReport report("invalid-aligned-alloc-alignment", stack); +#if SANITIZER_POSIX +    Report("ERROR: %s: invalid alignment requested in " +           "aligned_alloc: %zd, alignment must be a power of two and the " +           "requested size 0x%zx must be a multiple of alignment\n", +           SanitizerToolName, alignment, size); +#else +    Report("ERROR: %s: invalid alignment requested in aligned_alloc: %zd, " +           "the requested size 0x%zx must be a multiple of alignment\n", +           SanitizerToolName, alignment, size); +#endif +  } +  Die(); +} + +void NORETURN ReportInvalidPosixMemalignAlignment(uptr alignment, +                                                  const StackTrace *stack) { +  { +    ScopedAllocatorErrorReport report("invalid-posix-memalign-alignment", +                                      stack); +    Report("ERROR: %s: invalid alignment requested in " +           "posix_memalign: %zd, alignment must be a power of two and a " +           "multiple of sizeof(void*) == %zd\n", SanitizerToolName, alignment, +           sizeof(void*));  // NOLINT +  } +  Die(); +} + +void NORETURN ReportAllocationSizeTooBig(uptr user_size, uptr max_size, +                                         const StackTrace *stack) { +  { +    ScopedAllocatorErrorReport report("allocation-size-too-big", stack); +    Report("ERROR: %s: requested allocation size 0x%zx exceeds maximum " +           "supported size of 0x%zx\n", SanitizerToolName, user_size, max_size); +  } +  Die(); +} + +void NORETURN ReportOutOfMemory(uptr requested_size, const StackTrace *stack) { +  { +    ScopedAllocatorErrorReport report("out-of-memory", stack); +    Report("ERROR: %s: allocator is out of memory trying to allocate 0x%zx " +           "bytes\n", SanitizerToolName, requested_size); +  } +  Die(); +} + +}  // namespace __sanitizer diff --git a/lib/sanitizer_common/sanitizer_allocator_report.h b/lib/sanitizer_common/sanitizer_allocator_report.h new file mode 100644 index 0000000000000..b19b22fa5359b --- /dev/null +++ b/lib/sanitizer_common/sanitizer_allocator_report.h @@ -0,0 +1,38 @@ +//===-- sanitizer_allocator_report.h ----------------------------*- C++ -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Shared allocator error reporting for ThreadSanitizer, MemorySanitizer, etc. +/// +//===----------------------------------------------------------------------===// + +#ifndef SANITIZER_ALLOCATOR_REPORT_H +#define SANITIZER_ALLOCATOR_REPORT_H + +#include "sanitizer_internal_defs.h" +#include "sanitizer_stacktrace.h" + +namespace __sanitizer { + +void NORETURN ReportCallocOverflow(uptr count, uptr size, +                                   const StackTrace *stack); +void NORETURN ReportPvallocOverflow(uptr size, const StackTrace *stack); +void NORETURN ReportInvalidAllocationAlignment(uptr alignment, +                                               const StackTrace *stack); +void NORETURN ReportInvalidAlignedAllocAlignment(uptr size, uptr alignment, +                                                 const StackTrace *stack); +void NORETURN ReportInvalidPosixMemalignAlignment(uptr alignment, +                                                  const StackTrace *stack); +void NORETURN ReportAllocationSizeTooBig(uptr user_size, uptr max_size, +                                         const StackTrace *stack); +void NORETURN ReportOutOfMemory(uptr requested_size, const StackTrace *stack); + +}  // namespace __sanitizer + +#endif  // SANITIZER_ALLOCATOR_REPORT_H diff --git a/lib/sanitizer_common/sanitizer_allocator_secondary.h b/lib/sanitizer_common/sanitizer_allocator_secondary.h index 261dfb5e1a285..ab680b5e2d115 100644 --- a/lib/sanitizer_common/sanitizer_allocator_secondary.h +++ b/lib/sanitizer_common/sanitizer_allocator_secondary.h @@ -14,17 +14,66 @@  #error This file must be included inside sanitizer_allocator.h  #endif +// Fixed array to store LargeMmapAllocator chunks list, limited to 32K total +// allocated chunks. To be used in memory constrained or not memory hungry cases +// (currently, 32 bits and internal allocator). +class LargeMmapAllocatorPtrArrayStatic { + public: +  INLINE void *Init() { return &p_[0]; } +  INLINE void EnsureSpace(uptr n) { CHECK_LT(n, kMaxNumChunks); } + private: +  static const int kMaxNumChunks = 1 << 15; +  uptr p_[kMaxNumChunks]; +}; + +// Much less restricted LargeMmapAllocator chunks list (comparing to +// PtrArrayStatic). Backed by mmaped memory region and can hold up to 1M chunks. +// ReservedAddressRange was used instead of just MAP_NORESERVE to achieve the +// same functionality in Fuchsia case, which does not support MAP_NORESERVE. +class LargeMmapAllocatorPtrArrayDynamic { + public: +  INLINE void *Init() { +    uptr p = address_range_.Init(kMaxNumChunks * sizeof(uptr), +                                 SecondaryAllocatorName); +    CHECK(p); +    return reinterpret_cast<void*>(p); +  } + +  INLINE void EnsureSpace(uptr n) { +    CHECK_LT(n, kMaxNumChunks); +    DCHECK(n <= n_reserved_); +    if (UNLIKELY(n == n_reserved_)) { +      address_range_.MapOrDie( +          reinterpret_cast<uptr>(address_range_.base()) + +              n_reserved_ * sizeof(uptr), +          kChunksBlockCount * sizeof(uptr)); +      n_reserved_ += kChunksBlockCount; +    } +  } + + private: +  static const int kMaxNumChunks = 1 << 20; +  static const int kChunksBlockCount = 1 << 14; +  ReservedAddressRange address_range_; +  uptr n_reserved_; +}; + +#if SANITIZER_WORDSIZE == 32 +typedef LargeMmapAllocatorPtrArrayStatic DefaultLargeMmapAllocatorPtrArray; +#else +typedef LargeMmapAllocatorPtrArrayDynamic DefaultLargeMmapAllocatorPtrArray; +#endif +  // This class can (de)allocate only large chunks of memory using mmap/unmap.  // The main purpose of this allocator is to cover large and rare allocation  // sizes not covered by more efficient allocators (e.g. SizeClassAllocator64).  template <class MapUnmapCallback = NoOpMapUnmapCallback, -          class FailureHandlerT = ReturnNullOrDieOnFailure> +          class PtrArrayT = DefaultLargeMmapAllocatorPtrArray>  class LargeMmapAllocator {   public: -  typedef FailureHandlerT FailureHandler; -    void InitLinkerInitialized() {      page_size_ = GetPageSizeCached(); +    chunks_ = reinterpret_cast<Header**>(ptr_array_.Init());    }    void Init() { @@ -38,12 +87,16 @@ class LargeMmapAllocator {      if (alignment > page_size_)        map_size += alignment;      // Overflow. -    if (map_size < size) -      return FailureHandler::OnBadRequest(); +    if (map_size < size) { +      Report("WARNING: %s: LargeMmapAllocator allocation overflow: " +             "0x%zx bytes with 0x%zx alignment requested\n", +             SanitizerToolName, map_size, alignment); +      return nullptr; +    }      uptr map_beg = reinterpret_cast<uptr>( -        MmapOrDieOnFatalError(map_size, "LargeMmapAllocator")); +        MmapOrDieOnFatalError(map_size, SecondaryAllocatorName));      if (!map_beg) -      return FailureHandler::OnOOM(); +      return nullptr;      CHECK(IsAligned(map_beg, page_size_));      MapUnmapCallback().OnMap(map_beg, map_size);      uptr map_end = map_beg + map_size; @@ -62,11 +115,11 @@ class LargeMmapAllocator {      CHECK_LT(size_log, ARRAY_SIZE(stats.by_size_log));      {        SpinMutexLock l(&mutex_); +      ptr_array_.EnsureSpace(n_chunks_);        uptr idx = n_chunks_++; -      chunks_sorted_ = false; -      CHECK_LT(idx, kMaxNumChunks);        h->chunk_idx = idx;        chunks_[idx] = h; +      chunks_sorted_ = false;        stats.n_allocs++;        stats.currently_allocated += map_size;        stats.max_allocated = Max(stats.max_allocated, stats.currently_allocated); @@ -84,9 +137,8 @@ class LargeMmapAllocator {        uptr idx = h->chunk_idx;        CHECK_EQ(chunks_[idx], h);        CHECK_LT(idx, n_chunks_); -      chunks_[idx] = chunks_[n_chunks_ - 1]; +      chunks_[idx] = chunks_[--n_chunks_];        chunks_[idx]->chunk_idx = idx; -      n_chunks_--;        chunks_sorted_ = false;        stats.n_frees++;        stats.currently_allocated -= h->map_size; @@ -150,7 +202,7 @@ class LargeMmapAllocator {    void EnsureSortedChunks() {      if (chunks_sorted_) return; -    SortArray(reinterpret_cast<uptr*>(chunks_), n_chunks_); +    Sort(reinterpret_cast<uptr *>(chunks_), n_chunks_);      for (uptr i = 0; i < n_chunks_; i++)        chunks_[i]->chunk_idx = i;      chunks_sorted_ = true; @@ -222,7 +274,7 @@ class LargeMmapAllocator {      EnsureSortedChunks();  // Avoid doing the sort while iterating.      for (uptr i = 0; i < n_chunks_; i++) {        auto t = chunks_[i]; -      callback(reinterpret_cast<uptr>(GetUser(chunks_[i])), arg); +      callback(reinterpret_cast<uptr>(GetUser(t)), arg);        // Consistency check: verify that the array did not change.        CHECK_EQ(chunks_[i], t);        CHECK_EQ(chunks_[i]->chunk_idx, i); @@ -230,7 +282,6 @@ class LargeMmapAllocator {    }   private: -  static const int kMaxNumChunks = 1 << FIRST_32_SECOND_64(15, 18);    struct Header {      uptr map_beg;      uptr map_size; @@ -256,13 +307,13 @@ class LargeMmapAllocator {    }    uptr page_size_; -  Header *chunks_[kMaxNumChunks]; +  Header **chunks_; +  PtrArrayT ptr_array_;    uptr n_chunks_;    bool chunks_sorted_;    struct Stats {      uptr n_allocs, n_frees, currently_allocated, max_allocated, by_size_log[64];    } stats; -  SpinMutex mutex_; +  StaticSpinMutex mutex_;  }; - diff --git a/lib/sanitizer_common/sanitizer_allocator_size_class_map.h b/lib/sanitizer_common/sanitizer_allocator_size_class_map.h index 2bd83b2eb5a42..77ab4fb544a29 100644 --- a/lib/sanitizer_common/sanitizer_allocator_size_class_map.h +++ b/lib/sanitizer_common/sanitizer_allocator_size_class_map.h @@ -161,23 +161,24 @@ class SizeClassMap {        return 0;      if (size <= kMidSize)        return (size + kMinSize - 1) >> kMinSizeLog; -    uptr l = MostSignificantSetBitIndex(size); -    uptr hbits = (size >> (l - S)) & M; -    uptr lbits = size & ((1 << (l - S)) - 1); -    uptr l1 = l - kMidSizeLog; +    const uptr l = MostSignificantSetBitIndex(size); +    const uptr hbits = (size >> (l - S)) & M; +    const uptr lbits = size & ((1U << (l - S)) - 1); +    const uptr l1 = l - kMidSizeLog;      return kMidClass + (l1 << S) + hbits + (lbits > 0);    } -  static uptr MaxCachedHint(uptr class_id) { -    // Estimate the result for kBatchClassID because this class does not know -    // the exact size of TransferBatch. We need to cache fewer batches than user -    // chunks, so this number can be small. -    if (UNLIKELY(class_id == kBatchClassID)) -      return 16; -    if (UNLIKELY(class_id == 0)) +  static uptr MaxCachedHint(uptr size) { +    DCHECK_LE(size, kMaxSize); +    if (UNLIKELY(size == 0))        return 0; -    uptr n = (1UL << kMaxBytesCachedLog) / Size(class_id); -    return Max<uptr>(1, Min(kMaxNumCachedHint, n)); +    uptr n; +    // Force a 32-bit division if the template parameters allow for it. +    if (kMaxBytesCachedLog > 31 || kMaxSizeLog > 31) +      n = (1UL << kMaxBytesCachedLog) / size; +    else +      n = (1U << kMaxBytesCachedLog) / static_cast<u32>(size); +    return Max<uptr>(1U, Min(kMaxNumCachedHint, n));    }    static void Print() { @@ -190,12 +191,12 @@ class SizeClassMap {        uptr d = s - prev_s;        uptr p = prev_s ? (d * 100 / prev_s) : 0;        uptr l = s ? MostSignificantSetBitIndex(s) : 0; -      uptr cached = MaxCachedHint(i) * s; +      uptr cached = MaxCachedHint(s) * s;        if (i == kBatchClassID)          d = p = l = 0;        Printf("c%02zd => s: %zd diff: +%zd %02zd%% l %zd "               "cached: %zd %zd; id %zd\n", -             i, Size(i), d, p, l, MaxCachedHint(i), cached, ClassID(s)); +             i, Size(i), d, p, l, MaxCachedHint(s), cached, ClassID(s));        total_cached += cached;        prev_s = s;      } diff --git a/lib/sanitizer_common/sanitizer_allocator_stats.h b/lib/sanitizer_common/sanitizer_allocator_stats.h index 38b088b8446ed..76df3ed8de539 100644 --- a/lib/sanitizer_common/sanitizer_allocator_stats.h +++ b/lib/sanitizer_common/sanitizer_allocator_stats.h @@ -101,7 +101,7 @@ class AllocatorGlobalStats : public AllocatorStats {    }   private: -  mutable SpinMutex mu_; +  mutable StaticSpinMutex mu_;  }; diff --git a/lib/sanitizer_common/sanitizer_atomic_clang_other.h b/lib/sanitizer_common/sanitizer_atomic_clang_other.h index 35e2d007eda86..2eea549c0fdd1 100644 --- a/lib/sanitizer_common/sanitizer_atomic_clang_other.h +++ b/lib/sanitizer_common/sanitizer_atomic_clang_other.h @@ -86,7 +86,7 @@ INLINE void atomic_store(volatile T *a, typename T::Type v, memory_order mo) {      typename T::Type cur;      for (;;) {        cur = __sync_val_compare_and_swap(&a->val_dont_use, cmp, v); -      if (cmp == v) +      if (cur == cmp || cur == v)          break;        cmp = cur;      } diff --git a/lib/sanitizer_common/sanitizer_common.cc b/lib/sanitizer_common/sanitizer_common.cc index ae26d5efc24fd..7d72b0cfe4cec 100644 --- a/lib/sanitizer_common/sanitizer_common.cc +++ b/lib/sanitizer_common/sanitizer_common.cc @@ -14,11 +14,10 @@  #include "sanitizer_common.h"  #include "sanitizer_allocator_interface.h"  #include "sanitizer_allocator_internal.h" +#include "sanitizer_atomic.h"  #include "sanitizer_flags.h"  #include "sanitizer_libc.h"  #include "sanitizer_placement_new.h" -#include "sanitizer_stacktrace_printer.h" -#include "sanitizer_symbolizer.h"  namespace __sanitizer { @@ -39,9 +38,10 @@ void NORETURN ReportMmapFailureAndDie(uptr size, const char *mem_type,                                        const char *mmap_type, error_t err,                                        bool raw_report) {    static int recursion_count; -  if (raw_report || recursion_count) { -    // If raw report is requested or we went into recursion, just die. -    // The Report() and CHECK calls below may call mmap recursively and fail. +  if (SANITIZER_RTEMS || raw_report || recursion_count) { +    // If we are on RTEMS or raw report is requested or we went into recursion, +    // just die.  The Report() and CHECK calls below may call mmap recursively +    // and fail.      RawWrite("ERROR: Failed to mmap\n");      Die();    } @@ -58,19 +58,6 @@ void NORETURN ReportMmapFailureAndDie(uptr size, const char *mem_type,  typedef bool UptrComparisonFunction(const uptr &a, const uptr &b);  typedef bool U32ComparisonFunction(const u32 &a, const u32 &b); -template<class T> -static inline bool CompareLess(const T &a, const T &b) { -  return a < b; -} - -void SortArray(uptr *array, uptr size) { -  InternalSort<uptr*, UptrComparisonFunction>(&array, size, CompareLess); -} - -void SortArray(u32 *array, uptr size) { -  InternalSort<u32*, U32ComparisonFunction>(&array, size, CompareLess); -} -  const char *StripPathPrefix(const char *filepath,                              const char *strip_path_prefix) {    if (!filepath) return nullptr; @@ -107,18 +94,6 @@ void ReportErrorSummary(const char *error_message, const char *alt_tool_name) {    __sanitizer_report_error_summary(buff.data());  } -#if !SANITIZER_GO -void ReportErrorSummary(const char *error_type, const AddressInfo &info, -                        const char *alt_tool_name) { -  if (!common_flags()->print_summary) return; -  InternalScopedString buff(kMaxSummaryLength); -  buff.append("%s ", error_type); -  RenderFrame(&buff, "%L %F", 0, info, common_flags()->symbolize_vs_style, -              common_flags()->strip_path_prefix); -  ReportErrorSummary(buff.data(), alt_tool_name); -} -#endif -  // Removes the ANSI escape sequences from the input string (in-place).  void RemoveANSIEscapeSequencesFromString(char *str) {    if (!str) @@ -358,6 +333,12 @@ SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_report_error_summary,  }  SANITIZER_INTERFACE_ATTRIBUTE +int __sanitizer_acquire_crash_state() { +  static atomic_uint8_t in_crash_state = {}; +  return !atomic_exchange(&in_crash_state, 1, memory_order_relaxed); +} + +SANITIZER_INTERFACE_ATTRIBUTE  void __sanitizer_set_death_callback(void (*callback)(void)) {    SetUserDieCallback(callback);  } diff --git a/lib/sanitizer_common/sanitizer_common.h b/lib/sanitizer_common/sanitizer_common.h index 1fbaee7e39a10..3b999edfbe586 100644 --- a/lib/sanitizer_common/sanitizer_common.h +++ b/lib/sanitizer_common/sanitizer_common.h @@ -39,11 +39,7 @@ struct StackTrace;  const uptr kWordSize = SANITIZER_WORDSIZE / 8;  const uptr kWordSizeInBits = 8 * kWordSize; -#if defined(__powerpc__) || defined(__powerpc64__) -  const uptr kCacheLineSize = 128; -#else -  const uptr kCacheLineSize = 64; -#endif +const uptr kCacheLineSize = SANITIZER_CACHE_LINE_SIZE;  const uptr kMaxPathLength = 4096; @@ -52,7 +48,7 @@ const uptr kMaxThreadStackSize = 1 << 30;  // 1Gb  static const uptr kErrorMessageBufferSize = 1 << 16;  // Denotes fake PC values that come from JIT/JAVA/etc. -// For such PC values __tsan_symbolize_external() will be called. +// For such PC values __tsan_symbolize_external_ex() will be called.  const u64 kExternalPCBit = 1ULL << 60;  extern const char *SanitizerToolName;  // Can be changed by the tool. @@ -92,8 +88,8 @@ void UnmapOrDie(void *addr, uptr size);  // Behaves just like MmapOrDie, but tolerates out of memory condition, in that  // case returns nullptr.  void *MmapOrDieOnFatalError(uptr size, const char *mem_type); -void *MmapFixedNoReserve(uptr fixed_addr, uptr size, -                         const char *name = nullptr); +bool MmapFixedNoReserve(uptr fixed_addr, uptr size, const char *name = nullptr) +     WARN_UNUSED_RESULT;  void *MmapNoReserveOrDie(uptr size, const char *mem_type);  void *MmapFixedOrDie(uptr fixed_addr, uptr size);  // Behaves just like MmapFixedOrDie, but tolerates out of memory condition, in @@ -110,9 +106,11 @@ void *MmapAlignedOrDieOnFatalError(uptr size, uptr alignment,  bool MprotectNoAccess(uptr addr, uptr size);  bool MprotectReadOnly(uptr addr, uptr size); +void MprotectMallocZones(void *addr, int prot); +  // Find an available address space.  uptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding, -                              uptr *largest_gap_found); +                              uptr *largest_gap_found, uptr *max_occupied_addr);  // Used to check if we can map shadow memory to a fixed location.  bool MemoryRangeIsAvailable(uptr range_start, uptr range_end); @@ -122,8 +120,8 @@ void ReleaseMemoryPagesToOS(uptr beg, uptr end);  void IncreaseTotalMmap(uptr size);  void DecreaseTotalMmap(uptr size);  uptr GetRSS(); -void NoHugePagesInRegion(uptr addr, uptr length); -void DontDumpShadowMemory(uptr addr, uptr length); +bool NoHugePagesInRegion(uptr addr, uptr length); +bool DontDumpShadowMemory(uptr addr, uptr length);  // Check if the built VMA size matches the runtime one.  void CheckVMASize();  void RunMallocHooks(const void *ptr, uptr size); @@ -153,49 +151,6 @@ typedef void (*fill_profile_f)(uptr start, uptr rss, bool file,  // |stats_size| elements.  void GetMemoryProfile(fill_profile_f cb, uptr *stats, uptr stats_size); -// InternalScopedBuffer can be used instead of large stack arrays to -// keep frame size low. -// FIXME: use InternalAlloc instead of MmapOrDie once -// InternalAlloc is made libc-free. -template <typename T> -class InternalScopedBuffer { - public: -  explicit InternalScopedBuffer(uptr cnt) { -    cnt_ = cnt; -    ptr_ = (T *)MmapOrDie(cnt * sizeof(T), "InternalScopedBuffer"); -  } -  ~InternalScopedBuffer() { UnmapOrDie(ptr_, cnt_ * sizeof(T)); } -  T &operator[](uptr i) { return ptr_[i]; } -  T *data() { return ptr_; } -  uptr size() { return cnt_ * sizeof(T); } - - private: -  T *ptr_; -  uptr cnt_; -  // Disallow copies and moves. -  InternalScopedBuffer(const InternalScopedBuffer &) = delete; -  InternalScopedBuffer &operator=(const InternalScopedBuffer &) = delete; -  InternalScopedBuffer(InternalScopedBuffer &&) = delete; -  InternalScopedBuffer &operator=(InternalScopedBuffer &&) = delete; -}; - -class InternalScopedString : public InternalScopedBuffer<char> { - public: -  explicit InternalScopedString(uptr max_length) -      : InternalScopedBuffer<char>(max_length), length_(0) { -    (*this)[0] = '\0'; -  } -  uptr length() { return length_; } -  void clear() { -    (*this)[0] = '\0'; -    length_ = 0; -  } -  void append(const char *format, ...); - - private: -  uptr length_; -}; -  // Simple low-level (mmap-based) allocator for internal use. Doesn't have  // constructor, so all instances of LowLevelAllocator should be  // linker initialized. @@ -243,15 +198,6 @@ class ScopedErrorReportLock {  extern uptr stoptheworld_tracer_pid;  extern uptr stoptheworld_tracer_ppid; -// Opens the file 'file_name" and reads up to 'max_len' bytes. -// The resulting buffer is mmaped and stored in '*buff'. -// The size of the mmaped region is stored in '*buff_size'. -// The total number of read bytes is stored in '*read_len'. -// Returns true if file was successfully opened and read. -bool ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size, -                      uptr *read_len, uptr max_len = 1 << 26, -                      error_t *errno_p = nullptr); -  bool IsAccessibleMemoryRange(uptr beg, uptr size);  // Error report formatting. @@ -275,6 +221,7 @@ bool SetEnv(const char *name, const char *value);  u32 GetUid();  void ReExec(); +void CheckASLR();  char **GetArgv();  void PrintCmdline();  bool StackSizeIsUnlimited(); @@ -283,7 +230,7 @@ void SetStackSizeLimitInBytes(uptr limit);  bool AddressSpaceIsUnlimited();  void SetAddressSpaceUnlimited();  void AdjustStackSize(void *attr); -void PrepareForSandboxing(__sanitizer_sandbox_arguments *args); +void PlatformPrepareForSandboxing(__sanitizer_sandbox_arguments *args);  void SetSandboxingCallback(void (*f)());  void InitializeCoverage(bool enabled, const char *coverage_dir); @@ -297,8 +244,6 @@ void SleepForMillis(int millis);  u64 NanoTime();  u64 MonotonicNanoTime();  int Atexit(void (*function)(void)); -void SortArray(uptr *array, uptr size); -void SortArray(u32 *array, uptr size);  bool TemplateMatch(const char *templ, const char *str);  // Exit @@ -310,13 +255,6 @@ void NORETURN ReportMmapFailureAndDie(uptr size, const char *mem_type,                                        const char *mmap_type, error_t err,                                        bool raw_report = false); -// Set the name of the current thread to 'name', return true on succees. -// The name may be truncated to a system-dependent limit. -bool SanitizerSetThreadName(const char *name); -// Get the name of the current thread (no more than max_len bytes), -// return true on succees. name should have space for at least max_len+1 bytes. -bool SanitizerGetThreadName(char *name, int max_len); -  // Specific tools may override behavior of "Die" and "CheckFailed" functions  // to do tool-specific job.  typedef void (*DieCallbackType)(void); @@ -382,6 +320,8 @@ void ReportErrorSummary(const char *error_type, const AddressInfo &info,  void ReportErrorSummary(const char *error_type, const StackTrace *trace,                          const char *alt_tool_name = nullptr); +void ReportMmapWriteExec(int prot); +  // Math  #if SANITIZER_WINDOWS && !defined(__clang__) && !defined(__GNUC__)  extern "C" { @@ -489,13 +429,12 @@ template<typename T>  class InternalMmapVectorNoCtor {   public:    void Initialize(uptr initial_capacity) { -    capacity_ = Max(initial_capacity, (uptr)1); +    capacity_bytes_ = 0;      size_ = 0; -    data_ = (T *)MmapOrDie(capacity_ * sizeof(T), "InternalMmapVectorNoCtor"); -  } -  void Destroy() { -    UnmapOrDie(data_, capacity_ * sizeof(T)); +    data_ = 0; +    reserve(initial_capacity);    } +  void Destroy() { UnmapOrDie(data_, capacity_bytes_); }    T &operator[](uptr i) {      CHECK_LT(i, size_);      return data_[i]; @@ -505,10 +444,10 @@ class InternalMmapVectorNoCtor {      return data_[i];    }    void push_back(const T &element) { -    CHECK_LE(size_, capacity_); -    if (size_ == capacity_) { +    CHECK_LE(size_, capacity()); +    if (size_ == capacity()) {        uptr new_capacity = RoundUpToPowerOfTwo(size_ + 1); -      Resize(new_capacity); +      Realloc(new_capacity);      }      internal_memcpy(&data_[size_++], &element, sizeof(T));    } @@ -529,12 +468,15 @@ class InternalMmapVectorNoCtor {    T *data() {      return data_;    } -  uptr capacity() const { -    return capacity_; +  uptr capacity() const { return capacity_bytes_ / sizeof(T); } +  void reserve(uptr new_size) { +    // Never downsize internal buffer. +    if (new_size > capacity()) +      Realloc(new_size);    }    void resize(uptr new_size) { -    Resize(new_size);      if (new_size > size_) { +      reserve(new_size);        internal_memset(&data_[size_], 0, sizeof(T) * (new_size - size_));      }      size_ = new_size; @@ -556,39 +498,84 @@ class InternalMmapVectorNoCtor {      return data() + size();    } +  void swap(InternalMmapVectorNoCtor &other) { +    Swap(data_, other.data_); +    Swap(capacity_bytes_, other.capacity_bytes_); +    Swap(size_, other.size_); +  } +   private: -  void Resize(uptr new_capacity) { +  void Realloc(uptr new_capacity) {      CHECK_GT(new_capacity, 0);      CHECK_LE(size_, new_capacity); -    T *new_data = (T *)MmapOrDie(new_capacity * sizeof(T), -                                 "InternalMmapVector"); +    uptr new_capacity_bytes = +        RoundUpTo(new_capacity * sizeof(T), GetPageSizeCached()); +    T *new_data = (T *)MmapOrDie(new_capacity_bytes, "InternalMmapVector");      internal_memcpy(new_data, data_, size_ * sizeof(T)); -    T *old_data = data_; +    UnmapOrDie(data_, capacity_bytes_);      data_ = new_data; -    UnmapOrDie(old_data, capacity_ * sizeof(T)); -    capacity_ = new_capacity; +    capacity_bytes_ = new_capacity_bytes;    }    T *data_; -  uptr capacity_; +  uptr capacity_bytes_;    uptr size_;  }; +template <typename T> +bool operator==(const InternalMmapVectorNoCtor<T> &lhs, +                const InternalMmapVectorNoCtor<T> &rhs) { +  if (lhs.size() != rhs.size()) return false; +  return internal_memcmp(lhs.data(), rhs.data(), lhs.size() * sizeof(T)) == 0; +} + +template <typename T> +bool operator!=(const InternalMmapVectorNoCtor<T> &lhs, +                const InternalMmapVectorNoCtor<T> &rhs) { +  return !(lhs == rhs); +} +  template<typename T>  class InternalMmapVector : public InternalMmapVectorNoCtor<T> {   public: -  explicit InternalMmapVector(uptr initial_capacity) { -    InternalMmapVectorNoCtor<T>::Initialize(initial_capacity); +  InternalMmapVector() { InternalMmapVectorNoCtor<T>::Initialize(1); } +  explicit InternalMmapVector(uptr cnt) { +    InternalMmapVectorNoCtor<T>::Initialize(cnt); +    this->resize(cnt);    }    ~InternalMmapVector() { InternalMmapVectorNoCtor<T>::Destroy(); } -  // Disallow evil constructors. -  InternalMmapVector(const InternalMmapVector&); -  void operator=(const InternalMmapVector&); +  // Disallow copies and moves. +  InternalMmapVector(const InternalMmapVector &) = delete; +  InternalMmapVector &operator=(const InternalMmapVector &) = delete; +  InternalMmapVector(InternalMmapVector &&) = delete; +  InternalMmapVector &operator=(InternalMmapVector &&) = delete; +}; + +class InternalScopedString : public InternalMmapVector<char> { + public: +  explicit InternalScopedString(uptr max_length) +      : InternalMmapVector<char>(max_length), length_(0) { +    (*this)[0] = '\0'; +  } +  uptr length() { return length_; } +  void clear() { +    (*this)[0] = '\0'; +    length_ = 0; +  } +  void append(const char *format, ...); + + private: +  uptr length_; +}; + +template <class T> +struct CompareLess { +  bool operator()(const T &a, const T &b) const { return a < b; }  };  // HeapSort for arrays and InternalMmapVector. -template<class Container, class Compare> -void InternalSort(Container *v, uptr size, Compare comp) { +template <class T, class Compare = CompareLess<T>> +void Sort(T *v, uptr size, Compare comp = {}) {    if (size < 2)      return;    // Stage 1: insert elements to the heap. @@ -596,8 +583,8 @@ void InternalSort(Container *v, uptr size, Compare comp) {      uptr j, p;      for (j = i; j > 0; j = p) {        p = (j - 1) / 2; -      if (comp((*v)[p], (*v)[j])) -        Swap((*v)[j], (*v)[p]); +      if (comp(v[p], v[j])) +        Swap(v[j], v[p]);        else          break;      } @@ -605,18 +592,18 @@ void InternalSort(Container *v, uptr size, Compare comp) {    // Stage 2: swap largest element with the last one,    // and sink the new top.    for (uptr i = size - 1; i > 0; i--) { -    Swap((*v)[0], (*v)[i]); +    Swap(v[0], v[i]);      uptr j, max_ind;      for (j = 0; j < i; j = max_ind) {        uptr left = 2 * j + 1;        uptr right = 2 * j + 2;        max_ind = j; -      if (left < i && comp((*v)[max_ind], (*v)[left])) +      if (left < i && comp(v[max_ind], v[left]))          max_ind = left; -      if (right < i && comp((*v)[max_ind], (*v)[right])) +      if (right < i && comp(v[max_ind], v[right]))          max_ind = right;        if (max_ind != j) -        Swap((*v)[j], (*v)[max_ind]); +        Swap(v[j], v[max_ind]);        else          break;      } @@ -650,6 +637,25 @@ enum ModuleArch {    kModuleArchARM64  }; +// Opens the file 'file_name" and reads up to 'max_len' bytes. +// The resulting buffer is mmaped and stored in '*buff'. +// Returns true if file was successfully opened and read. +bool ReadFileToVector(const char *file_name, +                      InternalMmapVectorNoCtor<char> *buff, +                      uptr max_len = 1 << 26, error_t *errno_p = nullptr); + +// Opens the file 'file_name" and reads up to 'max_len' bytes. +// This function is less I/O efficient than ReadFileToVector as it may reread +// file multiple times to avoid mmap during read attempts. It's used to read +// procmap, so short reads with mmap in between can produce inconsistent result. +// The resulting buffer is mmaped and stored in '*buff'. +// The size of the mmaped region is stored in '*buff_size'. +// The total number of read bytes is stored in '*read_len'. +// Returns true if file was successfully opened and read. +bool ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size, +                      uptr *read_len, uptr max_len = 1 << 26, +                      error_t *errno_p = nullptr); +  // When adding a new architecture, don't forget to also update  // script/asan_symbolize.py and sanitizer_symbolizer_libcdep.cc.  inline const char *ModuleArchToString(ModuleArch arch) { diff --git a/lib/sanitizer_common/sanitizer_common_interceptors.inc b/lib/sanitizer_common/sanitizer_common_interceptors.inc index 32342682a5952..ff18bc8017492 100644 --- a/lib/sanitizer_common/sanitizer_common_interceptors.inc +++ b/lib/sanitizer_common/sanitizer_common_interceptors.inc @@ -34,6 +34,7 @@  //   COMMON_INTERCEPTOR_MEMSET_IMPL  //   COMMON_INTERCEPTOR_MEMMOVE_IMPL  //   COMMON_INTERCEPTOR_MEMCPY_IMPL +//   COMMON_INTERCEPTOR_MMAP_IMPL  //   COMMON_INTERCEPTOR_COPY_STRING  //   COMMON_INTERCEPTOR_STRNDUP_IMPL  //===----------------------------------------------------------------------===// @@ -75,6 +76,7 @@  #define clock_settime __clock_settime50  #define ctime __ctime50  #define ctime_r __ctime_r50 +#define devname __devname50  #define getitimer __getitimer50  #define getpwent __getpwent50  #define getpwnam __getpwnam50 @@ -88,8 +90,10 @@  #define glob __glob30  #define gmtime __gmtime50  #define gmtime_r __gmtime_r50 +#define localtime __locatime50  #define localtime_r __localtime_r50  #define mktime __mktime50 +#define lstat __lstat50  #define opendir __opendir30  #define readdir __readdir30  #define readdir_r __readdir_r30 @@ -107,6 +111,9 @@  #define times __times13  #define wait3 __wait350  #define wait4 __wait450 +extern const unsigned short *_ctype_tab_; +extern const short *_toupper_tab_; +extern const short *_tolower_tab_;  #endif  // Platform-specific options. @@ -261,6 +268,12 @@ bool PlatformHasDifferentMemcpyAndMemmove();    }  #endif +#ifndef COMMON_INTERCEPTOR_MMAP_IMPL +#define COMMON_INTERCEPTOR_MMAP_IMPL(ctx, mmap, addr, sz, prot, flags, fd, \ +                                     off)                                  \ +  { return REAL(mmap)(addr, sz, prot, flags, fd, off); } +#endif +  #ifndef COMMON_INTERCEPTOR_COPY_STRING  #define COMMON_INTERCEPTOR_COPY_STRING(ctx, to, from, size) {}  #endif @@ -1176,6 +1189,50 @@ INTERCEPTOR(SSIZE_T, pwritev64, int fd, __sanitizer_iovec *iov, int iovcnt,  #define INIT_PWRITEV64  #endif +#if SANITIZER_INTERCEPT_FGETS +INTERCEPTOR(char *, fgets, char *s, SIZE_T size, void *file) { +  // libc file streams can call user-supplied functions, see fopencookie. +  void *ctx; +  COMMON_INTERCEPTOR_ENTER(ctx, fgets, s, size, file); +  // FIXME: under ASan the call below may write to freed memory and corrupt +  // its metadata. See +  // https://github.com/google/sanitizers/issues/321. +  char *res = REAL(fgets)(s, size, file); +  if (res) +    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, s, REAL(strlen)(s) + 1); +  return res; +} +#define INIT_FGETS COMMON_INTERCEPT_FUNCTION(fgets) +#else +#define INIT_FGETS +#endif + +#if SANITIZER_INTERCEPT_FPUTS +INTERCEPTOR_WITH_SUFFIX(int, fputs, char *s, void *file) { +  // libc file streams can call user-supplied functions, see fopencookie. +  void *ctx; +  COMMON_INTERCEPTOR_ENTER(ctx, fputs, s, file); +  COMMON_INTERCEPTOR_READ_RANGE(ctx, s, REAL(strlen)(s) + 1); +  return REAL(fputs)(s, file); +} +#define INIT_FPUTS COMMON_INTERCEPT_FUNCTION(fputs) +#else +#define INIT_FPUTS +#endif + +#if SANITIZER_INTERCEPT_PUTS +INTERCEPTOR(int, puts, char *s) { +  // libc file streams can call user-supplied functions, see fopencookie. +  void *ctx; +  COMMON_INTERCEPTOR_ENTER(ctx, puts, s); +  COMMON_INTERCEPTOR_READ_RANGE(ctx, s, REAL(strlen)(s) + 1); +  return REAL(puts)(s); +} +#define INIT_PUTS COMMON_INTERCEPT_FUNCTION(puts) +#else +#define INIT_PUTS +#endif +  #if SANITIZER_INTERCEPT_PRCTL  INTERCEPTOR(int, prctl, int option, unsigned long arg2,              unsigned long arg3,                        // NOLINT @@ -1703,6 +1760,7 @@ FORMAT_INTERCEPTOR_IMPL(__isoc99_snprintf, __isoc99_vsnprintf, str, size,  #if SANITIZER_INTERCEPT_IOCTL  #include "sanitizer_common_interceptors_ioctl.inc" +#include "sanitizer_interceptors_ioctl_netbsd.inc"  INTERCEPTOR(int, ioctl, int d, unsigned long request, ...) {    // We need a frame pointer, because we call into ioctl_common_[pre|post] which    // can trigger a report and we need to be able to unwind through this @@ -2125,8 +2183,19 @@ INTERCEPTOR(int, getitimer, int which, void *curr_value) {  INTERCEPTOR(int, setitimer, int which, const void *new_value, void *old_value) {    void *ctx;    COMMON_INTERCEPTOR_ENTER(ctx, setitimer, which, new_value, old_value); -  if (new_value) -    COMMON_INTERCEPTOR_READ_RANGE(ctx, new_value, struct_itimerval_sz); +  if (new_value) { +    // itimerval can contain padding that may be legitimately uninitialized +    const struct __sanitizer_itimerval *nv = +        (const struct __sanitizer_itimerval *)new_value; +    COMMON_INTERCEPTOR_READ_RANGE(ctx, &nv->it_interval.tv_sec, +                                  sizeof(__sanitizer_time_t)); +    COMMON_INTERCEPTOR_READ_RANGE(ctx, &nv->it_interval.tv_usec, +                                  sizeof(__sanitizer_suseconds_t)); +    COMMON_INTERCEPTOR_READ_RANGE(ctx, &nv->it_value.tv_sec, +                                  sizeof(__sanitizer_time_t)); +    COMMON_INTERCEPTOR_READ_RANGE(ctx, &nv->it_value.tv_usec, +                                  sizeof(__sanitizer_suseconds_t)); +  }    // FIXME: under ASan the call below may write to freed memory and corrupt    // its metadata. See    // https://github.com/google/sanitizers/issues/321. @@ -2765,6 +2834,30 @@ INTERCEPTOR(int, accept4, int fd, void *addr, unsigned *addrlen, int f) {  #define INIT_ACCEPT4  #endif +#if SANITIZER_INTERCEPT_PACCEPT +INTERCEPTOR(int, paccept, int fd, void *addr, unsigned *addrlen, +            __sanitizer_sigset_t *set, int f) { +  void *ctx; +  COMMON_INTERCEPTOR_ENTER(ctx, paccept, fd, addr, addrlen, set, f); +  unsigned addrlen0 = 0; +  if (addrlen) { +    COMMON_INTERCEPTOR_READ_RANGE(ctx, addrlen, sizeof(*addrlen)); +    addrlen0 = *addrlen; +  } +  if (set) COMMON_INTERCEPTOR_READ_RANGE(ctx, set, sizeof(*set)); +  int fd2 = REAL(paccept)(fd, addr, addrlen, set, f); +  if (fd2 >= 0) { +    if (fd >= 0) COMMON_INTERCEPTOR_FD_SOCKET_ACCEPT(ctx, fd, fd2); +    if (addr && addrlen) +      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, addr, Min(*addrlen, addrlen0)); +  } +  return fd2; +} +#define INIT_PACCEPT COMMON_INTERCEPT_FUNCTION(paccept); +#else +#define INIT_PACCEPT +#endif +  #if SANITIZER_INTERCEPT_MODF  INTERCEPTOR(double, modf, double x, double *iptr) {    void *ctx; @@ -2810,7 +2903,7 @@ INTERCEPTOR(long double, modfl, long double x, long double *iptr) {  #define INIT_MODF  #endif -#if SANITIZER_INTERCEPT_RECVMSG +#if SANITIZER_INTERCEPT_RECVMSG || SANITIZER_INTERCEPT_RECVMMSG  static void write_msghdr(void *ctx, struct __sanitizer_msghdr *msg,                           SSIZE_T maxlen) {    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, msg, sizeof(*msg)); @@ -2823,7 +2916,9 @@ static void write_msghdr(void *ctx, struct __sanitizer_msghdr *msg,    if (msg->msg_control && msg->msg_controllen)      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, msg->msg_control, msg->msg_controllen);  } +#endif +#if SANITIZER_INTERCEPT_RECVMSG  INTERCEPTOR(SSIZE_T, recvmsg, int fd, struct __sanitizer_msghdr *msg,              int flags) {    void *ctx; @@ -2846,7 +2941,30 @@ INTERCEPTOR(SSIZE_T, recvmsg, int fd, struct __sanitizer_msghdr *msg,  #define INIT_RECVMSG  #endif -#if SANITIZER_INTERCEPT_SENDMSG +#if SANITIZER_INTERCEPT_RECVMMSG +INTERCEPTOR(int, recvmmsg, int fd, struct __sanitizer_mmsghdr *msgvec, +            unsigned int vlen, int flags, void *timeout) { +  void *ctx; +  COMMON_INTERCEPTOR_ENTER(ctx, recvmmsg, fd, msgvec, vlen, flags, timeout); +  if (timeout) COMMON_INTERCEPTOR_READ_RANGE(ctx, timeout, struct_timespec_sz); +  int res = REAL(recvmmsg)(fd, msgvec, vlen, flags, timeout); +  if (res >= 0) { +    if (fd >= 0) COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd); +    for (int i = 0; i < res; ++i) { +      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, &msgvec[i].msg_len, +                                     sizeof(msgvec[i].msg_len)); +      write_msghdr(ctx, &msgvec[i].msg_hdr, msgvec[i].msg_len); +      COMMON_INTERCEPTOR_HANDLE_RECVMSG(ctx, &msgvec[i].msg_hdr); +    } +  } +  return res; +} +#define INIT_RECVMMSG COMMON_INTERCEPT_FUNCTION(recvmmsg); +#else +#define INIT_RECVMMSG +#endif + +#if SANITIZER_INTERCEPT_SENDMSG || SANITIZER_INTERCEPT_SENDMMSG  static void read_msghdr_control(void *ctx, void *control, uptr controllen) {    const unsigned kCmsgDataOffset =        RoundUpTo(sizeof(__sanitizer_cmsghdr), sizeof(uptr)); @@ -2896,7 +3014,9 @@ static void read_msghdr(void *ctx, struct __sanitizer_msghdr *msg,    if (msg->msg_control && msg->msg_controllen)      read_msghdr_control(ctx, msg->msg_control, msg->msg_controllen);  } +#endif +#if SANITIZER_INTERCEPT_SENDMSG  INTERCEPTOR(SSIZE_T, sendmsg, int fd, struct __sanitizer_msghdr *msg,              int flags) {    void *ctx; @@ -2915,6 +3035,30 @@ INTERCEPTOR(SSIZE_T, sendmsg, int fd, struct __sanitizer_msghdr *msg,  #define INIT_SENDMSG  #endif +#if SANITIZER_INTERCEPT_SENDMMSG +INTERCEPTOR(int, sendmmsg, int fd, struct __sanitizer_mmsghdr *msgvec, +            unsigned vlen, int flags) { +  void *ctx; +  COMMON_INTERCEPTOR_ENTER(ctx, sendmmsg, fd, msgvec, vlen, flags); +  if (fd >= 0) { +    COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd); +    COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd); +  } +  int res = REAL(sendmmsg)(fd, msgvec, vlen, flags); +  if (res >= 0 && msgvec) +    for (int i = 0; i < res; ++i) { +      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, &msgvec[i].msg_len, +                                     sizeof(msgvec[i].msg_len)); +      if (common_flags()->intercept_send) +        read_msghdr(ctx, &msgvec[i].msg_hdr, msgvec[i].msg_len); +    } +  return res; +} +#define INIT_SENDMMSG COMMON_INTERCEPT_FUNCTION(sendmmsg); +#else +#define INIT_SENDMMSG +#endif +  #if SANITIZER_INTERCEPT_GETPEERNAME  INTERCEPTOR(int, getpeername, int sockfd, void *addr, unsigned *addrlen) {    void *ctx; @@ -3096,13 +3240,25 @@ INTERCEPTOR(uptr, ptrace, int request, int pid, void *addr, void *data) {  #endif  #if SANITIZER_INTERCEPT_SETLOCALE +static void unpoison_ctype_arrays(void *ctx) { +#if SANITIZER_NETBSD +  // These arrays contain 256 regular elements in unsigned char range + 1 EOF +  COMMON_INTERCEPTOR_WRITE_RANGE(ctx, _ctype_tab_, 257 * sizeof(short)); +  COMMON_INTERCEPTOR_WRITE_RANGE(ctx, _toupper_tab_, 257 * sizeof(short)); +  COMMON_INTERCEPTOR_WRITE_RANGE(ctx, _tolower_tab_, 257 * sizeof(short)); +#endif +} +  INTERCEPTOR(char *, setlocale, int category, char *locale) {    void *ctx;    COMMON_INTERCEPTOR_ENTER(ctx, setlocale, category, locale);    if (locale)      COMMON_INTERCEPTOR_READ_RANGE(ctx, locale, REAL(strlen)(locale) + 1);    char *res = REAL(setlocale)(category, locale); -  if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1); +  if (res) { +    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1); +    unpoison_ctype_arrays(ctx); +  }    return res;  } @@ -3485,7 +3641,8 @@ INTERCEPTOR(char *, strerror, int errnum) {  //  * GNU version returns message pointer, which points to either buf or some  //    static storage.  #if ((_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && !_GNU_SOURCE) || \ -    SANITIZER_MAC || SANITIZER_ANDROID || SANITIZER_NETBSD +    SANITIZER_MAC || SANITIZER_ANDROID || SANITIZER_NETBSD ||                 \ +    SANITIZER_FREEBSD || SANITIZER_OPENBSD  // POSIX version. Spec is not clear on whether buf is NULL-terminated.  // At least on OSX, buf contents are valid even when the call fails.  INTERCEPTOR(int, strerror_r, int errnum, char *buf, SIZE_T buflen) { @@ -3908,7 +4065,7 @@ INTERCEPTOR(void, _exit, int status) {  #define INIT__EXIT  #endif -#if SANITIZER_INTERCEPT_PHTREAD_MUTEX +#if SANITIZER_INTERCEPT_PTHREAD_MUTEX  INTERCEPTOR(int, pthread_mutex_lock, void *m) {    void *ctx;    COMMON_INTERCEPTOR_ENTER(ctx, pthread_mutex_lock, m); @@ -3941,13 +4098,42 @@ INTERCEPTOR(int, pthread_mutex_unlock, void *m) {  #define INIT_PTHREAD_MUTEX_UNLOCK  #endif -#if SANITIZER_NETBSD -INTERCEPTOR(int, __libc_mutex_lock, void *m) \ -  ALIAS(WRAPPER_NAME(pthread_mutex_lock)); -INTERCEPTOR(int, __libc_mutex_unlock, void *m) \ -  ALIAS(WRAPPER_NAME(pthread_mutex_unlock)); -INTERCEPTOR(int, __libc_thr_setcancelstate, int state, int *oldstate) \ -  ALIAS(WRAPPER_NAME(pthread_setcancelstate)); +#if SANITIZER_INTERCEPT___PTHREAD_MUTEX +INTERCEPTOR(int, __pthread_mutex_lock, void *m) { +  return WRAP(pthread_mutex_lock)(m); +} + +INTERCEPTOR(int, __pthread_mutex_unlock, void *m) { +  return WRAP(pthread_mutex_unlock)(m); +} + +#define INIT___PTHREAD_MUTEX_LOCK \ +  COMMON_INTERCEPT_FUNCTION(__pthread_mutex_lock) +#define INIT___PTHREAD_MUTEX_UNLOCK \ +  COMMON_INTERCEPT_FUNCTION(__pthread_mutex_unlock) +#else +#define INIT___PTHREAD_MUTEX_LOCK +#define INIT___PTHREAD_MUTEX_UNLOCK +#endif + +#if SANITIZER_INTERCEPT___LIBC_MUTEX +INTERCEPTOR(int, __libc_mutex_lock, void *m) +ALIAS(WRAPPER_NAME(pthread_mutex_lock)); + +INTERCEPTOR(int, __libc_mutex_unlock, void *m) +ALIAS(WRAPPER_NAME(pthread_mutex_unlock)); + +INTERCEPTOR(int, __libc_thr_setcancelstate, int state, int *oldstate) +ALIAS(WRAPPER_NAME(pthread_setcancelstate)); + +#define INIT___LIBC_MUTEX_LOCK COMMON_INTERCEPT_FUNCTION(__libc_mutex_lock) +#define INIT___LIBC_MUTEX_UNLOCK COMMON_INTERCEPT_FUNCTION(__libc_mutex_unlock) +#define INIT___LIBC_THR_SETCANCELSTATE \ +  COMMON_INTERCEPT_FUNCTION(__libc_thr_setcancelstate) +#else +#define INIT___LIBC_MUTEX_LOCK +#define INIT___LIBC_MUTEX_UNLOCK +#define INIT___LIBC_THR_SETCANCELSTATE  #endif  #if SANITIZER_INTERCEPT_GETMNTENT || SANITIZER_INTERCEPT_GETMNTENT_R @@ -4302,8 +4488,6 @@ INTERCEPTOR(int, random_r, void *buf, u32 *result) {  #if SANITIZER_INTERCEPT_PTHREAD_ATTR_GET  INTERCEPTOR_PTHREAD_ATTR_GET(detachstate, sizeof(int))  INTERCEPTOR_PTHREAD_ATTR_GET(guardsize, sizeof(SIZE_T)) -INTERCEPTOR_PTHREAD_ATTR_GET(schedparam, struct_sched_param_sz) -INTERCEPTOR_PTHREAD_ATTR_GET(schedpolicy, sizeof(int))  INTERCEPTOR_PTHREAD_ATTR_GET(scope, sizeof(int))  INTERCEPTOR_PTHREAD_ATTR_GET(stacksize, sizeof(SIZE_T))  INTERCEPTOR(int, pthread_attr_getstack, void *attr, void **addr, SIZE_T *size) { @@ -4334,8 +4518,6 @@ int real_pthread_attr_getstack(void *attr, void **addr, SIZE_T *size) {  #define INIT_PTHREAD_ATTR_GET                             \    COMMON_INTERCEPT_FUNCTION(pthread_attr_getdetachstate); \    COMMON_INTERCEPT_FUNCTION(pthread_attr_getguardsize);   \ -  COMMON_INTERCEPT_FUNCTION(pthread_attr_getschedparam);  \ -  COMMON_INTERCEPT_FUNCTION(pthread_attr_getschedpolicy); \    COMMON_INTERCEPT_FUNCTION(pthread_attr_getscope);       \    COMMON_INTERCEPT_FUNCTION(pthread_attr_getstacksize);   \    COMMON_INTERCEPT_FUNCTION(pthread_attr_getstack); @@ -4343,6 +4525,17 @@ int real_pthread_attr_getstack(void *attr, void **addr, SIZE_T *size) {  #define INIT_PTHREAD_ATTR_GET  #endif +#if SANITIZER_INTERCEPT_PTHREAD_ATTR_GET_SCHED +INTERCEPTOR_PTHREAD_ATTR_GET(schedparam, struct_sched_param_sz) +INTERCEPTOR_PTHREAD_ATTR_GET(schedpolicy, sizeof(int)) + +#define INIT_PTHREAD_ATTR_GET_SCHED                      \ +  COMMON_INTERCEPT_FUNCTION(pthread_attr_getschedparam); \ +  COMMON_INTERCEPT_FUNCTION(pthread_attr_getschedpolicy); +#else +#define INIT_PTHREAD_ATTR_GET_SCHED +#endif +  #if SANITIZER_INTERCEPT_PTHREAD_ATTR_GETINHERITSCHED  INTERCEPTOR_PTHREAD_ATTR_GET(inheritsched, sizeof(int)) @@ -6189,6 +6382,22 @@ INTERCEPTOR(int, stat, const char *path, void *buf) {  #define INIT_STAT  #endif +#if SANITIZER_INTERCEPT_LSTAT +INTERCEPTOR(int, lstat, const char *path, void *buf) { +  void *ctx; +  COMMON_INTERCEPTOR_ENTER(ctx, lstat, path, buf); +  if (common_flags()->intercept_stat) +    COMMON_INTERCEPTOR_READ_STRING(ctx, path, 0); +  int res = REAL(lstat)(path, buf); +  if (!res) +    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, __sanitizer::struct_stat_sz); +  return res; +} +#define INIT_LSTAT COMMON_INTERCEPT_FUNCTION(lstat) +#else +#define INIT_LSTAT +#endif +  #if SANITIZER_INTERCEPT___XSTAT  INTERCEPTOR(int, __xstat, int version, const char *path, void *buf) {    void *ctx; @@ -6401,10 +6610,636 @@ INTERCEPTOR(wchar_t *, wcsncat, wchar_t *dst, const wchar_t *src, SIZE_T n) {  #define INIT_WCSCAT  #endif +#if SANITIZER_INTERCEPT_STRXFRM +static SIZE_T RealStrLen(const char *str) { return REAL(strlen)(str); } + +static SIZE_T RealStrLen(const wchar_t *str) { return REAL(wcslen)(str); } + +#define STRXFRM_INTERCEPTOR_IMPL(strxfrm, dest, src, len, ...)             \ +  {                                                                        \ +    void *ctx;                                                             \ +    COMMON_INTERCEPTOR_ENTER(ctx, strxfrm, dest, src, len, ##__VA_ARGS__); \ +    COMMON_INTERCEPTOR_READ_RANGE(ctx, src,                                \ +                                  sizeof(*src) * (RealStrLen(src) + 1));   \ +    SIZE_T res = REAL(strxfrm)(dest, src, len, ##__VA_ARGS__);             \ +    if (res < len)                                                         \ +      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, sizeof(*src) * (res + 1)); \ +    return res;                                                            \ +  } + +INTERCEPTOR(SIZE_T, strxfrm, char *dest, const char *src, SIZE_T len) { +  STRXFRM_INTERCEPTOR_IMPL(strxfrm, dest, src, len); +} + +INTERCEPTOR(SIZE_T, strxfrm_l, char *dest, const char *src, SIZE_T len, +            void *locale) { +  STRXFRM_INTERCEPTOR_IMPL(strxfrm_l, dest, src, len, locale); +} + +#define INIT_STRXFRM                  \ +  COMMON_INTERCEPT_FUNCTION(strxfrm); \ +  COMMON_INTERCEPT_FUNCTION(strxfrm_l); +#else +#define INIT_STRXFRM +#endif + +#if SANITIZER_INTERCEPT___STRXFRM_L +INTERCEPTOR(SIZE_T, __strxfrm_l, char *dest, const char *src, SIZE_T len, +            void *locale) { +  STRXFRM_INTERCEPTOR_IMPL(__strxfrm_l, dest, src, len, locale); +} + +#define INIT___STRXFRM_L COMMON_INTERCEPT_FUNCTION(__strxfrm_l); +#else +#define INIT___STRXFRM_L +#endif + +#if SANITIZER_INTERCEPT_WCSXFRM +INTERCEPTOR(SIZE_T, wcsxfrm, wchar_t *dest, const wchar_t *src, SIZE_T len) { +  STRXFRM_INTERCEPTOR_IMPL(wcsxfrm, dest, src, len); +} + +INTERCEPTOR(SIZE_T, wcsxfrm_l, wchar_t *dest, const wchar_t *src, SIZE_T len, +            void *locale) { +  STRXFRM_INTERCEPTOR_IMPL(wcsxfrm_l, dest, src, len, locale); +} + +#define INIT_WCSXFRM                  \ +  COMMON_INTERCEPT_FUNCTION(wcsxfrm); \ +  COMMON_INTERCEPT_FUNCTION(wcsxfrm_l); +#else +#define INIT_WCSXFRM +#endif + +#if SANITIZER_INTERCEPT___WCSXFRM_L +INTERCEPTOR(SIZE_T, __wcsxfrm_l, wchar_t *dest, const wchar_t *src, SIZE_T len, +            void *locale) { +  STRXFRM_INTERCEPTOR_IMPL(__wcsxfrm_l, dest, src, len, locale); +} + +#define INIT___WCSXFRM_L COMMON_INTERCEPT_FUNCTION(__wcsxfrm_l); +#else +#define INIT___WCSXFRM_L +#endif + +#if SANITIZER_INTERCEPT_ACCT +INTERCEPTOR(int, acct, const char *file) { +  void *ctx; +  COMMON_INTERCEPTOR_ENTER(ctx, acct, file); +  if (file) +    COMMON_INTERCEPTOR_READ_RANGE(ctx, file, REAL(strlen)(file) + 1); +  return REAL(acct)(file); +} +#define INIT_ACCT COMMON_INTERCEPT_FUNCTION(acct) +#else +#define INIT_ACCT +#endif + +#if SANITIZER_INTERCEPT_USER_FROM_UID +INTERCEPTOR(const char *, user_from_uid, u32 uid, int nouser) { +  void *ctx; +  const char *user; +  COMMON_INTERCEPTOR_ENTER(ctx, user_from_uid, uid, nouser); +  user = REAL(user_from_uid)(uid, nouser); +  if (user) +    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, user, REAL(strlen)(user) + 1); +  return user; +} +#define INIT_USER_FROM_UID COMMON_INTERCEPT_FUNCTION(user_from_uid) +#else +#define INIT_USER_FROM_UID +#endif + +#if SANITIZER_INTERCEPT_UID_FROM_USER +INTERCEPTOR(int, uid_from_user, const char *name, u32 *uid) { +  void *ctx; +  int res; +  COMMON_INTERCEPTOR_ENTER(ctx, uid_from_user, name, uid); +  if (name) +    COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1); +  res = REAL(uid_from_user)(name, uid); +  if (uid) +    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, uid, sizeof(*uid)); +  return res; +} +#define INIT_UID_FROM_USER COMMON_INTERCEPT_FUNCTION(uid_from_user) +#else +#define INIT_UID_FROM_USER +#endif + +#if SANITIZER_INTERCEPT_GROUP_FROM_GID +INTERCEPTOR(const char *, group_from_gid, u32 gid, int nogroup) { +  void *ctx; +  const char *group; +  COMMON_INTERCEPTOR_ENTER(ctx, group_from_gid, gid, nogroup); +  group = REAL(group_from_gid)(gid, nogroup); +  if (group) +    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, group, REAL(strlen)(group) + 1); +  return group; +} +#define INIT_GROUP_FROM_GID COMMON_INTERCEPT_FUNCTION(group_from_gid) +#else +#define INIT_GROUP_FROM_GID +#endif + +#if SANITIZER_INTERCEPT_GID_FROM_GROUP +INTERCEPTOR(int, gid_from_group, const char *group, u32 *gid) { +  void *ctx; +  int res; +  COMMON_INTERCEPTOR_ENTER(ctx, gid_from_group, group, gid); +  if (group) +    COMMON_INTERCEPTOR_READ_RANGE(ctx, group, REAL(strlen)(group) + 1); +  res = REAL(gid_from_group)(group, gid); +  if (gid) +    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, gid, sizeof(*gid)); +  return res; +} +#define INIT_GID_FROM_GROUP COMMON_INTERCEPT_FUNCTION(gid_from_group) +#else +#define INIT_GID_FROM_GROUP +#endif + +#if SANITIZER_INTERCEPT_ACCESS +INTERCEPTOR(int, access, const char *path, int mode) { +  void *ctx; +  COMMON_INTERCEPTOR_ENTER(ctx, access, path, mode); +  if (path) +    COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1); +  return REAL(access)(path, mode); +} +#define INIT_ACCESS COMMON_INTERCEPT_FUNCTION(access) +#else +#define INIT_ACCESS +#endif + +#if SANITIZER_INTERCEPT_FACCESSAT +INTERCEPTOR(int, faccessat, int fd, const char *path, int mode, int flags) { +  void *ctx; +  COMMON_INTERCEPTOR_ENTER(ctx, faccessat, fd, path, mode, flags); +  if (path) +    COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1); +  return REAL(faccessat)(fd, path, mode, flags); +} +#define INIT_FACCESSAT COMMON_INTERCEPT_FUNCTION(faccessat) +#else +#define INIT_FACCESSAT +#endif + +#if SANITIZER_INTERCEPT_GETGROUPLIST +INTERCEPTOR(int, getgrouplist, const char *name, u32 basegid, u32 *groups, +            int *ngroups) { +  void *ctx; +  int res; +  COMMON_INTERCEPTOR_ENTER(ctx, getgrouplist, name, basegid, groups, ngroups); +  if (name) +    COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1); +  if (ngroups) +    COMMON_INTERCEPTOR_READ_RANGE(ctx, ngroups, sizeof(*ngroups)); +  res = REAL(getgrouplist)(name, basegid, groups, ngroups); +  if (!res && groups && ngroups) { +    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, groups, sizeof(*groups) * (*ngroups)); +    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ngroups, sizeof(*ngroups)); +  } +  return res; +} + +#define INIT_GETGROUPLIST COMMON_INTERCEPT_FUNCTION(getgrouplist); +#else +#define INIT_GETGROUPLIST +#endif + +#if SANITIZER_INTERCEPT_GETGROUPMEMBERSHIP +INTERCEPTOR(int, getgroupmembership, const char *name, u32 basegid, u32 *groups, +            int maxgrp, int *ngroups) { +  void *ctx; +  int res; +  COMMON_INTERCEPTOR_ENTER(ctx, getgroupmembership, name, basegid, groups, +                           maxgrp, ngroups); +  if (name) +    COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1); +  res = REAL(getgroupmembership)(name, basegid, groups, maxgrp, ngroups); +  if (!res && groups && ngroups) { +    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, groups, sizeof(*groups) * (*ngroups)); +    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ngroups, sizeof(*ngroups)); +  } +  return res; +} + +#define INIT_GETGROUPMEMBERSHIP COMMON_INTERCEPT_FUNCTION(getgroupmembership); +#else +#define INIT_GETGROUPMEMBERSHIP +#endif + +#if SANITIZER_INTERCEPT_READLINK +INTERCEPTOR(SSIZE_T, readlink, const char *path, char *buf, SIZE_T bufsiz) { +  void* ctx; +  COMMON_INTERCEPTOR_ENTER(ctx, readlink, path, buf, bufsiz); +  COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1); +  SSIZE_T res = REAL(readlink)(path, buf, bufsiz); +  if (res > 0) +    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, res); +  return res; +} + +#define INIT_READLINK COMMON_INTERCEPT_FUNCTION(readlink) +#else +#define INIT_READLINK +#endif + +#if SANITIZER_INTERCEPT_READLINKAT +INTERCEPTOR(SSIZE_T, readlinkat, int dirfd, const char *path, char *buf, +            SIZE_T bufsiz) { +  void* ctx; +  COMMON_INTERCEPTOR_ENTER(ctx, readlinkat, dirfd, path, buf, bufsiz); +  COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1); +  SSIZE_T res = REAL(readlinkat)(dirfd, path, buf, bufsiz); +  if (res > 0) +    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, res); +  return res; +} + +#define INIT_READLINKAT COMMON_INTERCEPT_FUNCTION(readlinkat) +#else +#define INIT_READLINKAT +#endif + +#if SANITIZER_INTERCEPT_NAME_TO_HANDLE_AT +INTERCEPTOR(int, name_to_handle_at, int dirfd, const char *pathname, +            struct file_handle *handle, int *mount_id, int flags) { +  void* ctx; +  COMMON_INTERCEPTOR_ENTER(ctx, name_to_handle_at, dirfd, pathname, handle, +                           mount_id, flags); +  COMMON_INTERCEPTOR_READ_RANGE(ctx, pathname, REAL(strlen)(pathname) + 1); + +  __sanitizer_file_handle *sanitizer_handle = +      reinterpret_cast<__sanitizer_file_handle*>(handle); +  COMMON_INTERCEPTOR_READ_RANGE( +      ctx, &sanitizer_handle->handle_bytes, +      sizeof(sanitizer_handle->handle_bytes)); + +  int res = REAL(name_to_handle_at)(dirfd, pathname, handle, mount_id, flags); +  if (!res) { +    COMMON_INTERCEPTOR_WRITE_RANGE( +        ctx, &sanitizer_handle->handle_bytes, +        sizeof(sanitizer_handle->handle_bytes)); +    COMMON_INTERCEPTOR_WRITE_RANGE( +        ctx, &sanitizer_handle->handle_type, +        sizeof(sanitizer_handle->handle_type)); +    COMMON_INTERCEPTOR_WRITE_RANGE( +        ctx, &sanitizer_handle->f_handle, sanitizer_handle->handle_bytes); +    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, mount_id, sizeof(*mount_id)); +  } +  return res; +} + +#define INIT_NAME_TO_HANDLE_AT COMMON_INTERCEPT_FUNCTION(name_to_handle_at) +#else +#define INIT_NAME_TO_HANDLE_AT +#endif + +#if SANITIZER_INTERCEPT_OPEN_BY_HANDLE_AT +INTERCEPTOR(int, open_by_handle_at, int mount_fd, struct file_handle* handle, +            int flags) { +  void* ctx; +  COMMON_INTERCEPTOR_ENTER(ctx, open_by_handle_at, mount_fd, handle, flags); + +  __sanitizer_file_handle *sanitizer_handle = +      reinterpret_cast<__sanitizer_file_handle*>(handle); +  COMMON_INTERCEPTOR_READ_RANGE( +      ctx, &sanitizer_handle->handle_bytes, +      sizeof(sanitizer_handle->handle_bytes)); +  COMMON_INTERCEPTOR_READ_RANGE( +      ctx, &sanitizer_handle->handle_type, +      sizeof(sanitizer_handle->handle_type)); +  COMMON_INTERCEPTOR_READ_RANGE( +      ctx, &sanitizer_handle->f_handle, sanitizer_handle->handle_bytes); + +  return REAL(open_by_handle_at)(mount_fd, handle, flags); +} + +#define INIT_OPEN_BY_HANDLE_AT COMMON_INTERCEPT_FUNCTION(open_by_handle_at) +#else +#define INIT_OPEN_BY_HANDLE_AT +#endif + +#if SANITIZER_INTERCEPT_STRLCPY +INTERCEPTOR(SIZE_T, strlcpy, char *dst, char *src, SIZE_T size) { +  void *ctx; +  SIZE_T res; +  COMMON_INTERCEPTOR_ENTER(ctx, strlcpy, dst, src, size); +  if (src) { +    // Keep strnlen as macro argument, as macro may ignore it. +    COMMON_INTERCEPTOR_READ_STRING( +        ctx, src, Min(internal_strnlen(src, size), size - 1) + 1); +  } +  res = REAL(strlcpy)(dst, src, size); +  COMMON_INTERCEPTOR_COPY_STRING(ctx, dst, src, REAL(strlen)(dst) + 1); +  return res; +} + +INTERCEPTOR(SIZE_T, strlcat, char *dst, char *src, SIZE_T size) { +  void *ctx; +  SIZE_T len = 0; +  COMMON_INTERCEPTOR_ENTER(ctx, strlcat, dst, src, size); +  // src is checked in the strlcpy() interceptor +  if (dst) { +    len = internal_strnlen(dst, size); +    COMMON_INTERCEPTOR_READ_STRING(ctx, dst, Min(len, size - 1) + 1); +  } +  // Reuse the rest of the code in the strlcpy() interceptor +  return WRAP(strlcpy)(dst + len, src, size - len) + len; +} +#define INIT_STRLCPY \ +  COMMON_INTERCEPT_FUNCTION(strlcpy); \ +  COMMON_INTERCEPT_FUNCTION(strlcat); +#else +#define INIT_STRLCPY +#endif + +#if SANITIZER_INTERCEPT_MMAP +INTERCEPTOR(void *, mmap, void *addr, SIZE_T sz, int prot, int flags, int fd, +            OFF_T off) { +  void *ctx; +  if (common_flags()->detect_write_exec) +    ReportMmapWriteExec(prot); +  if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED) +    return (void *)internal_mmap(addr, sz, prot, flags, fd, off); +  COMMON_INTERCEPTOR_ENTER(ctx, mmap, addr, sz, prot, flags, fd, off); +  COMMON_INTERCEPTOR_MMAP_IMPL(ctx, mmap, addr, sz, prot, flags, fd, off); +} + +INTERCEPTOR(int, mprotect, void *addr, SIZE_T sz, int prot) { +  void *ctx; +  if (common_flags()->detect_write_exec) +    ReportMmapWriteExec(prot); +  if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED) +    return (int)internal_mprotect(addr, sz, prot); +  COMMON_INTERCEPTOR_ENTER(ctx, mprotect, addr, sz, prot); +  MprotectMallocZones(addr, prot); +  return REAL(mprotect)(addr, sz, prot); +} +#define INIT_MMAP                                                              \ +  COMMON_INTERCEPT_FUNCTION(mmap);                                             \ +  COMMON_INTERCEPT_FUNCTION(mprotect); +#else +#define INIT_MMAP +#endif + +#if SANITIZER_INTERCEPT_MMAP64 +INTERCEPTOR(void *, mmap64, void *addr, SIZE_T sz, int prot, int flags, int fd, +            OFF64_T off) { +  void *ctx; +  if (common_flags()->detect_write_exec) +    ReportMmapWriteExec(prot); +  if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED) +    return (void *)internal_mmap(addr, sz, prot, flags, fd, off); +  COMMON_INTERCEPTOR_ENTER(ctx, mmap64, addr, sz, prot, flags, fd, off); +  COMMON_INTERCEPTOR_MMAP_IMPL(ctx, mmap64, addr, sz, prot, flags, fd, off); +} +#define INIT_MMAP64 COMMON_INTERCEPT_FUNCTION(mmap64); +#else +#define INIT_MMAP64 +#endif + +#if SANITIZER_INTERCEPT_DEVNAME +INTERCEPTOR(char *, devname, u64 dev, u32 type) { +  void *ctx; +  char *name; +  COMMON_INTERCEPTOR_ENTER(ctx, devname, dev, type); +  name = REAL(devname)(dev, type); +  if (name) +    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, name, REAL(strlen)(name) + 1); +  return name; +} +#define INIT_DEVNAME COMMON_INTERCEPT_FUNCTION(devname); +#else +#define INIT_DEVNAME +#endif + +#if SANITIZER_INTERCEPT_DEVNAME_R +INTERCEPTOR(int, devname_r, u64 dev, u32 type, char *path, uptr len) { +  void *ctx; +  int res; +  COMMON_INTERCEPTOR_ENTER(ctx, devname_r, dev, type, path, len); +  res = REAL(devname_r)(dev, type, path, len); +  if (!res) +    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, path, REAL(strlen)(path) + 1); +  return res; +} +#define INIT_DEVNAME_R COMMON_INTERCEPT_FUNCTION(devname_r); +#else +#define INIT_DEVNAME_R +#endif + +#if SANITIZER_INTERCEPT_FGETLN +INTERCEPTOR(char *, fgetln, __sanitizer_FILE *stream, SIZE_T *len) { +  void *ctx; +  COMMON_INTERCEPTOR_ENTER(ctx, fgetln, stream, len); +  char *str = REAL(fgetln)(stream, len); +  if (str && len) { +    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, len, sizeof(*len)); +    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, str, *len); +  } +  return str; +} +#define INIT_FGETLN COMMON_INTERCEPT_FUNCTION(fgetln) +#else +#define INIT_FGETLN +#endif + +#if SANITIZER_INTERCEPT_STRMODE +INTERCEPTOR(void, strmode, u32 mode, char *bp) { +  void *ctx; +  COMMON_INTERCEPTOR_ENTER(ctx, strmode, mode, bp); +  REAL(strmode)(mode, bp); +  if (bp) +    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, bp, REAL(strlen)(bp) + 1); +} +#define INIT_STRMODE COMMON_INTERCEPT_FUNCTION(strmode) +#else +#define INIT_STRMODE +#endif + +#if SANITIZER_INTERCEPT_TTYENT +INTERCEPTOR(struct __sanitizer_ttyent *, getttyent, void) { +  void *ctx; +  COMMON_INTERCEPTOR_ENTER(ctx, getttyent); +  struct __sanitizer_ttyent *ttyent = REAL(getttyent)(); +  if (ttyent) +    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ttyent, struct_ttyent_sz); +  return ttyent; +} +INTERCEPTOR(struct __sanitizer_ttyent *, getttynam, char *name) { +  void *ctx; +  COMMON_INTERCEPTOR_ENTER(ctx, getttynam, name); +  if (name) +    COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1); +  struct __sanitizer_ttyent *ttyent = REAL(getttynam)(name); +  if (ttyent) +    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ttyent, struct_ttyent_sz); +  return ttyent; +} +INTERCEPTOR(int, setttyentpath, char *path) { +  void *ctx; +  COMMON_INTERCEPTOR_ENTER(ctx, setttyentpath, path); +  if (path) +    COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1); +  return REAL(setttyentpath)(path); +} +#define INIT_TTYENT \ +  COMMON_INTERCEPT_FUNCTION(getttyent); \ +  COMMON_INTERCEPT_FUNCTION(getttynam); \ +  COMMON_INTERCEPT_FUNCTION(setttyentpath) +#else +#define INIT_TTYENT +#endif + +#if SANITIZER_INTERCEPT_PROTOENT +INTERCEPTOR(struct __sanitizer_protoent *, getprotoent) { +  void *ctx; +  COMMON_INTERCEPTOR_ENTER(ctx, getprotoent); +  struct __sanitizer_protoent *p = REAL(getprotoent)(); +  if (p) { +    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p, sizeof(*p)); + +    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p->p_name, REAL(strlen)(p->p_name) + 1); + +    SIZE_T pp_size = 1; // One handles the trailing \0 + +    for (char **pp = p->p_aliases; *pp; ++pp, ++pp_size) +       COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *pp, REAL(strlen)(*pp) + 1); + +    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p->p_aliases, +                                   pp_size * sizeof(char **)); +  } +  return p; +} + +INTERCEPTOR(struct __sanitizer_protoent *, getprotobyname, const char *name) { +  void *ctx; +  COMMON_INTERCEPTOR_ENTER(ctx, getprotobyname, name); +  if (name) +    COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1); +  struct __sanitizer_protoent *p = REAL(getprotobyname)(name); +  if (p) { +    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p, sizeof(*p)); + +    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p->p_name, REAL(strlen)(p->p_name) + 1); + +    SIZE_T pp_size = 1; // One handles the trailing \0 + +    for (char **pp = p->p_aliases; *pp; ++pp, ++pp_size) +       COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *pp, REAL(strlen)(*pp) + 1); + +    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p->p_aliases, +                                   pp_size * sizeof(char **)); +  } +  return p; +} + +INTERCEPTOR(struct __sanitizer_protoent *, getprotobynumber, int proto) { +  void *ctx; +  COMMON_INTERCEPTOR_ENTER(ctx, getprotobynumber, proto); +  struct __sanitizer_protoent *p = REAL(getprotobynumber)(proto); +  if (p) { +    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p, sizeof(*p)); + +    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p->p_name, REAL(strlen)(p->p_name) + 1); + +    SIZE_T pp_size = 1; // One handles the trailing \0 + +    for (char **pp = p->p_aliases; *pp; ++pp, ++pp_size) +       COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *pp, REAL(strlen)(*pp) + 1); + +    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p->p_aliases, +                                   pp_size * sizeof(char **)); +  } +  return p; +} +#define INIT_PROTOENT \ +  COMMON_INTERCEPT_FUNCTION(getprotoent); \ +  COMMON_INTERCEPT_FUNCTION(getprotobyname); \ +  COMMON_INTERCEPT_FUNCTION(getprotobynumber) +#else +#define INIT_PROTOENT +#endif + +#if SANITIZER_INTERCEPT_NETENT +INTERCEPTOR(struct __sanitizer_netent *, getnetent) { +  void *ctx; +  COMMON_INTERCEPTOR_ENTER(ctx, getnetent); +  struct __sanitizer_netent *n = REAL(getnetent)(); +  if (n) { +    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, n, sizeof(*n)); + +    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, n->n_name, REAL(strlen)(n->n_name) + 1); + +    SIZE_T nn_size = 1; // One handles the trailing \0 + +    for (char **nn = n->n_aliases; *nn; ++nn, ++nn_size) +      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *nn, REAL(strlen)(*nn) + 1); + +    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, n->n_aliases, +                                   nn_size * sizeof(char **)); +  } +  return n; +} + +INTERCEPTOR(struct __sanitizer_netent *, getnetbyname, const char *name) { +  void *ctx; +  COMMON_INTERCEPTOR_ENTER(ctx, getnetbyname, name); +  if (name) +    COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1); +  struct __sanitizer_netent *n = REAL(getnetbyname)(name); +  if (n) { +    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, n, sizeof(*n)); + +    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, n->n_name, REAL(strlen)(n->n_name) + 1); + +    SIZE_T nn_size = 1; // One handles the trailing \0 + +    for (char **nn = n->n_aliases; *nn; ++nn, ++nn_size) +      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *nn, REAL(strlen)(*nn) + 1); + +    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, n->n_aliases, +                                   nn_size * sizeof(char **)); +  } +  return n; +} + +INTERCEPTOR(struct __sanitizer_netent *, getnetbyaddr, u32 net, int type) { +  void *ctx; +  COMMON_INTERCEPTOR_ENTER(ctx, getnetbyaddr, net, type); +  struct __sanitizer_netent *n = REAL(getnetbyaddr)(net, type); +  if (n) { +    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, n, sizeof(*n)); + +    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, n->n_name, REAL(strlen)(n->n_name) + 1); + +    SIZE_T nn_size = 1; // One handles the trailing \0 + +    for (char **nn = n->n_aliases; *nn; ++nn, ++nn_size) +      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *nn, REAL(strlen)(*nn) + 1); + +    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, n->n_aliases, +                                   nn_size * sizeof(char **)); +  } +  return n; +} +#define INIT_NETENT \ +  COMMON_INTERCEPT_FUNCTION(getnetent); \ +  COMMON_INTERCEPT_FUNCTION(getnetbyname); \ +  COMMON_INTERCEPT_FUNCTION(getnetbyaddr) +#else +#define INIT_NETENT +#endif +  static void InitializeCommonInterceptors() {    static u64 metadata_mem[sizeof(MetadataHashMap) / sizeof(u64) + 1];    interceptor_metadata_map = new((void *)&metadata_mem) MetadataHashMap(); +  INIT_MMAP; +  INIT_MMAP64;    INIT_TEXTDOMAIN;    INIT_STRLEN;    INIT_STRNLEN; @@ -6422,6 +7257,8 @@ static void InitializeCommonInterceptors() {    INIT_STRSPN;    INIT_STRTOK;    INIT_STRPBRK; +  INIT_STRXFRM; +  INIT___STRXFRM_L;    INIT_MEMSET;    INIT_MEMMOVE;    INIT_MEMCPY; @@ -6443,6 +7280,9 @@ static void InitializeCommonInterceptors() {    INIT_WRITEV;    INIT_PWRITEV;    INIT_PWRITEV64; +  INIT_FGETS; +  INIT_FPUTS; +  INIT_PUTS;    INIT_PRCTL;    INIT_LOCALTIME_AND_FRIENDS;    INIT_STRPTIME; @@ -6480,9 +7320,12 @@ static void InitializeCommonInterceptors() {    INIT_GETSOCKOPT;    INIT_ACCEPT;    INIT_ACCEPT4; +  INIT_PACCEPT;    INIT_MODF;    INIT_RECVMSG;    INIT_SENDMSG; +  INIT_RECVMMSG; +  INIT_SENDMMSG;    INIT_GETPEERNAME;    INIT_IOCTL;    INIT_INET_ATON; @@ -6524,6 +7367,11 @@ static void InitializeCommonInterceptors() {    INIT__EXIT;    INIT_PTHREAD_MUTEX_LOCK;    INIT_PTHREAD_MUTEX_UNLOCK; +  INIT___PTHREAD_MUTEX_LOCK; +  INIT___PTHREAD_MUTEX_UNLOCK; +  INIT___LIBC_MUTEX_LOCK; +  INIT___LIBC_MUTEX_UNLOCK; +  INIT___LIBC_THR_SETCANCELSTATE;    INIT_GETMNTENT;    INIT_GETMNTENT_R;    INIT_STATFS; @@ -6537,6 +7385,7 @@ static void InitializeCommonInterceptors() {    INIT_SHMCTL;    INIT_RANDOM_R;    INIT_PTHREAD_ATTR_GET; +  INIT_PTHREAD_ATTR_GET_SCHED;    INIT_PTHREAD_ATTR_GETINHERITSCHED;    INIT_PTHREAD_ATTR_GETAFFINITY_NP;    INIT_PTHREAD_MUTEXATTR_GETPSHARED; @@ -6600,6 +7449,7 @@ static void InitializeCommonInterceptors() {    INIT_SEND_SENDTO;    INIT_STAT;    INIT_EVENTFD_READ_WRITE; +  INIT_LSTAT;    INIT___XSTAT;    INIT___XSTAT64;    INIT___LXSTAT; @@ -6610,12 +7460,29 @@ static void InitializeCommonInterceptors() {    INIT_GETLOADAVG;    INIT_WCSLEN;    INIT_WCSCAT; - -#if SANITIZER_NETBSD -  COMMON_INTERCEPT_FUNCTION(__libc_mutex_lock); -  COMMON_INTERCEPT_FUNCTION(__libc_mutex_unlock); -  COMMON_INTERCEPT_FUNCTION(__libc_thr_setcancelstate); -#endif +  INIT_WCSXFRM; +  INIT___WCSXFRM_L; +  INIT_ACCT; +  INIT_USER_FROM_UID; +  INIT_UID_FROM_USER; +  INIT_GROUP_FROM_GID; +  INIT_GID_FROM_GROUP; +  INIT_ACCESS; +  INIT_FACCESSAT; +  INIT_GETGROUPLIST; +  INIT_GETGROUPMEMBERSHIP; +  INIT_READLINK; +  INIT_READLINKAT; +  INIT_NAME_TO_HANDLE_AT; +  INIT_OPEN_BY_HANDLE_AT; +  INIT_STRLCPY; +  INIT_DEVNAME; +  INIT_DEVNAME_R; +  INIT_FGETLN; +  INIT_STRMODE; +  INIT_TTYENT; +  INIT_PROTOENT; +  INIT_NETENT;    INIT___PRINTF_CHK;  } diff --git a/lib/sanitizer_common/sanitizer_common_interceptors_ioctl.inc b/lib/sanitizer_common/sanitizer_common_interceptors_ioctl.inc index 24e7548a597e2..2d633c1738949 100755 --- a/lib/sanitizer_common/sanitizer_common_interceptors_ioctl.inc +++ b/lib/sanitizer_common/sanitizer_common_interceptors_ioctl.inc @@ -10,6 +10,8 @@  // Ioctl handling in common sanitizer interceptors.  //===----------------------------------------------------------------------===// +#if !SANITIZER_NETBSD +  #include "sanitizer_flags.h"  struct ioctl_desc { @@ -478,7 +480,7 @@ struct ioctl_desc_compare {  static void ioctl_init() {    ioctl_table_fill(); -  InternalSort(&ioctl_table, ioctl_table_size, ioctl_desc_compare()); +  Sort(ioctl_table, ioctl_table_size, ioctl_desc_compare());    bool bad = false;    for (unsigned i = 0; i < ioctl_table_size - 1; ++i) { @@ -604,3 +606,5 @@ static void ioctl_common_post(void *ctx, const ioctl_desc *desc, int res, int d,      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ifc->ifc_ifcu.ifcu_req, ifc->ifc_len);    }  } + +#endif diff --git a/lib/sanitizer_common/sanitizer_common_interface.inc b/lib/sanitizer_common/sanitizer_common_interface.inc index 2568df3a5bff3..377580cb0b4ef 100644 --- a/lib/sanitizer_common/sanitizer_common_interface.inc +++ b/lib/sanitizer_common/sanitizer_common_interface.inc @@ -8,6 +8,7 @@  //===----------------------------------------------------------------------===//  // Sanitizer Common interface list.  //===----------------------------------------------------------------------===// +INTERFACE_FUNCTION(__sanitizer_acquire_crash_state)  INTERFACE_FUNCTION(__sanitizer_annotate_contiguous_container)  INTERFACE_FUNCTION(__sanitizer_contiguous_container_find_bad_address)  INTERFACE_FUNCTION(__sanitizer_set_death_callback) diff --git a/lib/sanitizer_common/sanitizer_common_libcdep.cc b/lib/sanitizer_common/sanitizer_common_libcdep.cc index 5cdfbbb275f7f..796a054858bca 100644 --- a/lib/sanitizer_common/sanitizer_common_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_common_libcdep.cc @@ -11,76 +11,14 @@  // run-time libraries.  //===----------------------------------------------------------------------===// -#include "sanitizer_common.h" -  #include "sanitizer_allocator_interface.h" -#include "sanitizer_file.h" +#include "sanitizer_common.h"  #include "sanitizer_flags.h"  #include "sanitizer_procmaps.h" -#include "sanitizer_report_decorator.h" -#include "sanitizer_stackdepot.h" -#include "sanitizer_stacktrace.h" -#include "sanitizer_symbolizer.h" -#if SANITIZER_POSIX -#include "sanitizer_posix.h" -#endif  namespace __sanitizer { -#if !SANITIZER_FUCHSIA - -bool ReportFile::SupportsColors() { -  SpinMutexLock l(mu); -  ReopenIfNecessary(); -  return SupportsColoredOutput(fd); -} - -static INLINE bool ReportSupportsColors() { -  return report_file.SupportsColors(); -} - -#else  // SANITIZER_FUCHSIA - -// Fuchsia's logs always go through post-processing that handles colorization. -static INLINE bool ReportSupportsColors() { return true; } - -#endif  // !SANITIZER_FUCHSIA - -bool ColorizeReports() { -  // FIXME: Add proper Windows support to AnsiColorDecorator and re-enable color -  // printing on Windows. -  if (SANITIZER_WINDOWS) -    return false; - -  const char *flag = common_flags()->color; -  return internal_strcmp(flag, "always") == 0 || -         (internal_strcmp(flag, "auto") == 0 && ReportSupportsColors()); -} - -static void (*sandboxing_callback)(); -void SetSandboxingCallback(void (*f)()) { -  sandboxing_callback = f; -} - -void ReportErrorSummary(const char *error_type, const StackTrace *stack, -                        const char *alt_tool_name) { -#if !SANITIZER_GO -  if (!common_flags()->print_summary) -    return; -  if (stack->size == 0) { -    ReportErrorSummary(error_type); -    return; -  } -  // Currently, we include the first stack frame into the report summary. -  // Maybe sometimes we need to choose another frame (e.g. skip memcpy/etc). -  uptr pc = StackTrace::GetPreviousInstructionPc(stack->trace[0]); -  SymbolizedStack *frame = Symbolizer::GetOrInit()->SymbolizePC(pc); -  ReportErrorSummary(error_type, frame->info, alt_tool_name); -  frame->ClearAll(); -#endif -} -  static void (*SoftRssLimitExceededCallback)(bool exceeded);  void SetSoftRssLimitExceededCallback(void (*Callback)(bool exceeded)) {    CHECK_EQ(SoftRssLimitExceededCallback, nullptr); @@ -88,17 +26,22 @@ void SetSoftRssLimitExceededCallback(void (*Callback)(bool exceeded)) {  }  #if SANITIZER_LINUX && !SANITIZER_GO +// Weak default implementation for when sanitizer_stackdepot is not linked in. +SANITIZER_WEAK_ATTRIBUTE StackDepotStats *StackDepotGetStats() { +  return nullptr; +} +  void BackgroundThread(void *arg) { -  uptr hard_rss_limit_mb = common_flags()->hard_rss_limit_mb; -  uptr soft_rss_limit_mb = common_flags()->soft_rss_limit_mb; -  bool heap_profile = common_flags()->heap_profile; +  const uptr hard_rss_limit_mb = common_flags()->hard_rss_limit_mb; +  const uptr soft_rss_limit_mb = common_flags()->soft_rss_limit_mb; +  const bool heap_profile = common_flags()->heap_profile;    uptr prev_reported_rss = 0;    uptr prev_reported_stack_depot_size = 0;    bool reached_soft_rss_limit = false;    uptr rss_during_last_reported_profile = 0;    while (true) {      SleepForMillis(100); -    uptr current_rss_mb = GetRSS() >> 20; +    const uptr current_rss_mb = GetRSS() >> 20;      if (Verbosity()) {        // If RSS has grown 10% since last time, print some information.        if (prev_reported_rss * 11 / 10 < current_rss_mb) { @@ -107,13 +50,15 @@ void BackgroundThread(void *arg) {        }        // If stack depot has grown 10% since last time, print it too.        StackDepotStats *stack_depot_stats = StackDepotGetStats(); -      if (prev_reported_stack_depot_size * 11 / 10 < -          stack_depot_stats->allocated) { -        Printf("%s: StackDepot: %zd ids; %zdM allocated\n", -               SanitizerToolName, -               stack_depot_stats->n_uniq_ids, -               stack_depot_stats->allocated >> 20); -        prev_reported_stack_depot_size = stack_depot_stats->allocated; +      if (stack_depot_stats) { +        if (prev_reported_stack_depot_size * 11 / 10 < +            stack_depot_stats->allocated) { +          Printf("%s: StackDepot: %zd ids; %zdM allocated\n", +                 SanitizerToolName, +                 stack_depot_stats->n_uniq_ids, +                 stack_depot_stats->allocated >> 20); +          prev_reported_stack_depot_size = stack_depot_stats->allocated; +        }        }      }      // Check RSS against the limit. @@ -147,127 +92,6 @@ void BackgroundThread(void *arg) {  }  #endif -#if !SANITIZER_FUCHSIA && !SANITIZER_GO -void StartReportDeadlySignal() { -  // Write the first message using fd=2, just in case. -  // It may actually fail to write in case stderr is closed. -  CatastrophicErrorWrite(SanitizerToolName, internal_strlen(SanitizerToolName)); -  static const char kDeadlySignal[] = ":DEADLYSIGNAL\n"; -  CatastrophicErrorWrite(kDeadlySignal, sizeof(kDeadlySignal) - 1); -} - -static void MaybeReportNonExecRegion(uptr pc) { -#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD -  MemoryMappingLayout proc_maps(/*cache_enabled*/ true); -  MemoryMappedSegment segment; -  while (proc_maps.Next(&segment)) { -    if (pc >= segment.start && pc < segment.end && !segment.IsExecutable()) -      Report("Hint: PC is at a non-executable region. Maybe a wild jump?\n"); -  } -#endif -} - -static void PrintMemoryByte(InternalScopedString *str, const char *before, -                            u8 byte) { -  SanitizerCommonDecorator d; -  str->append("%s%s%x%x%s ", before, d.MemoryByte(), byte >> 4, byte & 15, -              d.Default()); -} - -static void MaybeDumpInstructionBytes(uptr pc) { -  if (!common_flags()->dump_instruction_bytes || (pc < GetPageSizeCached())) -    return; -  InternalScopedString str(1024); -  str.append("First 16 instruction bytes at pc: "); -  if (IsAccessibleMemoryRange(pc, 16)) { -    for (int i = 0; i < 16; ++i) { -      PrintMemoryByte(&str, "", ((u8 *)pc)[i]); -    } -    str.append("\n"); -  } else { -    str.append("unaccessible\n"); -  } -  Report("%s", str.data()); -} - -static void MaybeDumpRegisters(void *context) { -  if (!common_flags()->dump_registers) return; -  SignalContext::DumpAllRegisters(context); -} - -static void ReportStackOverflowImpl(const SignalContext &sig, u32 tid, -                                    UnwindSignalStackCallbackType unwind, -                                    const void *unwind_context) { -  SanitizerCommonDecorator d; -  Printf("%s", d.Warning()); -  static const char kDescription[] = "stack-overflow"; -  Report("ERROR: %s: %s on address %p (pc %p bp %p sp %p T%d)\n", -         SanitizerToolName, kDescription, (void *)sig.addr, (void *)sig.pc, -         (void *)sig.bp, (void *)sig.sp, tid); -  Printf("%s", d.Default()); -  InternalScopedBuffer<BufferedStackTrace> stack_buffer(1); -  BufferedStackTrace *stack = stack_buffer.data(); -  stack->Reset(); -  unwind(sig, unwind_context, stack); -  stack->Print(); -  ReportErrorSummary(kDescription, stack); -} - -static void ReportDeadlySignalImpl(const SignalContext &sig, u32 tid, -                                   UnwindSignalStackCallbackType unwind, -                                   const void *unwind_context) { -  SanitizerCommonDecorator d; -  Printf("%s", d.Warning()); -  const char *description = sig.Describe(); -  Report("ERROR: %s: %s on unknown address %p (pc %p bp %p sp %p T%d)\n", -         SanitizerToolName, description, (void *)sig.addr, (void *)sig.pc, -         (void *)sig.bp, (void *)sig.sp, tid); -  Printf("%s", d.Default()); -  if (sig.pc < GetPageSizeCached()) -    Report("Hint: pc points to the zero page.\n"); -  if (sig.is_memory_access) { -    const char *access_type = -        sig.write_flag == SignalContext::WRITE -            ? "WRITE" -            : (sig.write_flag == SignalContext::READ ? "READ" : "UNKNOWN"); -    Report("The signal is caused by a %s memory access.\n", access_type); -    if (sig.addr < GetPageSizeCached()) -      Report("Hint: address points to the zero page.\n"); -  } -  MaybeReportNonExecRegion(sig.pc); -  InternalScopedBuffer<BufferedStackTrace> stack_buffer(1); -  BufferedStackTrace *stack = stack_buffer.data(); -  stack->Reset(); -  unwind(sig, unwind_context, stack); -  stack->Print(); -  MaybeDumpInstructionBytes(sig.pc); -  MaybeDumpRegisters(sig.context); -  Printf("%s can not provide additional info.\n", SanitizerToolName); -  ReportErrorSummary(description, stack); -} - -void ReportDeadlySignal(const SignalContext &sig, u32 tid, -                        UnwindSignalStackCallbackType unwind, -                        const void *unwind_context) { -  if (sig.IsStackOverflow()) -    ReportStackOverflowImpl(sig, tid, unwind, unwind_context); -  else -    ReportDeadlySignalImpl(sig, tid, unwind, unwind_context); -} - -void HandleDeadlySignal(void *siginfo, void *context, u32 tid, -                        UnwindSignalStackCallbackType unwind, -                        const void *unwind_context) { -  StartReportDeadlySignal(); -  ScopedErrorReportLock rl; -  SignalContext sig(siginfo, context); -  ReportDeadlySignal(sig, tid, unwind, unwind_context); -  Report("ABORTING\n"); -  Die(); -} - -#endif  // !SANITIZER_FUCHSIA && !SANITIZER_GO -  void WriteToSyslog(const char *msg) {    InternalScopedString msg_copy(kErrorMessageBufferSize);    msg_copy.append("%s", msg); @@ -298,52 +122,16 @@ void MaybeStartBackgroudThread() {  #endif  } -static atomic_uintptr_t reporting_thread = {0}; -static StaticSpinMutex CommonSanitizerReportMutex; - -ScopedErrorReportLock::ScopedErrorReportLock() { -  uptr current = GetThreadSelf(); -  for (;;) { -    uptr expected = 0; -    if (atomic_compare_exchange_strong(&reporting_thread, &expected, current, -                                       memory_order_relaxed)) { -      // We've claimed reporting_thread so proceed. -      CommonSanitizerReportMutex.Lock(); -      return; -    } - -    if (expected == current) { -      // This is either asynch signal or nested error during error reporting. -      // Fail simple to avoid deadlocks in Report(). - -      // Can't use Report() here because of potential deadlocks in nested -      // signal handlers. -      CatastrophicErrorWrite(SanitizerToolName, -                             internal_strlen(SanitizerToolName)); -      static const char msg[] = ": nested bug in the same thread, aborting.\n"; -      CatastrophicErrorWrite(msg, sizeof(msg) - 1); - -      internal__exit(common_flags()->exitcode); -    } - -    internal_sched_yield(); -  } -} - -ScopedErrorReportLock::~ScopedErrorReportLock() { -  CommonSanitizerReportMutex.Unlock(); -  atomic_store_relaxed(&reporting_thread, 0); -} - -void ScopedErrorReportLock::CheckLocked() { -  CommonSanitizerReportMutex.CheckLocked(); +static void (*sandboxing_callback)(); +void SetSandboxingCallback(void (*f)()) { +  sandboxing_callback = f;  }  }  // namespace __sanitizer  SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_sandbox_on_notify,                               __sanitizer_sandbox_arguments *args) { -  __sanitizer::PrepareForSandboxing(args); +  __sanitizer::PlatformPrepareForSandboxing(args);    if (__sanitizer::sandboxing_callback)      __sanitizer::sandboxing_callback();  } diff --git a/lib/sanitizer_common/sanitizer_common_nolibc.cc b/lib/sanitizer_common/sanitizer_common_nolibc.cc index ba54c739a9e06..5d322907343e7 100644 --- a/lib/sanitizer_common/sanitizer_common_nolibc.cc +++ b/lib/sanitizer_common/sanitizer_common_nolibc.cc @@ -21,7 +21,6 @@ namespace __sanitizer {  // bypassing libc.  #if !SANITIZER_WINDOWS  #if SANITIZER_LINUX -bool ShouldLogAfterPrintf() { return false; }  void LogMessageOnPrintf(const char *str) {}  #endif  void WriteToSyslog(const char *buffer) {} diff --git a/lib/sanitizer_common/sanitizer_coverage_fuchsia.cc b/lib/sanitizer_common/sanitizer_coverage_fuchsia.cc index c5be48bceaceb..b4ffcca5c30b7 100644 --- a/lib/sanitizer_common/sanitizer_coverage_fuchsia.cc +++ b/lib/sanitizer_common/sanitizer_coverage_fuchsia.cc @@ -1,11 +1,11 @@ -//===-- sanitizer_coverage_fuchsia.cc ------------------------------------===// +//===-- sanitizer_coverage_fuchsia.cc -------------------------------------===//  //  //                     The LLVM Compiler Infrastructure  //  // This file is distributed under the University of Illinois Open Source  // License. See LICENSE.TXT for details.  // -//===---------------------------------------------------------------------===// +//===----------------------------------------------------------------------===//  //  // Sanitizer Coverage Controller for Trace PC Guard, Fuchsia-specific version.  // @@ -49,7 +49,7 @@ constexpr const char kSancovSinkName[] = "sancov";  // Collects trace-pc guard coverage.  // This class relies on zero-initialization. -class TracePcGuardController { +class TracePcGuardController final {   public:    // For each PC location being tracked, there is a u32 reserved in global    // data called the "guard".  At startup, we assign each guard slot a @@ -113,11 +113,11 @@ class TracePcGuardController {    // We can always spare the 32G of address space.    static constexpr size_t MappingSize = sizeof(uptr) << 32; -  BlockingMutex setup_lock_; -  uptr *array_; -  u32 next_index_; -  zx_handle_t vmo_; -  char vmo_name_[ZX_MAX_NAME_LEN]; +  BlockingMutex setup_lock_ = BlockingMutex(LINKER_INITIALIZED); +  uptr *array_ = nullptr; +  u32 next_index_ = 0; +  zx_handle_t vmo_ = {}; +  char vmo_name_[ZX_MAX_NAME_LEN] = {};    size_t DataSize() const { return next_index_ * sizeof(uintptr_t); } @@ -146,9 +146,9 @@ class TracePcGuardController {        // indices, but we'll never move the mapping address so we don't have        // any multi-thread synchronization issues with that.        uintptr_t mapping; -      status = -          _zx_vmar_map(_zx_vmar_root_self(), 0, vmo_, 0, MappingSize, -                       ZX_VM_FLAG_PERM_READ | ZX_VM_FLAG_PERM_WRITE, &mapping); +      status = _zx_vmar_map_old(_zx_vmar_root_self(), 0, vmo_, 0, MappingSize, +                                ZX_VM_FLAG_PERM_READ | ZX_VM_FLAG_PERM_WRITE, +                                &mapping);        CHECK_EQ(status, ZX_OK);        // Hereafter other threads are free to start storing into diff --git a/lib/sanitizer_common/sanitizer_coverage_libcdep_new.cc b/lib/sanitizer_common/sanitizer_coverage_libcdep_new.cc index 3c5f29b2899b9..bea2775872890 100644 --- a/lib/sanitizer_common/sanitizer_coverage_libcdep_new.cc +++ b/lib/sanitizer_common/sanitizer_coverage_libcdep_new.cc @@ -16,7 +16,6 @@  #include "sanitizer_atomic.h"  #include "sanitizer_common.h"  #include "sanitizer_file.h" -#include "sanitizer_symbolizer.h"  using namespace __sanitizer; @@ -64,7 +63,7 @@ static void SanitizerDumpCoverage(const uptr* unsorted_pcs, uptr len) {    uptr* pcs = static_cast<uptr*>(InternalAlloc(len * sizeof(uptr)));    internal_memcpy(pcs, unsorted_pcs, len * sizeof(uptr)); -  SortArray(pcs, len); +  Sort(pcs, len);    bool module_found = false;    uptr last_base = 0; diff --git a/lib/sanitizer_common/sanitizer_deadlock_detector2.cc b/lib/sanitizer_common/sanitizer_deadlock_detector2.cc index 87d4a4d9a838d..0b0085a48bd54 100644 --- a/lib/sanitizer_common/sanitizer_deadlock_detector2.cc +++ b/lib/sanitizer_common/sanitizer_deadlock_detector2.cc @@ -111,7 +111,7 @@ struct DD : public DDetector {    SpinMutex mtx;    InternalMmapVector<u32> free_id; -  int id_gen; +  int id_gen = 0;  };  DDetector *DDetector::Create(const DDFlags *flags) { @@ -120,11 +120,7 @@ DDetector *DDetector::Create(const DDFlags *flags) {    return new(mem) DD(flags);  } -DD::DD(const DDFlags *flags) -    : flags(*flags) -    , free_id(1024) { -  id_gen = 0; -} +DD::DD(const DDFlags *flags) : flags(*flags) { free_id.reserve(1024); }  DDPhysicalThread* DD::CreatePhysicalThread() {    DDPhysicalThread *pt = (DDPhysicalThread*)MmapOrDie(sizeof(DDPhysicalThread), diff --git a/lib/sanitizer_common/sanitizer_errno.h b/lib/sanitizer_common/sanitizer_errno.h index 42cc290502bf2..9322608aa8f56 100644 --- a/lib/sanitizer_common/sanitizer_errno.h +++ b/lib/sanitizer_common/sanitizer_errno.h @@ -24,7 +24,8 @@  #if SANITIZER_FREEBSD || SANITIZER_MAC  #  define __errno_location __error -#elif SANITIZER_ANDROID || SANITIZER_NETBSD +#elif SANITIZER_ANDROID || SANITIZER_NETBSD || SANITIZER_OPENBSD || \ +  SANITIZER_RTEMS  #  define __errno_location __errno  #elif SANITIZER_SOLARIS  #  define __errno_location ___errno diff --git a/lib/sanitizer_common/sanitizer_file.cc b/lib/sanitizer_common/sanitizer_file.cc index cde54bfde8047..278d75c520ae5 100644 --- a/lib/sanitizer_common/sanitizer_file.cc +++ b/lib/sanitizer_common/sanitizer_file.cc @@ -95,32 +95,40 @@ void ReportFile::SetReportPath(const char *path) {  bool ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size,                        uptr *read_len, uptr max_len, error_t *errno_p) { -  uptr PageSize = GetPageSizeCached(); -  uptr kMinFileLen = PageSize;    *buff = nullptr;    *buff_size = 0;    *read_len = 0; +  if (!max_len) +    return true; +  uptr PageSize = GetPageSizeCached(); +  uptr kMinFileLen = Min(PageSize, max_len); +    // The files we usually open are not seekable, so try different buffer sizes. -  for (uptr size = kMinFileLen; size <= max_len; size *= 2) { -    fd_t fd = OpenFile(file_name, RdOnly, errno_p); -    if (fd == kInvalidFd) return false; +  for (uptr size = kMinFileLen;; size = Min(size * 2, max_len)) {      UnmapOrDie(*buff, *buff_size);      *buff = (char*)MmapOrDie(size, __func__);      *buff_size = size; +    fd_t fd = OpenFile(file_name, RdOnly, errno_p); +    if (fd == kInvalidFd) { +      UnmapOrDie(*buff, *buff_size); +      return false; +    }      *read_len = 0;      // Read up to one page at a time.      bool reached_eof = false; -    while (*read_len + PageSize <= size) { +    while (*read_len < size) {        uptr just_read; -      if (!ReadFromFile(fd, *buff + *read_len, PageSize, &just_read, errno_p)) { +      if (!ReadFromFile(fd, *buff + *read_len, size - *read_len, &just_read, +                        errno_p)) {          UnmapOrDie(*buff, *buff_size); +        CloseFile(fd);          return false;        } -      if (just_read == 0) { +      *read_len += just_read; +      if (just_read == 0 || *read_len == max_len) {          reached_eof = true;          break;        } -      *read_len += just_read;      }      CloseFile(fd);      if (reached_eof)  // We've read the whole file. @@ -129,6 +137,37 @@ bool ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size,    return true;  } +bool ReadFileToVector(const char *file_name, +                      InternalMmapVectorNoCtor<char> *buff, uptr max_len, +                      error_t *errno_p) { +  buff->clear(); +  if (!max_len) +    return true; +  uptr PageSize = GetPageSizeCached(); +  fd_t fd = OpenFile(file_name, RdOnly, errno_p); +  if (fd == kInvalidFd) +    return false; +  uptr read_len = 0; +  while (read_len < max_len) { +    if (read_len >= buff->size()) +      buff->resize(Min(Max(PageSize, read_len * 2), max_len)); +    CHECK_LT(read_len, buff->size()); +    CHECK_LE(buff->size(), max_len); +    uptr just_read; +    if (!ReadFromFile(fd, buff->data() + read_len, buff->size() - read_len, +                      &just_read, errno_p)) { +      CloseFile(fd); +      return false; +    } +    read_len += just_read; +    if (!just_read) +      break; +  } +  CloseFile(fd); +  buff->resize(read_len); +  return true; +} +  static const char kPathSeparator = SANITIZER_WINDOWS ? ';' : ':';  char *FindPathToBinary(const char *name) { @@ -140,7 +179,7 @@ char *FindPathToBinary(const char *name) {    if (!path)      return nullptr;    uptr name_len = internal_strlen(name); -  InternalScopedBuffer<char> buffer(kMaxPathLength); +  InternalMmapVector<char> buffer(kMaxPathLength);    const char *beg = path;    while (true) {      const char *end = internal_strchrnul(beg, kPathSeparator); diff --git a/lib/sanitizer_common/sanitizer_flag_parser.h b/lib/sanitizer_common/sanitizer_flag_parser.h index f649f5bffea70..705bfe23b309a 100644 --- a/lib/sanitizer_common/sanitizer_flag_parser.h +++ b/lib/sanitizer_common/sanitizer_flag_parser.h @@ -81,7 +81,7 @@ inline bool FlagHandler<const char *>::Parse(const char *value) {  template <>  inline bool FlagHandler<int>::Parse(const char *value) { -  char *value_end; +  const char *value_end;    *t_ = internal_simple_strtoll(value, &value_end, 10);    bool ok = *value_end == 0;    if (!ok) Printf("ERROR: Invalid value for int option: '%s'\n", value); @@ -90,7 +90,7 @@ inline bool FlagHandler<int>::Parse(const char *value) {  template <>  inline bool FlagHandler<uptr>::Parse(const char *value) { -  char *value_end; +  const char *value_end;    *t_ = internal_simple_strtoll(value, &value_end, 10);    bool ok = *value_end == 0;    if (!ok) Printf("ERROR: Invalid value for uptr option: '%s'\n", value); diff --git a/lib/sanitizer_common/sanitizer_flags.cc b/lib/sanitizer_common/sanitizer_flags.cc index 913ce3cb423ee..4631dfb7120cf 100644 --- a/lib/sanitizer_common/sanitizer_flags.cc +++ b/lib/sanitizer_common/sanitizer_flags.cc @@ -22,14 +22,6 @@ namespace __sanitizer {  CommonFlags common_flags_dont_use; -struct FlagDescription { -  const char *name; -  const char *description; -  FlagDescription *next; -}; - -IntrusiveList<FlagDescription> flag_descriptions; -  void CommonFlags::SetDefaults() {  #define COMMON_FLAG(Type, Name, DefaultValue, Description) Name = DefaultValue;  #include "sanitizer_flags.inc" diff --git a/lib/sanitizer_common/sanitizer_flags.inc b/lib/sanitizer_common/sanitizer_flags.inc index 445e25f9df70b..cfe8af8934233 100644 --- a/lib/sanitizer_common/sanitizer_flags.inc +++ b/lib/sanitizer_common/sanitizer_flags.inc @@ -56,7 +56,7 @@ COMMON_FLAG(      "Mention name of executable when reporting error and "      "append executable name to logs (as in \"log_path.exe_name.pid\").")  COMMON_FLAG( -    bool, log_to_syslog, SANITIZER_ANDROID || SANITIZER_MAC, +    bool, log_to_syslog, (bool)SANITIZER_ANDROID || (bool)SANITIZER_MAC,      "Write all sanitizer output to syslog in addition to other means of "      "logging.")  COMMON_FLAG( @@ -93,6 +93,8 @@ COMMON_FLAG(HandleSignalMode, handle_abort, kHandleSignalNo,              COMMON_FLAG_HANDLE_SIGNAL_HELP(SIGABRT))  COMMON_FLAG(HandleSignalMode, handle_sigill, kHandleSignalNo,              COMMON_FLAG_HANDLE_SIGNAL_HELP(SIGILL)) +COMMON_FLAG(HandleSignalMode, handle_sigtrap, kHandleSignalNo, +            COMMON_FLAG_HANDLE_SIGNAL_HELP(SIGTRAP))  COMMON_FLAG(HandleSignalMode, handle_sigfpe, kHandleSignalYes,              COMMON_FLAG_HANDLE_SIGNAL_HELP(SIGFPE))  #undef COMMON_FLAG_HANDLE_SIGNAL_HELP @@ -132,7 +134,8 @@ COMMON_FLAG(uptr, soft_rss_limit_mb, 0,              " This limit does not affect memory allocations other than"              " malloc/new.")  COMMON_FLAG(bool, heap_profile, false, "Experimental heap profiler, asan-only") -COMMON_FLAG(s32, allocator_release_to_os_interval_ms, 5000, +COMMON_FLAG(s32, allocator_release_to_os_interval_ms, +            ((bool)SANITIZER_FUCHSIA || (bool)SANITIZER_WINDOWS) ? -1 : 5000,              "Only affects a 64-bit allocator. If set, tries to release unused "              "memory to the OS, but not more often than this interval (in "              "milliseconds). Negative values mean do not attempt to release " @@ -222,7 +225,7 @@ COMMON_FLAG(bool, decorate_proc_maps, false, "If set, decorate sanitizer "  COMMON_FLAG(int, exitcode, 1, "Override the program exit status if the tool "                                "found an error")  COMMON_FLAG( -    bool, abort_on_error, SANITIZER_ANDROID || SANITIZER_MAC, +    bool, abort_on_error, (bool)SANITIZER_ANDROID || (bool)SANITIZER_MAC,      "If set, the tool calls abort() instead of _exit() after printing the "      "error report.")  COMMON_FLAG(bool, suppress_equal_pcs, true, @@ -237,3 +240,6 @@ COMMON_FLAG(bool, dump_instruction_bytes, false,  COMMON_FLAG(bool, dump_registers, true,            "If true, dump values of CPU registers when SEGV happens. Only "            "available on OS X for now.") +COMMON_FLAG(bool, detect_write_exec, false, +          "If true, triggers warning when writable-executable pages requests " +          "are being made") diff --git a/lib/sanitizer_common/sanitizer_fuchsia.cc b/lib/sanitizer_common/sanitizer_fuchsia.cc index 936ec794b8e86..391620690f302 100644 --- a/lib/sanitizer_common/sanitizer_fuchsia.cc +++ b/lib/sanitizer_common/sanitizer_fuchsia.cc @@ -1,16 +1,16 @@ -//===-- sanitizer_fuchsia.cc ---------------------------------------------===// +//===-- sanitizer_fuchsia.cc ----------------------------------------------===//  //  //                     The LLVM Compiler Infrastructure  //  // This file is distributed under the University of Illinois Open Source  // License. See LICENSE.TXT for details.  // -//===---------------------------------------------------------------------===// +//===----------------------------------------------------------------------===//  //  // This file is shared between AddressSanitizer and other sanitizer  // run-time libraries and implements Fuchsia-specific functions from  // sanitizer_common.h. -//===---------------------------------------------------------------------===// +//===----------------------------------------------------------------------===//  #include "sanitizer_fuchsia.h"  #if SANITIZER_FUCHSIA @@ -18,19 +18,20 @@  #include "sanitizer_common.h"  #include "sanitizer_libc.h"  #include "sanitizer_mutex.h" -#include "sanitizer_stacktrace.h"  #include <limits.h>  #include <pthread.h>  #include <stdlib.h>  #include <unistd.h> -#include <unwind.h>  #include <zircon/errors.h>  #include <zircon/process.h>  #include <zircon/syscalls.h>  namespace __sanitizer { +// TODO(phosek): remove this and replace it with ZX_TIME_INFINITE +#define ZX_TIME_INFINITE_OLD INT64_MAX +  void NORETURN internal__exit(int exitcode) { _zx_process_exit(exitcode); }  uptr internal_sched_yield() { @@ -49,9 +50,9 @@ unsigned int internal_sleep(unsigned int seconds) {    return 0;  } -u64 NanoTime() { return _zx_time_get(ZX_CLOCK_UTC); } +u64 NanoTime() { return _zx_clock_get(ZX_CLOCK_UTC); } -u64 MonotonicNanoTime() { return _zx_time_get(ZX_CLOCK_MONOTONIC); } +u64 MonotonicNanoTime() { return _zx_clock_get(ZX_CLOCK_MONOTONIC); }  uptr internal_getpid() {    zx_info_handle_basic_t info; @@ -66,7 +67,7 @@ uptr internal_getpid() {  uptr GetThreadSelf() { return reinterpret_cast<uptr>(thrd_current()); } -uptr GetTid() { return GetThreadSelf(); } +tid_t GetTid() { return GetThreadSelf(); }  void Abort() { abort(); } @@ -89,13 +90,10 @@ void GetThreadStackTopAndBottom(bool, uptr *stack_top, uptr *stack_bottom) {  }  void MaybeReexec() {} -void PrepareForSandboxing(__sanitizer_sandbox_arguments *args) {} +void CheckASLR() {} +void PlatformPrepareForSandboxing(__sanitizer_sandbox_arguments *args) {}  void DisableCoreDumperIfNecessary() {}  void InstallDeadlySignalHandlers(SignalHandlerType handler) {} -void StartReportDeadlySignal() {} -void ReportDeadlySignal(const SignalContext &sig, u32 tid, -                        UnwindSignalStackCallbackType unwind, -                        const void *unwind_context) {}  void SetAlternateSignalStack() {}  void UnsetAlternateSignalStack() {}  void InitTlsSize() {} @@ -106,42 +104,6 @@ bool SignalContext::IsStackOverflow() const { return false; }  void SignalContext::DumpAllRegisters(void *context) { UNIMPLEMENTED(); }  const char *SignalContext::Describe() const { UNIMPLEMENTED(); } -struct UnwindTraceArg { -  BufferedStackTrace *stack; -  u32 max_depth; -}; - -_Unwind_Reason_Code Unwind_Trace(struct _Unwind_Context *ctx, void *param) { -  UnwindTraceArg *arg = static_cast<UnwindTraceArg *>(param); -  CHECK_LT(arg->stack->size, arg->max_depth); -  uptr pc = _Unwind_GetIP(ctx); -  if (pc < PAGE_SIZE) return _URC_NORMAL_STOP; -  arg->stack->trace_buffer[arg->stack->size++] = pc; -  return (arg->stack->size == arg->max_depth ? _URC_NORMAL_STOP -                                             : _URC_NO_REASON); -} - -void BufferedStackTrace::SlowUnwindStack(uptr pc, u32 max_depth) { -  CHECK_GE(max_depth, 2); -  size = 0; -  UnwindTraceArg arg = {this, Min(max_depth + 1, kStackTraceMax)}; -  _Unwind_Backtrace(Unwind_Trace, &arg); -  CHECK_GT(size, 0); -  // We need to pop a few frames so that pc is on top. -  uptr to_pop = LocatePcInTrace(pc); -  // trace_buffer[0] belongs to the current function so we always pop it, -  // unless there is only 1 frame in the stack trace (1 frame is always better -  // than 0!). -  PopStackFrames(Min(to_pop, static_cast<uptr>(1))); -  trace_buffer[0] = pc; -} - -void BufferedStackTrace::SlowUnwindStackWithContext(uptr pc, void *context, -                                                    u32 max_depth) { -  CHECK_NE(context, nullptr); -  UNREACHABLE("signal context doesn't exist"); -} -  enum MutexState : int { MtxUnlocked = 0, MtxLocked = 1, MtxSleeping = 2 };  BlockingMutex::BlockingMutex() { @@ -161,7 +123,7 @@ void BlockingMutex::Lock() {      return;    while (atomic_exchange(m, MtxSleeping, memory_order_acquire) != MtxUnlocked) {      zx_status_t status = _zx_futex_wait(reinterpret_cast<zx_futex_t *>(m), -                                        MtxSleeping, ZX_TIME_INFINITE); +                                        MtxSleeping, ZX_TIME_INFINITE_OLD);      if (status != ZX_ERR_BAD_STATE)  // Normal race.        CHECK_EQ(status, ZX_OK);    } @@ -212,8 +174,9 @@ static void *DoAnonymousMmapOrDie(uptr size, const char *mem_type,    // TODO(mcgrathr): Maybe allocate a VMAR for all sanitizer heap and use that?    uintptr_t addr; -  status = _zx_vmar_map(_zx_vmar_root_self(), 0, vmo, 0, size, -                        ZX_VM_FLAG_PERM_READ | ZX_VM_FLAG_PERM_WRITE, &addr); +  status = +      _zx_vmar_map_old(_zx_vmar_root_self(), 0, vmo, 0, size, +                       ZX_VM_FLAG_PERM_READ | ZX_VM_FLAG_PERM_WRITE, &addr);    _zx_handle_close(vmo);    if (status != ZX_OK) { @@ -247,10 +210,10 @@ uptr ReservedAddressRange::Init(uptr init_size, const char *name,    uintptr_t base;    zx_handle_t vmar;    zx_status_t status = -      _zx_vmar_allocate(_zx_vmar_root_self(), 0, init_size, -                        ZX_VM_FLAG_CAN_MAP_READ | ZX_VM_FLAG_CAN_MAP_WRITE | -                            ZX_VM_FLAG_CAN_MAP_SPECIFIC, -                        &vmar, &base); +      _zx_vmar_allocate_old(_zx_vmar_root_self(), 0, init_size, +                            ZX_VM_FLAG_CAN_MAP_READ | ZX_VM_FLAG_CAN_MAP_WRITE | +                                ZX_VM_FLAG_CAN_MAP_SPECIFIC, +                            &vmar, &base);    if (status != ZX_OK)      ReportMmapFailureAndDie(init_size, name, "zx_vmar_allocate", status);    base_ = reinterpret_cast<void *>(base); @@ -272,11 +235,11 @@ static uptr DoMmapFixedOrDie(zx_handle_t vmar, uptr fixed_addr, uptr map_size,        ReportMmapFailureAndDie(map_size, name, "zx_vmo_create", status);      return 0;    } -  _zx_object_set_property(vmo, ZX_PROP_NAME, name, sizeof(name) - 1); +  _zx_object_set_property(vmo, ZX_PROP_NAME, name, internal_strlen(name));    DCHECK_GE(base + size_, map_size + offset);    uintptr_t addr; -  status = _zx_vmar_map( +  status = _zx_vmar_map_old(        vmar, offset, vmo, 0, map_size,        ZX_VM_FLAG_PERM_READ | ZX_VM_FLAG_PERM_WRITE | ZX_VM_FLAG_SPECIFIC,        &addr); @@ -316,20 +279,16 @@ void UnmapOrDieVmar(void *addr, uptr size, zx_handle_t target_vmar) {    DecreaseTotalMmap(size);  } -void ReservedAddressRange::Unmap(uptr fixed_addr, uptr size) { -  uptr offset = fixed_addr - reinterpret_cast<uptr>(base_); -  uptr addr = reinterpret_cast<uptr>(base_) + offset; -  void *addr_as_void = reinterpret_cast<void *>(addr); -  uptr base_as_uptr = reinterpret_cast<uptr>(base_); -  // Only unmap at the beginning or end of the range. -  CHECK((addr_as_void == base_) || (addr + size == base_as_uptr + size_)); +void ReservedAddressRange::Unmap(uptr addr, uptr size) {    CHECK_LE(size, size_); +  if (addr == reinterpret_cast<uptr>(base_)) +    // If we unmap the whole range, just null out the base. +    base_ = (size == size_) ? nullptr : reinterpret_cast<void*>(addr + size); +  else +    CHECK_EQ(addr + size, reinterpret_cast<uptr>(base_) + size_); +  size_ -= size;    UnmapOrDieVmar(reinterpret_cast<void *>(addr), size,                   static_cast<zx_handle_t>(os_handle_)); -  if (addr_as_void == base_) { -    base_ = reinterpret_cast<void *>(addr + size); -  } -  size_ = size_ - size;  }  // This should never be called. @@ -361,8 +320,9 @@ void *MmapAlignedOrDieOnFatalError(uptr size, uptr alignment,    // beginning of the VMO, and unmap the excess before and after.    size_t map_size = size + alignment;    uintptr_t addr; -  status = _zx_vmar_map(_zx_vmar_root_self(), 0, vmo, 0, map_size, -                        ZX_VM_FLAG_PERM_READ | ZX_VM_FLAG_PERM_WRITE, &addr); +  status = +      _zx_vmar_map_old(_zx_vmar_root_self(), 0, vmo, 0, map_size, +                       ZX_VM_FLAG_PERM_READ | ZX_VM_FLAG_PERM_WRITE, &addr);    if (status == ZX_OK) {      uintptr_t map_addr = addr;      uintptr_t map_end = map_addr + map_size; @@ -374,11 +334,11 @@ void *MmapAlignedOrDieOnFatalError(uptr size, uptr alignment,                                     sizeof(info), NULL, NULL);        if (status == ZX_OK) {          uintptr_t new_addr; -        status = -            _zx_vmar_map(_zx_vmar_root_self(), addr - info.base, vmo, 0, size, -                         ZX_VM_FLAG_PERM_READ | ZX_VM_FLAG_PERM_WRITE | -                             ZX_VM_FLAG_SPECIFIC_OVERWRITE, -                         &new_addr); +        status = _zx_vmar_map_old(_zx_vmar_root_self(), addr - info.base, vmo, +                                  0, size, +                                  ZX_VM_FLAG_PERM_READ | ZX_VM_FLAG_PERM_WRITE | +                                      ZX_VM_FLAG_SPECIFIC_OVERWRITE, +                                  &new_addr);          if (status == ZX_OK) CHECK_EQ(new_addr, addr);        }      } @@ -418,16 +378,7 @@ bool IsAccessibleMemoryRange(uptr beg, uptr size) {    zx_handle_t vmo;    zx_status_t status = _zx_vmo_create(size, 0, &vmo);    if (status == ZX_OK) { -    while (size > 0) { -      size_t wrote; -      status = _zx_vmo_write(vmo, reinterpret_cast<const void *>(beg), 0, size, -                             &wrote); -      if (status != ZX_OK) break; -      CHECK_GT(wrote, 0); -      CHECK_LE(wrote, size); -      beg += wrote; -      size -= wrote; -    } +    status = _zx_vmo_write(vmo, reinterpret_cast<const void *>(beg), 0, size);      _zx_handle_close(vmo);    }    return status == ZX_OK; @@ -447,8 +398,8 @@ bool ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size,        if (vmo_size < max_len) max_len = vmo_size;        size_t map_size = RoundUpTo(max_len, PAGE_SIZE);        uintptr_t addr; -      status = _zx_vmar_map(_zx_vmar_root_self(), 0, vmo, 0, map_size, -                            ZX_VM_FLAG_PERM_READ, &addr); +      status = _zx_vmar_map_old(_zx_vmar_root_self(), 0, vmo, 0, map_size, +                                ZX_VM_FLAG_PERM_READ, &addr);        if (status == ZX_OK) {          *buff = reinterpret_cast<char *>(addr);          *buff_size = map_size; @@ -462,7 +413,31 @@ bool ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size,  }  void RawWrite(const char *buffer) { -  __sanitizer_log_write(buffer, internal_strlen(buffer)); +  constexpr size_t size = 128; +  static _Thread_local char line[size]; +  static _Thread_local size_t lastLineEnd = 0; +  static _Thread_local size_t cur = 0; + +  while (*buffer) { +    if (cur >= size) { +      if (lastLineEnd == 0) +        lastLineEnd = size; +      __sanitizer_log_write(line, lastLineEnd); +      internal_memmove(line, line + lastLineEnd, cur - lastLineEnd); +      cur = cur - lastLineEnd; +      lastLineEnd = 0; +    } +    if (*buffer == '\n') +      lastLineEnd = cur + 1; +    line[cur++] = *buffer++; +  } +  // Flush all complete lines before returning. +  if (lastLineEnd != 0) { +    __sanitizer_log_write(line, lastLineEnd); +    internal_memmove(line, line + lastLineEnd, cur - lastLineEnd); +    cur = cur - lastLineEnd; +    lastLineEnd = 0; +  }  }  void CatastrophicErrorWrite(const char *buffer, uptr length) { @@ -486,8 +461,10 @@ const char *GetEnv(const char *name) {  }  uptr ReadBinaryName(/*out*/ char *buf, uptr buf_len) { -  const char *argv0 = StoredArgv[0]; -  if (!argv0) argv0 = "<UNKNOWN>"; +  const char *argv0 = "<UNKNOWN>"; +  if (StoredArgv && StoredArgv[0]) { +    argv0 = StoredArgv[0]; +  }    internal_strncpy(buf, argv0, buf_len);    return internal_strlen(buf);  } @@ -500,9 +477,7 @@ uptr MainThreadStackBase, MainThreadStackSize;  bool GetRandom(void *buffer, uptr length, bool blocking) {    CHECK_LE(length, ZX_CPRNG_DRAW_MAX_LEN); -  size_t size; -  CHECK_EQ(_zx_cprng_draw(buffer, length, &size), ZX_OK); -  CHECK_EQ(size, length); +  _zx_cprng_draw(buffer, length);    return true;  } diff --git a/lib/sanitizer_common/sanitizer_getauxval.h b/lib/sanitizer_common/sanitizer_getauxval.h index 934e311a78512..b22fcade5f9d2 100644 --- a/lib/sanitizer_common/sanitizer_getauxval.h +++ b/lib/sanitizer_common/sanitizer_getauxval.h @@ -18,7 +18,7 @@  #include "sanitizer_platform.h" -#if SANITIZER_LINUX +#if SANITIZER_LINUX || SANITIZER_FUCHSIA  # include <features.h> @@ -26,7 +26,8 @@  #  define __GLIBC_PREREQ(x, y) 0  # endif -# if __GLIBC_PREREQ(2, 16) || (SANITIZER_ANDROID && __ANDROID_API__ >= 21) +# if __GLIBC_PREREQ(2, 16) || (SANITIZER_ANDROID && __ANDROID_API__ >= 21) || \ +     SANITIZER_FUCHSIA  #  define SANITIZER_USE_GETAUXVAL 1  # else  #  define SANITIZER_USE_GETAUXVAL 0 @@ -42,6 +43,6 @@ extern "C" SANITIZER_WEAK_ATTRIBUTE  unsigned long getauxval(unsigned long type);  // NOLINT  # endif -#endif // SANITIZER_LINUX +#endif // SANITIZER_LINUX || SANITIZER_FUCHSIA  #endif // SANITIZER_GETAUXVAL_H diff --git a/lib/sanitizer_common/sanitizer_interceptors_ioctl_netbsd.inc b/lib/sanitizer_common/sanitizer_interceptors_ioctl_netbsd.inc new file mode 100644 index 0000000000000..9a2a9f1206848 --- /dev/null +++ b/lib/sanitizer_common/sanitizer_interceptors_ioctl_netbsd.inc @@ -0,0 +1,1489 @@ +//===-- sanitizer_interceptors_ioctl_netbsd.inc -----------------*- C++ -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Ioctl handling in common sanitizer interceptors. +//===----------------------------------------------------------------------===// + +#if SANITIZER_NETBSD + +#include "sanitizer_flags.h" + +struct ioctl_desc { +  unsigned req; +  // FIXME: support read+write arguments. Currently READWRITE and WRITE do the +  // same thing. +  // XXX: The declarations below may use WRITE instead of READWRITE, unless +  // explicitly noted. +  enum { NONE, READ, WRITE, READWRITE, CUSTOM } type : 3; +  unsigned size : 29; +  const char *name; +}; + +const unsigned ioctl_table_max = 1198; +static ioctl_desc ioctl_table[ioctl_table_max]; +static unsigned ioctl_table_size = 0; + +// This can not be declared as a global, because references to struct_*_sz +// require a global initializer. And this table must be available before global +// initializers are run. +static void ioctl_table_fill() { +#define _(rq, tp, sz)                                                          \ +  if (IOCTL_##rq != IOCTL_NOT_PRESENT) {                                       \ +    CHECK(ioctl_table_size < ioctl_table_max);                                 \ +    ioctl_table[ioctl_table_size].req = IOCTL_##rq;                            \ +    ioctl_table[ioctl_table_size].type = ioctl_desc::tp;                       \ +    ioctl_table[ioctl_table_size].size = sz;                                   \ +    ioctl_table[ioctl_table_size].name = #rq;                                  \ +    ++ioctl_table_size;                                                        \ +  } + +  /* Entries from file: altq/altq_afmap.h */ +  _(AFM_ADDFMAP, READWRITE, struct_atm_flowmap_sz); +  _(AFM_DELFMAP, READWRITE, struct_atm_flowmap_sz); +  _(AFM_CLEANFMAP, READWRITE, struct_atm_flowmap_sz); +  _(AFM_GETFMAP, READWRITE, struct_atm_flowmap_sz); +  /* Entries from file: altq/altq.h */ +  _(ALTQGTYPE, READWRITE, struct_altqreq_sz); +  _(ALTQTBRSET, READ, struct_tbrreq_sz); +  _(ALTQTBRGET, READWRITE, struct_tbrreq_sz); +  /* Entries from file: altq/altq_blue.h */ +  _(BLUE_IF_ATTACH, READ, struct_blue_interface_sz); +  _(BLUE_DISABLE, READ, struct_blue_interface_sz); +  _(BLUE_CONFIG, READWRITE, struct_blue_conf_sz); +  _(BLUE_GETSTATS, READWRITE, struct_blue_stats_sz); +  /* Entries from file: altq/altq_cbq.h */ +  _(CBQ_ENABLE, READ, struct_cbq_interface_sz); +  _(CBQ_ADD_CLASS, READWRITE, struct_cbq_add_class_sz); +  _(CBQ_DEL_CLASS, READ, struct_cbq_delete_class_sz); +  _(CBQ_MODIFY_CLASS, READWRITE, struct_cbq_modify_class_sz); +  _(CBQ_DEL_FILTER, READ, struct_cbq_delete_filter_sz); +  _(CBQ_GETSTATS, READWRITE, struct_cbq_getstats_sz); +  /* Entries from file: altq/altq_cdnr.h */ +  _(CDNR_IF_DETACH, READ, struct_cdnr_interface_sz); +  _(CDNR_ADD_FILTER, READWRITE, struct_cdnr_add_filter_sz); +  _(CDNR_GETSTATS, READWRITE, struct_cdnr_get_stats_sz); +  _(CDNR_ADD_ELEM, READWRITE, struct_cdnr_add_element_sz); +  _(CDNR_DEL_ELEM, READ, struct_cdnr_delete_element_sz); +  _(CDNR_ADD_TBM, READWRITE, struct_cdnr_add_tbmeter_sz); +  _(CDNR_MOD_TBM, READ, struct_cdnr_modify_tbmeter_sz); +  _(CDNR_TBM_STATS, READWRITE, struct_cdnr_tbmeter_stats_sz); +  _(CDNR_ADD_TCM, READWRITE, struct_cdnr_add_trtcm_sz); +  _(CDNR_MOD_TCM, READWRITE, struct_cdnr_modify_trtcm_sz); +  _(CDNR_TCM_STATS, READWRITE, struct_cdnr_tcm_stats_sz); +  _(CDNR_ADD_TSW, READWRITE, struct_cdnr_add_tswtcm_sz); +  _(CDNR_MOD_TSW, READWRITE, struct_cdnr_modify_tswtcm_sz); +  /* Entries from file: altq/altq_fifoq.h */ +  _(FIFOQ_CONFIG, READWRITE, struct_fifoq_conf_sz); +  _(FIFOQ_GETSTATS, READWRITE, struct_fifoq_getstats_sz); +  /* Entries from file: altq/altq_hfsc.h */ +  _(HFSC_CLEAR_HIERARCHY, READ, struct_hfsc_interface_sz); +  _(HFSC_ADD_CLASS, READWRITE, struct_hfsc_add_class_sz); +  _(HFSC_GETSTATS, READWRITE, struct_hfsc_class_stats_sz); +  /* Entries from file: altq/altq_jobs.h */ +  _(JOBS_IF_ATTACH, READ, struct_jobs_attach_sz); +  _(JOBS_IF_DETACH, READ, struct_jobs_interface_sz); +  _(JOBS_ENABLE, READ, struct_jobs_interface_sz); +  _(JOBS_DISABLE, READ, struct_jobs_interface_sz); +  _(JOBS_CLEAR, READ, struct_jobs_interface_sz); +  _(JOBS_ADD_CLASS, READWRITE, struct_jobs_add_class_sz); +  _(JOBS_MOD_CLASS, READ, struct_jobs_modify_class_sz); +  /* Entries from file: altq/altq_priq.h */ +  _(PRIQ_IF_ATTACH, READ, struct_priq_interface_sz); +  _(PRIQ_CLEAR, READ, struct_priq_interface_sz); +  _(PRIQ_ADD_CLASS, READWRITE, struct_priq_add_class_sz); +  _(PRIQ_DEL_CLASS, READ, struct_priq_delete_class_sz); +  _(PRIQ_MOD_CLASS, READ, struct_priq_modify_class_sz); +  _(PRIQ_ADD_FILTER, READWRITE, struct_priq_add_filter_sz); +  _(PRIQ_DEL_FILTER, READ, struct_priq_delete_filter_sz); +  _(PRIQ_GETSTATS, READWRITE, struct_priq_class_stats_sz); +  /* Entries from file: altq/altq_red.h */ +  _(RED_CONFIG, READWRITE, struct_red_conf_sz); +  _(RED_GETSTATS, READWRITE, struct_red_stats_sz); +  _(RED_SETDEFAULTS, READ, struct_redparams_sz); +  /* Entries from file: altq/altq_rio.h */ +  _(RIO_CONFIG, READWRITE, struct_rio_conf_sz); +  _(RIO_GETSTATS, READWRITE, struct_rio_stats_sz); +  _(RIO_SETDEFAULTS, READ, struct_redparams_sz); +  /* Entries from file: altq/altq_wfq.h */ +  _(WFQ_CONFIG, READWRITE, struct_wfq_conf_sz); +  _(WFQ_GET_QID, READWRITE, struct_wfq_getqid_sz); +  _(WFQ_SET_WEIGHT, READWRITE, struct_wfq_setweight_sz); +  /* Entries from file: crypto/cryptodev.h */ +  _(CRIOGET, READWRITE, sizeof(u32)); +  _(CIOCFSESSION, READ, sizeof(u32)); +  _(CIOCKEY, READWRITE, struct_crypt_kop_sz); +  _(CIOCNFKEYM, READWRITE, struct_crypt_mkop_sz); +  _(CIOCNFSESSION, READ, struct_crypt_sfop_sz); +  _(CIOCNCRYPTRETM, READWRITE, struct_cryptret_sz); +  _(CIOCNCRYPTRET, READWRITE, struct_crypt_result_sz); +  _(CIOCGSESSION, READWRITE, struct_session_op_sz); +  _(CIOCNGSESSION, READWRITE, struct_crypt_sgop_sz); +  _(CIOCCRYPT, READWRITE, struct_crypt_op_sz); +  _(CIOCNCRYPTM, READWRITE, struct_crypt_mop_sz); +  _(CIOCASYMFEAT, WRITE, sizeof(u32)); +  /* Entries from file: dev/apm/apmio.h */ +  _(APM_IOC_REJECT, READ, struct_apm_event_info_sz); +  _(OAPM_IOC_GETPOWER, WRITE, struct_apm_power_info_sz); +  _(APM_IOC_GETPOWER, READWRITE, struct_apm_power_info_sz); +  _(APM_IOC_NEXTEVENT, WRITE, struct_apm_event_info_sz); +  _(APM_IOC_DEV_CTL, READ, struct_apm_ctl_sz); +  /* Entries from file: dev/dm/netbsd-dm.h */ +  _(NETBSD_DM_IOCTL, READWRITE, struct_plistref_sz); +  /* Entries from file: dev/dmover/dmover_io.h */ +  _(DMIO_SETFUNC, READ, struct_dmio_setfunc_sz); +  /* Entries from file: dev/dtv/dtvio_demux.h */ +  _(DMX_START, NONE, 0); +  _(DMX_STOP, NONE, 0); +  _(DMX_SET_FILTER, READ, struct_dmx_sct_filter_params_sz); +  _(DMX_SET_PES_FILTER, READ, struct_dmx_pes_filter_params_sz); +  _(DMX_SET_BUFFER_SIZE, NONE, 0); +  _(DMX_GET_STC, READWRITE, struct_dmx_stc_sz); +  _(DMX_ADD_PID, READ, sizeof(u16)); +  _(DMX_REMOVE_PID, READ, sizeof(u16)); +  _(DMX_GET_CAPS, WRITE, struct_dmx_caps_sz); +  _(DMX_SET_SOURCE, READ, enum_dmx_source_sz); +  /* Entries from file: dev/dtv/dtvio_frontend.h */ +  _(FE_READ_STATUS, WRITE, enum_fe_status_sz); +  _(FE_READ_BER, WRITE, sizeof(u32)); +  _(FE_READ_SNR, WRITE, sizeof(u16)); +  _(FE_READ_SIGNAL_STRENGTH, WRITE, sizeof(u16)); +  _(FE_READ_UNCORRECTED_BLOCKS, WRITE, sizeof(u32)); +  _(FE_SET_FRONTEND, READWRITE, struct_dvb_frontend_parameters_sz); +  _(FE_GET_FRONTEND, WRITE, struct_dvb_frontend_parameters_sz); +  _(FE_GET_EVENT, WRITE, struct_dvb_frontend_event_sz); +  _(FE_GET_INFO, WRITE, struct_dvb_frontend_info_sz); +  _(FE_DISEQC_RESET_OVERLOAD, NONE, 0); +  _(FE_DISEQC_SEND_MASTER_CMD, READ, struct_dvb_diseqc_master_cmd_sz); +  _(FE_DISEQC_RECV_SLAVE_REPLY, WRITE, struct_dvb_diseqc_slave_reply_sz); +  _(FE_DISEQC_SEND_BURST, READ, enum_fe_sec_mini_cmd_sz); +  _(FE_SET_TONE, READ, enum_fe_sec_tone_mode_sz); +  _(FE_SET_VOLTAGE, READ, enum_fe_sec_voltage_sz); +  _(FE_ENABLE_HIGH_LNB_VOLTAGE, READ, sizeof(int)); +  _(FE_SET_FRONTEND_TUNE_MODE, READ, sizeof(unsigned int)); +  _(FE_DISHNETWORK_SEND_LEGACY_CMD, READ, sizeof(unsigned long)); +  /* Entries from file: dev/filemon/filemon.h */ +  _(FILEMON_SET_FD, READWRITE, sizeof(int)); +  _(FILEMON_SET_PID, READWRITE, sizeof(int)); +  /* Entries from file: dev/hdaudio/hdaudioio.h */ +  _(HDAUDIO_FGRP_INFO, READWRITE, struct_plistref_sz); +  _(HDAUDIO_FGRP_GETCONFIG, READWRITE, struct_plistref_sz); +  _(HDAUDIO_FGRP_SETCONFIG, READWRITE, struct_plistref_sz); +  _(HDAUDIO_FGRP_WIDGET_INFO, READWRITE, struct_plistref_sz); +  _(HDAUDIO_FGRP_CODEC_INFO, READWRITE, struct_plistref_sz); +  _(HDAUDIO_AFG_WIDGET_INFO, READWRITE, struct_plistref_sz); +  _(HDAUDIO_AFG_CODEC_INFO, READWRITE, struct_plistref_sz); +  /* Entries from file: dev/hdmicec/hdmicecio.h */ +  _(CEC_GET_PHYS_ADDR, WRITE, sizeof(u16)); +  _(CEC_GET_LOG_ADDRS, WRITE, sizeof(u16)); +  _(CEC_SET_LOG_ADDRS, READ, sizeof(u16)); +  _(CEC_GET_VENDOR_ID, WRITE, sizeof(u32)); +  /* Entries from file: dev/hpc/hpcfbio.h */ +  _(HPCFBIO_GCONF, READWRITE, struct_hpcfb_fbconf_sz); +  _(HPCFBIO_SCONF, READ, struct_hpcfb_fbconf_sz); +  _(HPCFBIO_GDSPCONF, READWRITE, struct_hpcfb_dspconf_sz); +  _(HPCFBIO_SDSPCONF, READ, struct_hpcfb_dspconf_sz); +  _(HPCFBIO_GOP, WRITE, struct_hpcfb_dsp_op_sz); +  _(HPCFBIO_SOP, READWRITE, struct_hpcfb_dsp_op_sz); +  /* Entries from file: dev/i2o/iopio.h */ +  _(IOPIOCPT, READWRITE, struct_ioppt_sz); +  _(IOPIOCGLCT, READWRITE, struct_iovec_sz); +  _(IOPIOCGSTATUS, READWRITE, struct_iovec_sz); +  _(IOPIOCRECONFIG, NONE, 0); +  _(IOPIOCGTIDMAP, READWRITE, struct_iovec_sz); +  /* Entries from file: dev/ic/athioctl.h */ +  _(SIOCGATHSTATS, READWRITE, struct_ifreq_sz); +  _(SIOCGATHDIAG, READWRITE, struct_ath_diag_sz); +  /* Entries from file: dev/ic/bt8xx.h */ +  _(METEORCAPTUR, READ, sizeof(int)); +  _(METEORCAPFRM, READ, struct_meteor_capframe_sz); +  _(METEORSETGEO, READ, struct_meteor_geomet_sz); +  _(METEORGETGEO, WRITE, struct_meteor_geomet_sz); +  _(METEORSTATUS, WRITE, sizeof(unsigned short)); +  _(METEORSHUE, READ, sizeof(signed char)); +  _(METEORGHUE, WRITE, sizeof(signed char)); +  _(METEORSFMT, READ, sizeof(unsigned int)); +  _(METEORGFMT, WRITE, sizeof(unsigned int)); +  _(METEORSINPUT, READ, sizeof(unsigned int)); +  _(METEORGINPUT, WRITE, sizeof(unsigned int)); +  _(METEORSCHCV, READ, sizeof(unsigned char)); +  _(METEORGCHCV, WRITE, sizeof(unsigned char)); +  _(METEORSCOUNT, READ, struct_meteor_counts_sz); +  _(METEORGCOUNT, WRITE, struct_meteor_counts_sz); +  _(METEORSFPS, READ, sizeof(unsigned short)); +  _(METEORGFPS, WRITE, sizeof(unsigned short)); +  _(METEORSSIGNAL, READ, sizeof(unsigned int)); +  _(METEORGSIGNAL, WRITE, sizeof(unsigned int)); +  _(METEORSVIDEO, READ, struct_meteor_video_sz); +  _(METEORGVIDEO, WRITE, struct_meteor_video_sz); +  _(METEORSBRIG, READ, sizeof(unsigned char)); +  _(METEORGBRIG, WRITE, sizeof(unsigned char)); +  _(METEORSCSAT, READ, sizeof(unsigned char)); +  _(METEORGCSAT, WRITE, sizeof(unsigned char)); +  _(METEORSCONT, READ, sizeof(unsigned char)); +  _(METEORGCONT, WRITE, sizeof(unsigned char)); +  _(METEORSHWS, READ, sizeof(unsigned char)); +  _(METEORGHWS, WRITE, sizeof(unsigned char)); +  _(METEORSVWS, READ, sizeof(unsigned char)); +  _(METEORGVWS, WRITE, sizeof(unsigned char)); +  _(METEORSTS, READ, sizeof(unsigned char)); +  _(METEORGTS, WRITE, sizeof(unsigned char)); +  _(TVTUNER_SETCHNL, READ, sizeof(unsigned int)); +  _(TVTUNER_GETCHNL, WRITE, sizeof(unsigned int)); +  _(TVTUNER_SETTYPE, READ, sizeof(unsigned int)); +  _(TVTUNER_GETTYPE, WRITE, sizeof(unsigned int)); +  _(TVTUNER_GETSTATUS, WRITE, sizeof(unsigned int)); +  _(TVTUNER_SETFREQ, READ, sizeof(unsigned int)); +  _(TVTUNER_GETFREQ, WRITE, sizeof(unsigned int)); +  _(TVTUNER_SETAFC, READ, sizeof(int)); +  _(TVTUNER_GETAFC, WRITE, sizeof(int)); +  _(RADIO_SETMODE, READ, sizeof(unsigned int)); +  _(RADIO_GETMODE, WRITE, sizeof(unsigned char)); +  _(RADIO_SETFREQ, READ, sizeof(unsigned int)); +  _(RADIO_GETFREQ, WRITE, sizeof(unsigned int)); +  _(METEORSACTPIXFMT, READ, sizeof(int)); +  _(METEORGACTPIXFMT, WRITE, sizeof(int)); +  _(METEORGSUPPIXFMT, READWRITE, struct_meteor_pixfmt_sz); +  _(TVTUNER_GETCHNLSET, READWRITE, struct_bktr_chnlset_sz); +  _(REMOTE_GETKEY, WRITE, struct_bktr_remote_sz); +  /* Entries from file: dev/ic/icp_ioctl.h */ +  _(GDT_IOCTL_GENERAL, READWRITE, struct_gdt_ucmd_sz); +  _(GDT_IOCTL_DRVERS, WRITE, sizeof(int)); +  _(GDT_IOCTL_CTRTYPE, READWRITE, struct_gdt_ctrt_sz); +  _(GDT_IOCTL_OSVERS, WRITE, struct_gdt_osv_sz); +  _(GDT_IOCTL_CTRCNT, WRITE, sizeof(int)); +  _(GDT_IOCTL_EVENT, READWRITE, struct_gdt_event_sz); +  _(GDT_IOCTL_STATIST, WRITE, struct_gdt_statist_sz); +  _(GDT_IOCTL_RESCAN, READWRITE, struct_gdt_rescan_sz); +  /* Entries from file: dev/ic/isp_ioctl.h */ +  _(ISP_SDBLEV, READWRITE, sizeof(int)); +  _(ISP_RESETHBA, NONE, 0); +  _(ISP_RESCAN, NONE, 0); +  _(ISP_SETROLE, READWRITE, sizeof(int)); +  _(ISP_GETROLE, WRITE, sizeof(int)); +  _(ISP_GET_STATS, WRITE, struct_isp_stats_sz); +  _(ISP_CLR_STATS, NONE, 0); +  _(ISP_FC_LIP, NONE, 0); +  _(ISP_FC_GETDINFO, READWRITE, struct_isp_fc_device_sz); +  _(ISP_GET_FW_CRASH_DUMP, NONE, 0); +  _(ISP_FORCE_CRASH_DUMP, NONE, 0); +  _(ISP_FC_GETHINFO, READWRITE, struct_isp_hba_device_sz); +  _(ISP_TSK_MGMT, READWRITE, struct_isp_fc_tsk_mgmt_sz); +  _(ISP_FC_GETDLIST, NONE, 0); +  /* Entries from file: dev/ic/mlxio.h */ +  _(MLXD_STATUS, WRITE, sizeof(int)); +  _(MLXD_CHECKASYNC, WRITE, sizeof(int)); +  _(MLXD_DETACH, READ, sizeof(int)); +  _(MLX_RESCAN_DRIVES, NONE, 0); +  _(MLX_PAUSE_CHANNEL, READ, struct_mlx_pause_sz); +  _(MLX_COMMAND, READWRITE, struct_mlx_usercommand_sz); +  _(MLX_REBUILDASYNC, READWRITE, struct_mlx_rebuild_request_sz); +  _(MLX_REBUILDSTAT, WRITE, struct_mlx_rebuild_status_sz); +  _(MLX_GET_SYSDRIVE, READWRITE, sizeof(int)); +  _(MLX_GET_CINFO, WRITE, struct_mlx_cinfo_sz); +  /* Entries from file: dev/ic/nvmeio.h */ +  _(NVME_PASSTHROUGH_CMD, READWRITE, struct_nvme_pt_command_sz); +  /* Entries from file: dev/ir/irdaio.h */ +  _(IRDA_RESET_PARAMS, NONE, 0); +  _(IRDA_SET_PARAMS, READ, struct_irda_params_sz); +  _(IRDA_GET_SPEEDMASK, WRITE, sizeof(unsigned int)); +  _(IRDA_GET_TURNAROUNDMASK, WRITE, sizeof(unsigned int)); +  _(IRFRAMETTY_GET_DEVICE, WRITE, sizeof(unsigned int)); +  _(IRFRAMETTY_GET_DONGLE, WRITE, sizeof(unsigned int)); +  _(IRFRAMETTY_SET_DONGLE, READ, sizeof(unsigned int)); +  /* Entries from file: dev/isa/satlinkio.h */ +  _(SATIORESET, NONE, 0); +  _(SATIOGID, WRITE, struct_satlink_id_sz); +  /* Entries from file: dev/isa/isvio.h */ +  _(ISV_CMD, READWRITE, struct_isv_cmd_sz); +  /* Entries from file: dev/isa/wtreg.h */ +  _(WTQICMD, NONE, 0); +  /* Entries from file: dev/iscsi/iscsi_ioctl.h */ +  _(ISCSI_GET_VERSION, READWRITE, struct_iscsi_get_version_parameters_sz); +  _(ISCSI_LOGIN, READWRITE, struct_iscsi_login_parameters_sz); +  _(ISCSI_LOGOUT, READWRITE, struct_iscsi_logout_parameters_sz); +  _(ISCSI_ADD_CONNECTION, READWRITE, struct_iscsi_login_parameters_sz); +  _(ISCSI_RESTORE_CONNECTION, READWRITE, struct_iscsi_login_parameters_sz); +  _(ISCSI_REMOVE_CONNECTION, READWRITE, struct_iscsi_remove_parameters_sz); +  _(ISCSI_CONNECTION_STATUS, READWRITE, struct_iscsi_conn_status_parameters_sz); +  _(ISCSI_SEND_TARGETS, READWRITE, struct_iscsi_send_targets_parameters_sz); +  _(ISCSI_SET_NODE_NAME, READWRITE, struct_iscsi_set_node_name_parameters_sz); +  _(ISCSI_IO_COMMAND, READWRITE, struct_iscsi_iocommand_parameters_sz); +  _(ISCSI_REGISTER_EVENT, READWRITE, struct_iscsi_register_event_parameters_sz); +  _(ISCSI_DEREGISTER_EVENT, READWRITE, +    struct_iscsi_register_event_parameters_sz); +  _(ISCSI_WAIT_EVENT, READWRITE, struct_iscsi_wait_event_parameters_sz); +  _(ISCSI_POLL_EVENT, READWRITE, struct_iscsi_wait_event_parameters_sz); +  /* Entries from file: dev/ofw/openfirmio.h */ +  _(OFIOCGET, READWRITE, struct_ofiocdesc_sz); +  _(OFIOCSET, READ, struct_ofiocdesc_sz); +  _(OFIOCNEXTPROP, READWRITE, struct_ofiocdesc_sz); +  _(OFIOCGETOPTNODE, WRITE, sizeof(int)); +  _(OFIOCGETNEXT, READWRITE, sizeof(int)); +  _(OFIOCGETCHILD, READWRITE, sizeof(int)); +  _(OFIOCFINDDEVICE, READWRITE, struct_ofiocdesc_sz); +  /* Entries from file: dev/pci/amrio.h */ +  _(AMR_IO_VERSION, WRITE, sizeof(int)); +  _(AMR_IO_COMMAND, READWRITE, struct_amr_user_ioctl_sz); +  /* Entries from file: dev/pci/mlyio.h */ +  _(MLYIO_COMMAND, READWRITE, struct_mly_user_command_sz); +  _(MLYIO_HEALTH, READ, struct_mly_user_health_sz); +  /* Entries from file: dev/pci/pciio.h */ +  _(PCI_IOC_CFGREAD, READWRITE, struct_pciio_cfgreg_sz); +  _(PCI_IOC_CFGWRITE, READ, struct_pciio_cfgreg_sz); +  _(PCI_IOC_BDF_CFGREAD, READWRITE, struct_pciio_bdf_cfgreg_sz); +  _(PCI_IOC_BDF_CFGWRITE, READ, struct_pciio_bdf_cfgreg_sz); +  _(PCI_IOC_BUSINFO, WRITE, struct_pciio_businfo_sz); +  _(PCI_IOC_DRVNAME, READWRITE, struct_pciio_drvname_sz); +  _(PCI_IOC_DRVNAMEONBUS, READWRITE, struct_pciio_drvnameonbus_sz); +  /* Entries from file: dev/pci/tweio.h */ +  _(TWEIO_COMMAND, READWRITE, struct_twe_usercommand_sz); +  _(TWEIO_STATS, READWRITE, union_twe_statrequest_sz); +  _(TWEIO_AEN_POLL, WRITE, sizeof(int)); +  _(TWEIO_AEN_WAIT, WRITE, sizeof(int)); +  _(TWEIO_SET_PARAM, READ, struct_twe_paramcommand_sz); +  _(TWEIO_GET_PARAM, READ, struct_twe_paramcommand_sz); +  _(TWEIO_RESET, NONE, 0); +  _(TWEIO_ADD_UNIT, READ, struct_twe_drivecommand_sz); +  _(TWEIO_DEL_UNIT, READ, struct_twe_drivecommand_sz); +  /* Entries from file: dev/pcmcia/if_cnwioctl.h */ +  _(SIOCSCNWDOMAIN, READ, struct_ifreq_sz); +  _(SIOCGCNWDOMAIN, READWRITE, struct_ifreq_sz); +  _(SIOCSCNWKEY, READWRITE, struct_ifreq_sz); +  _(SIOCGCNWSTATUS, READWRITE, struct_cnwstatus_sz); +  _(SIOCGCNWSTATS, READWRITE, struct_cnwistats_sz); +  _(SIOCGCNWTRAIL, READWRITE, struct_cnwitrail_sz); +  /* Entries from file: dev/pcmcia/if_rayreg.h */ +  _(SIOCGRAYSIGLEV, READWRITE, struct_ifreq_sz); +  /* Entries from file: dev/raidframe/raidframeio.h */ +  _(RAIDFRAME_SHUTDOWN, NONE, 0); +  _(RAIDFRAME_TUR, READ, sizeof(u64)); +  _(RAIDFRAME_FAIL_DISK, READ, struct_rf_recon_req_sz); +  _(RAIDFRAME_CHECK_RECON_STATUS, READWRITE, sizeof(int)); +  _(RAIDFRAME_REWRITEPARITY, NONE, 0); +  _(RAIDFRAME_COPYBACK, NONE, 0); +  _(RAIDFRAME_SPARET_WAIT, WRITE, struct_RF_SparetWait_sz); +  _(RAIDFRAME_SEND_SPARET, READ, sizeof(uptr)); +  _(RAIDFRAME_ABORT_SPARET_WAIT, NONE, 0); +  _(RAIDFRAME_START_ATRACE, NONE, 0); +  _(RAIDFRAME_STOP_ATRACE, NONE, 0); +  _(RAIDFRAME_GET_SIZE, WRITE, sizeof(int)); +  _(RAIDFRAME_RESET_ACCTOTALS, NONE, 0); +  _(RAIDFRAME_KEEP_ACCTOTALS, READ, sizeof(int)); +  _(RAIDFRAME_GET_COMPONENT_LABEL, READWRITE, struct_RF_ComponentLabel_sz); +  _(RAIDFRAME_SET_COMPONENT_LABEL, READ, struct_RF_ComponentLabel_sz); +  _(RAIDFRAME_INIT_LABELS, READ, struct_RF_ComponentLabel_sz); +  _(RAIDFRAME_ADD_HOT_SPARE, READ, struct_RF_SingleComponent_sz); +  _(RAIDFRAME_REMOVE_HOT_SPARE, READ, struct_RF_SingleComponent_sz); +  _(RAIDFRAME_REBUILD_IN_PLACE, READ, struct_RF_SingleComponent_sz); +  _(RAIDFRAME_CHECK_PARITY, READWRITE, sizeof(int)); +  _(RAIDFRAME_CHECK_PARITYREWRITE_STATUS, READWRITE, sizeof(int)); +  _(RAIDFRAME_CHECK_COPYBACK_STATUS, READWRITE, sizeof(int)); +  _(RAIDFRAME_SET_AUTOCONFIG, READWRITE, sizeof(int)); +  _(RAIDFRAME_SET_ROOT, READWRITE, sizeof(int)); +  _(RAIDFRAME_DELETE_COMPONENT, READ, struct_RF_SingleComponent_sz); +  _(RAIDFRAME_INCORPORATE_HOT_SPARE, READ, struct_RF_SingleComponent_sz); +  _(RAIDFRAME_CHECK_RECON_STATUS_EXT, READWRITE, struct_RF_ProgressInfo_sz); +  _(RAIDFRAME_CHECK_PARITYREWRITE_STATUS_EXT, READWRITE, +    struct_RF_ProgressInfo_sz); +  _(RAIDFRAME_CHECK_COPYBACK_STATUS_EXT, READWRITE, struct_RF_ProgressInfo_sz); +  _(RAIDFRAME_PARITYMAP_STATUS, WRITE, struct_rf_pmstat_sz); +  _(RAIDFRAME_PARITYMAP_GET_DISABLE, WRITE, sizeof(int)); +  _(RAIDFRAME_PARITYMAP_SET_DISABLE, READ, sizeof(int)); +  _(RAIDFRAME_PARITYMAP_SET_PARAMS, READ, struct_rf_pmparams_sz); +  _(RAIDFRAME_SET_LAST_UNIT, READ, sizeof(int)); +  _(RAIDFRAME_GET_INFO, READWRITE, sizeof(uptr)); +  _(RAIDFRAME_CONFIGURE, READ, sizeof(uptr)); +  /* Entries from file: dev/sbus/mbppio.h */ +  _(MBPPIOCSPARAM, READ, struct_mbpp_param_sz); +  _(MBPPIOCGPARAM, WRITE, struct_mbpp_param_sz); +  _(MBPPIOCGSTAT, WRITE, sizeof(int)); +  /* Entries from file: dev/scsipi/ses.h */ +  _(SESIOC_GETNOBJ, NONE, 0); +  _(SESIOC_GETOBJMAP, NONE, 0); +  _(SESIOC_GETENCSTAT, NONE, 0); +  _(SESIOC_SETENCSTAT, NONE, 0); +  _(SESIOC_GETOBJSTAT, NONE, 0); +  _(SESIOC_SETOBJSTAT, NONE, 0); +  _(SESIOC_GETTEXT, NONE, 0); +  _(SESIOC_INIT, NONE, 0); +  /* Entries from file: dev/sun/disklabel.h */ +  _(SUN_DKIOCGGEOM, WRITE, struct_sun_dkgeom_sz); +  _(SUN_DKIOCINFO, WRITE, struct_sun_dkctlr_sz); +  _(SUN_DKIOCGPART, WRITE, struct_sun_dkpart_sz); +  /* Entries from file: dev/sun/fbio.h */ +  _(FBIOGTYPE, WRITE, struct_fbtype_sz); +  _(FBIOPUTCMAP, READ, struct_fbcmap_sz); +  _(FBIOGETCMAP, READ, struct_fbcmap_sz); +  _(FBIOGATTR, WRITE, struct_fbgattr_sz); +  _(FBIOSVIDEO, READ, sizeof(int)); +  _(FBIOGVIDEO, WRITE, sizeof(int)); +  _(FBIOSCURSOR, READ, struct_fbcursor_sz); +  _(FBIOGCURSOR, READWRITE, struct_fbcursor_sz); +  _(FBIOSCURPOS, READ, struct_fbcurpos_sz); +  _(FBIOGCURPOS, READ, struct_fbcurpos_sz); +  _(FBIOGCURMAX, WRITE, struct_fbcurpos_sz); +  /* Entries from file: dev/sun/kbio.h */ +  _(KIOCTRANS, READ, sizeof(int)); +  _(KIOCSETKEY, READWRITE, struct_okiockey_sz); +  _(KIOCGETKEY, READWRITE, struct_okiockey_sz); +  _(KIOCGTRANS, WRITE, sizeof(int)); +  _(KIOCCMD, READ, sizeof(int)); +  _(KIOCTYPE, WRITE, sizeof(int)); +  _(KIOCSDIRECT, READ, sizeof(int)); +  _(KIOCSKEY, READ, struct_kiockeymap_sz); +  _(KIOCGKEY, READWRITE, struct_kiockeymap_sz); +  _(KIOCSLED, READ, sizeof(char)); +  _(KIOCGLED, WRITE, sizeof(char)); +  _(KIOCLAYOUT, WRITE, sizeof(int)); +  /* Entries from file: dev/sun/vuid_event.h */ +  _(VUIDSFORMAT, READ, sizeof(int)); +  _(VUIDGFORMAT, WRITE, sizeof(int)); +  /* Entries from file: dev/tc/sticio.h */ +  _(STICIO_GXINFO, WRITE, struct_stic_xinfo_sz); +  _(STICIO_RESET, NONE, 0); +  _(STICIO_STARTQ, NONE, 0); +  _(STICIO_STOPQ, NONE, 0); +  /* Entries from file: dev/usb/ukyopon.h */ +  _(UKYOPON_IDENTIFY, WRITE, struct_ukyopon_identify_sz); +  /* Entries from file: dev/usb/urio.h */ +  _(URIO_SEND_COMMAND, READWRITE, struct_urio_command_sz); +  _(URIO_RECV_COMMAND, READWRITE, struct_urio_command_sz); +  /* Entries from file: dev/usb/usb.h */ +  _(USB_REQUEST, READWRITE, struct_usb_ctl_request_sz); +  _(USB_SETDEBUG, READ, sizeof(int)); +  _(USB_DISCOVER, NONE, 0); +  _(USB_DEVICEINFO, READWRITE, struct_usb_device_info_sz); +  _(USB_DEVICEINFO_OLD, READWRITE, struct_usb_device_info_old_sz); +  _(USB_DEVICESTATS, WRITE, struct_usb_device_stats_sz); +  _(USB_GET_REPORT_DESC, WRITE, struct_usb_ctl_report_desc_sz); +  _(USB_SET_IMMED, READ, sizeof(int)); +  _(USB_GET_REPORT, READWRITE, struct_usb_ctl_report_sz); +  _(USB_SET_REPORT, READ, struct_usb_ctl_report_sz); +  _(USB_GET_REPORT_ID, WRITE, sizeof(int)); +  _(USB_GET_CONFIG, WRITE, sizeof(int)); +  _(USB_SET_CONFIG, READ, sizeof(int)); +  _(USB_GET_ALTINTERFACE, READWRITE, struct_usb_alt_interface_sz); +  _(USB_SET_ALTINTERFACE, READWRITE, struct_usb_alt_interface_sz); +  _(USB_GET_NO_ALT, READWRITE, struct_usb_alt_interface_sz); +  _(USB_GET_DEVICE_DESC, WRITE, struct_usb_device_descriptor_sz); +  _(USB_GET_CONFIG_DESC, READWRITE, struct_usb_config_desc_sz); +  _(USB_GET_INTERFACE_DESC, READWRITE, struct_usb_interface_desc_sz); +  _(USB_GET_ENDPOINT_DESC, READWRITE, struct_usb_endpoint_desc_sz); +  _(USB_GET_FULL_DESC, READWRITE, struct_usb_full_desc_sz); +  _(USB_GET_STRING_DESC, READWRITE, struct_usb_string_desc_sz); +  _(USB_DO_REQUEST, READWRITE, struct_usb_ctl_request_sz); +  _(USB_GET_DEVICEINFO, WRITE, struct_usb_device_info_sz); +  _(USB_GET_DEVICEINFO_OLD, WRITE, struct_usb_device_info_old_sz); +  _(USB_SET_SHORT_XFER, READ, sizeof(int)); +  _(USB_SET_TIMEOUT, READ, sizeof(int)); +  _(USB_SET_BULK_RA, READ, sizeof(int)); +  _(USB_SET_BULK_WB, READ, sizeof(int)); +  _(USB_SET_BULK_RA_OPT, READ, struct_usb_bulk_ra_wb_opt_sz); +  _(USB_SET_BULK_WB_OPT, READ, struct_usb_bulk_ra_wb_opt_sz); +  _(USB_GET_CM_OVER_DATA, WRITE, sizeof(int)); +  _(USB_SET_CM_OVER_DATA, READ, sizeof(int)); +  /* Entries from file: dev/usb/utoppy.h */ +  _(UTOPPYIOTURBO, READ, sizeof(int)); +  _(UTOPPYIOREBOOT, NONE, 0); +  _(UTOPPYIOSTATS, WRITE, struct_utoppy_stats_sz); +  _(UTOPPYIORENAME, READ, struct_utoppy_rename_sz); +  _(UTOPPYIOMKDIR, READ, sizeof(uptr)); +  _(UTOPPYIODELETE, READ, sizeof(uptr)); +  _(UTOPPYIOREADDIR, READ, sizeof(uptr)); +  _(UTOPPYIOREADFILE, READ, struct_utoppy_readfile_sz); +  _(UTOPPYIOWRITEFILE, READ, struct_utoppy_writefile_sz); +  /* Entries from file: dev/vme/xio.h */ +  _(DIOSXDCMD, READWRITE, struct_xd_iocmd_sz); +  /* Entries from file: dev/wscons/wsdisplay_usl_io.h */ +  _(VT_OPENQRY, WRITE, sizeof(int)); +  _(VT_SETMODE, READ, struct_vt_mode_sz); +  _(VT_GETMODE, WRITE, struct_vt_mode_sz); +  _(VT_RELDISP, NONE, 0); +  _(VT_ACTIVATE, NONE, 0); +  _(VT_WAITACTIVE, NONE, 0); +  _(VT_GETACTIVE, WRITE, sizeof(int)); +  _(VT_GETSTATE, WRITE, struct_vt_stat_sz); +  _(KDGETKBENT, READWRITE, struct_kbentry_sz); +  _(KDGKBMODE, WRITE, sizeof(int)); +  _(KDSKBMODE, NONE, 0); +  _(KDMKTONE, NONE, 0); +  _(KDSETMODE, NONE, 0); +  _(KDENABIO, NONE, 0); +  _(KDDISABIO, NONE, 0); +  _(KDGKBTYPE, WRITE, sizeof(char)); +  _(KDGETLED, WRITE, sizeof(int)); +  _(KDSETLED, NONE, 0); +  _(KDSETRAD, NONE, 0); +  _(VGAPCVTID, READWRITE, struct_pcvtid_sz); +  _(CONS_GETVERS, WRITE, sizeof(int)); +  /* Entries from file: dev/wscons/wsconsio.h */ +  _(WSKBDIO_GTYPE, WRITE, sizeof(unsigned int)); +  _(WSKBDIO_BELL, NONE, 0); +  _(WSKBDIO_COMPLEXBELL, READ, struct_wskbd_bell_data_sz); +  _(WSKBDIO_SETBELL, READ, struct_wskbd_bell_data_sz); +  _(WSKBDIO_GETBELL, WRITE, struct_wskbd_bell_data_sz); +  _(WSKBDIO_SETDEFAULTBELL, READ, struct_wskbd_bell_data_sz); +  _(WSKBDIO_GETDEFAULTBELL, WRITE, struct_wskbd_bell_data_sz); +  _(WSKBDIO_SETKEYREPEAT, READ, struct_wskbd_keyrepeat_data_sz); +  _(WSKBDIO_GETKEYREPEAT, WRITE, struct_wskbd_keyrepeat_data_sz); +  _(WSKBDIO_SETDEFAULTKEYREPEAT, READ, struct_wskbd_keyrepeat_data_sz); +  _(WSKBDIO_GETDEFAULTKEYREPEAT, WRITE, struct_wskbd_keyrepeat_data_sz); +  _(WSKBDIO_SETLEDS, READ, sizeof(int)); +  _(WSKBDIO_GETLEDS, WRITE, sizeof(int)); +  _(WSKBDIO_GETMAP, READWRITE, struct_wskbd_map_data_sz); +  _(WSKBDIO_SETMAP, READ, struct_wskbd_map_data_sz); +  _(WSKBDIO_GETENCODING, WRITE, sizeof(int)); +  _(WSKBDIO_SETENCODING, READ, sizeof(int)); +  _(WSKBDIO_SETMODE, READ, sizeof(int)); +  _(WSKBDIO_GETMODE, WRITE, sizeof(int)); +  _(WSKBDIO_SETKEYCLICK, READ, sizeof(int)); +  _(WSKBDIO_GETKEYCLICK, WRITE, sizeof(int)); +  _(WSKBDIO_GETSCROLL, WRITE, struct_wskbd_scroll_data_sz); +  _(WSKBDIO_SETSCROLL, READ, struct_wskbd_scroll_data_sz); +  _(WSKBDIO_SETVERSION, READ, sizeof(int)); +  _(WSMOUSEIO_GTYPE, WRITE, sizeof(unsigned int)); +  _(WSMOUSEIO_SRES, READ, sizeof(unsigned int)); +  _(WSMOUSEIO_SSCALE, READ, sizeof(unsigned int)); +  _(WSMOUSEIO_SRATE, READ, sizeof(unsigned int)); +  _(WSMOUSEIO_SCALIBCOORDS, READ, struct_wsmouse_calibcoords_sz); +  _(WSMOUSEIO_GCALIBCOORDS, WRITE, struct_wsmouse_calibcoords_sz); +  _(WSMOUSEIO_GETID, READWRITE, struct_wsmouse_id_sz); +  _(WSMOUSEIO_GETREPEAT, WRITE, struct_wsmouse_repeat_sz); +  _(WSMOUSEIO_SETREPEAT, READ, struct_wsmouse_repeat_sz); +  _(WSMOUSEIO_SETVERSION, READ, sizeof(int)); +  _(WSDISPLAYIO_GTYPE, WRITE, sizeof(unsigned int)); +  _(WSDISPLAYIO_GINFO, WRITE, struct_wsdisplay_fbinfo_sz); +  _(WSDISPLAYIO_GETCMAP, READ, struct_wsdisplay_cmap_sz); +  _(WSDISPLAYIO_PUTCMAP, READ, struct_wsdisplay_cmap_sz); +  _(WSDISPLAYIO_GVIDEO, WRITE, sizeof(unsigned int)); +  _(WSDISPLAYIO_SVIDEO, READ, sizeof(unsigned int)); +  _(WSDISPLAYIO_GCURPOS, WRITE, struct_wsdisplay_curpos_sz); +  _(WSDISPLAYIO_SCURPOS, READ, struct_wsdisplay_curpos_sz); +  _(WSDISPLAYIO_GCURMAX, WRITE, struct_wsdisplay_curpos_sz); +  _(WSDISPLAYIO_GCURSOR, READWRITE, struct_wsdisplay_cursor_sz); +  _(WSDISPLAYIO_SCURSOR, READ, struct_wsdisplay_cursor_sz); +  _(WSDISPLAYIO_GMODE, WRITE, sizeof(unsigned int)); +  _(WSDISPLAYIO_SMODE, READ, sizeof(unsigned int)); +  _(WSDISPLAYIO_LDFONT, READ, struct_wsdisplay_font_sz); +  _(WSDISPLAYIO_ADDSCREEN, READ, struct_wsdisplay_addscreendata_sz); +  _(WSDISPLAYIO_DELSCREEN, READ, struct_wsdisplay_delscreendata_sz); +  _(WSDISPLAYIO_SFONT, READ, struct_wsdisplay_usefontdata_sz); +  _(_O_WSDISPLAYIO_SETKEYBOARD, READWRITE, struct_wsdisplay_kbddata_sz); +  _(WSDISPLAYIO_GETPARAM, READWRITE, struct_wsdisplay_param_sz); +  _(WSDISPLAYIO_SETPARAM, READWRITE, struct_wsdisplay_param_sz); +  _(WSDISPLAYIO_GETACTIVESCREEN, WRITE, sizeof(int)); +  _(WSDISPLAYIO_GETWSCHAR, READWRITE, struct_wsdisplay_char_sz); +  _(WSDISPLAYIO_PUTWSCHAR, READWRITE, struct_wsdisplay_char_sz); +  _(WSDISPLAYIO_DGSCROLL, WRITE, struct_wsdisplay_scroll_data_sz); +  _(WSDISPLAYIO_DSSCROLL, READ, struct_wsdisplay_scroll_data_sz); +  _(WSDISPLAYIO_GMSGATTRS, WRITE, struct_wsdisplay_msgattrs_sz); +  _(WSDISPLAYIO_SMSGATTRS, READ, struct_wsdisplay_msgattrs_sz); +  _(WSDISPLAYIO_GBORDER, WRITE, sizeof(int)); +  _(WSDISPLAYIO_SBORDER, READ, sizeof(int)); +  _(WSDISPLAYIO_SSPLASH, READ, sizeof(int)); +  _(WSDISPLAYIO_SPROGRESS, READ, sizeof(int)); +  _(WSDISPLAYIO_LINEBYTES, WRITE, sizeof(unsigned int)); +  _(WSDISPLAYIO_SETVERSION, READ, sizeof(int)); +  _(WSMUXIO_ADD_DEVICE, READ, struct_wsmux_device_sz); +  _(WSMUXIO_REMOVE_DEVICE, READ, struct_wsmux_device_sz); +  _(WSMUXIO_LIST_DEVICES, READWRITE, struct_wsmux_device_list_sz); +  _(WSMUXIO_INJECTEVENT, READ, struct_wscons_event_sz); +  _(WSDISPLAYIO_GET_BUSID, WRITE, struct_wsdisplayio_bus_id_sz); +  _(WSDISPLAYIO_GET_EDID, READWRITE, struct_wsdisplayio_edid_info_sz); +  _(WSDISPLAYIO_SET_POLLING, READ, sizeof(int)); +  _(WSDISPLAYIO_GET_FBINFO, READWRITE, struct_wsdisplayio_fbinfo_sz); +  _(WSDISPLAYIO_DOBLIT, READWRITE, struct_wsdisplayio_blit_sz); +  _(WSDISPLAYIO_WAITBLIT, READWRITE, struct_wsdisplayio_blit_sz); +  /* Entries from file: dev/biovar.h */ +  _(BIOCLOCATE, READWRITE, struct_bio_locate_sz); +  _(BIOCINQ, READWRITE, struct_bioc_inq_sz); +  _(BIOCDISK_NOVOL, READWRITE, struct_bioc_disk_sz); +  _(BIOCDISK, READWRITE, struct_bioc_disk_sz); +  _(BIOCVOL, READWRITE, struct_bioc_vol_sz); +  _(BIOCALARM, READWRITE, struct_bioc_alarm_sz); +  _(BIOCBLINK, READWRITE, struct_bioc_blink_sz); +  _(BIOCSETSTATE, READWRITE, struct_bioc_setstate_sz); +  _(BIOCVOLOPS, READWRITE, struct_bioc_volops_sz); +  /* Entries from file: dev/md.h */ +  _(MD_GETCONF, WRITE, struct_md_conf_sz); +  _(MD_SETCONF, READ, struct_md_conf_sz); +  /* Entries from file: dev/ccdvar.h */ +  _(CCDIOCSET, READWRITE, struct_ccd_ioctl_sz); +  _(CCDIOCCLR, READ, struct_ccd_ioctl_sz); +  /* Entries from file: dev/cgdvar.h */ +  _(CGDIOCSET, READWRITE, struct_cgd_ioctl_sz); +  _(CGDIOCCLR, READ, struct_cgd_ioctl_sz); +  _(CGDIOCGET, READWRITE, struct_cgd_user_sz); +  /* Entries from file: dev/fssvar.h */ +  _(FSSIOCSET, READ, struct_fss_set_sz); +  _(FSSIOCGET, WRITE, struct_fss_get_sz); +  _(FSSIOCCLR, NONE, 0); +  _(FSSIOFSET, READ, sizeof(int)); +  _(FSSIOFGET, WRITE, sizeof(int)); +  /* Entries from file: dev/bluetooth/btdev.h */ +  _(BTDEV_ATTACH, READ, struct_plistref_sz); +  _(BTDEV_DETACH, READ, struct_plistref_sz); +  /* Entries from file: dev/bluetooth/btsco.h */ +  _(BTSCO_GETINFO, WRITE, struct_btsco_info_sz); +  /* Entries from file: dev/kttcpio.h */ +  _(KTTCP_IO_SEND, READWRITE, struct_kttcp_io_args_sz); +  _(KTTCP_IO_RECV, READWRITE, struct_kttcp_io_args_sz); +  /* Entries from file: dev/lockstat.h */ +  _(IOC_LOCKSTAT_GVERSION, WRITE, sizeof(int)); +  _(IOC_LOCKSTAT_ENABLE, READ, struct_lsenable_sz); +  _(IOC_LOCKSTAT_DISABLE, WRITE, struct_lsdisable_sz); +  /* Entries from file: dev/vndvar.h */ +  _(VNDIOCSET, READWRITE, struct_vnd_ioctl_sz); +  _(VNDIOCCLR, READ, struct_vnd_ioctl_sz); +  _(VNDIOCGET, READWRITE, struct_vnd_user_sz); +  /* Entries from file: dev/spkrio.h */ +  _(SPKRTONE, READ, struct_tone_sz); +  _(SPKRTUNE, NONE, 0); +  _(SPKRGETVOL, WRITE, sizeof(unsigned int)); +  _(SPKRSETVOL, READ, sizeof(unsigned int)); +  /* Entries from file: net/bpf.h */ +  _(BIOCGBLEN, WRITE, sizeof(unsigned int)); +  _(BIOCSBLEN, READWRITE, sizeof(unsigned int)); +  _(BIOCSETF, READ, struct_bpf_program_sz); +  _(BIOCFLUSH, NONE, 0); +  _(BIOCPROMISC, NONE, 0); +  _(BIOCGDLT, WRITE, sizeof(unsigned int)); +  _(BIOCGETIF, WRITE, struct_ifreq_sz); +  _(BIOCSETIF, READ, struct_ifreq_sz); +  _(BIOCGSTATS, WRITE, struct_bpf_stat_sz); +  _(BIOCGSTATSOLD, WRITE, struct_bpf_stat_old_sz); +  _(BIOCIMMEDIATE, READ, sizeof(unsigned int)); +  _(BIOCVERSION, WRITE, struct_bpf_version_sz); +  _(BIOCSTCPF, READ, struct_bpf_program_sz); +  _(BIOCSUDPF, READ, struct_bpf_program_sz); +  _(BIOCGHDRCMPLT, WRITE, sizeof(unsigned int)); +  _(BIOCSHDRCMPLT, READ, sizeof(unsigned int)); +  _(BIOCSDLT, READ, sizeof(unsigned int)); +  _(BIOCGDLTLIST, READWRITE, struct_bpf_dltlist_sz); +  _(BIOCGSEESENT, WRITE, sizeof(unsigned int)); +  _(BIOCSSEESENT, READ, sizeof(unsigned int)); +  _(BIOCSRTIMEOUT, READ, struct_timeval_sz); +  _(BIOCGRTIMEOUT, WRITE, struct_timeval_sz); +  _(BIOCGFEEDBACK, WRITE, sizeof(unsigned int)); +  _(BIOCSFEEDBACK, READ, sizeof(unsigned int)); +  /* Entries from file: net/if_atm.h */ +  _(SIOCRAWATM, READWRITE, sizeof(int)); +  _(SIOCATMENA, READWRITE, struct_atm_pseudoioctl_sz); +  _(SIOCATMDIS, READWRITE, struct_atm_pseudoioctl_sz); +  _(SIOCSPVCTX, READWRITE, struct_pvctxreq_sz); +  _(SIOCGPVCTX, READWRITE, struct_pvctxreq_sz); +  _(SIOCSPVCSIF, READWRITE, struct_ifreq_sz); +  _(SIOCGPVCSIF, READWRITE, struct_ifreq_sz); +  /* Entries from file: net/if_gre.h */ +  _(GRESADDRS, READ, struct_ifreq_sz); +  _(GRESADDRD, READ, struct_ifreq_sz); +  _(GREGADDRS, READWRITE, struct_ifreq_sz); +  _(GREGADDRD, READWRITE, struct_ifreq_sz); +  _(GRESPROTO, READ, struct_ifreq_sz); +  _(GREGPROTO, READWRITE, struct_ifreq_sz); +  _(GRESSOCK, READ, struct_ifreq_sz); +  _(GREDSOCK, READ, struct_ifreq_sz); +  /* Entries from file: net/if_ppp.h */ +  _(PPPIOCGRAWIN, WRITE, struct_ppp_rawin_sz); +  _(PPPIOCGFLAGS, WRITE, sizeof(int)); +  _(PPPIOCSFLAGS, READ, sizeof(int)); +  _(PPPIOCGASYNCMAP, WRITE, sizeof(int)); +  _(PPPIOCSASYNCMAP, READ, sizeof(int)); +  _(PPPIOCGUNIT, WRITE, sizeof(int)); +  _(PPPIOCGRASYNCMAP, WRITE, sizeof(int)); +  _(PPPIOCSRASYNCMAP, READ, sizeof(int)); +  _(PPPIOCGMRU, WRITE, sizeof(int)); +  _(PPPIOCSMRU, READ, sizeof(int)); +  _(PPPIOCSMAXCID, READ, sizeof(int)); +  _(PPPIOCGXASYNCMAP, WRITE, (8 * sizeof(u32))); +  _(PPPIOCSXASYNCMAP, READ, (8 * sizeof(u32))); +  _(PPPIOCXFERUNIT, NONE, 0); +  _(PPPIOCSCOMPRESS, READ, struct_ppp_option_data_sz); +  _(PPPIOCGNPMODE, READWRITE, struct_npioctl_sz); +  _(PPPIOCSNPMODE, READ, struct_npioctl_sz); +  _(PPPIOCGIDLE, WRITE, struct_ppp_idle_sz); +  _(PPPIOCGMTU, WRITE, sizeof(int)); +  _(PPPIOCSMTU, READ, sizeof(int)); +  _(SIOCGPPPSTATS, READWRITE, struct_ifpppstatsreq_sz); +  _(SIOCGPPPCSTATS, READWRITE, struct_ifpppcstatsreq_sz); +  /* Entries from file: net/npf.h */ +  _(IOC_NPF_VERSION, WRITE, sizeof(int)); +  _(IOC_NPF_SWITCH, READ, sizeof(int)); +  _(IOC_NPF_LOAD, READWRITE, struct_plistref_sz); +  _(IOC_NPF_TABLE, READ, struct_npf_ioctl_table_sz); +  _(IOC_NPF_STATS, READ, sizeof(uptr)); +  _(IOC_NPF_SAVE, WRITE, struct_plistref_sz); +  _(IOC_NPF_RULE, READWRITE, struct_plistref_sz); +  _(IOC_NPF_CONN_LOOKUP, READWRITE, struct_plistref_sz); +  /* Entries from file: net/if_pppoe.h */ +  _(PPPOESETPARMS, READ, struct_pppoediscparms_sz); +  _(PPPOEGETPARMS, READWRITE, struct_pppoediscparms_sz); +  _(PPPOEGETSESSION, READWRITE, struct_pppoeconnectionstate_sz); +  /* Entries from file: net/if_sppp.h */ +  _(SPPPGETAUTHCFG, READWRITE, struct_spppauthcfg_sz); +  _(SPPPSETAUTHCFG, READ, struct_spppauthcfg_sz); +  _(SPPPGETLCPCFG, READWRITE, struct_sppplcpcfg_sz); +  _(SPPPSETLCPCFG, READ, struct_sppplcpcfg_sz); +  _(SPPPGETSTATUS, READWRITE, struct_spppstatus_sz); +  _(SPPPGETSTATUSNCP, READWRITE, struct_spppstatusncp_sz); +  _(SPPPGETIDLETO, READWRITE, struct_spppidletimeout_sz); +  _(SPPPSETIDLETO, READ, struct_spppidletimeout_sz); +  _(SPPPGETAUTHFAILURES, READWRITE, struct_spppauthfailurestats_sz); +  _(SPPPSETAUTHFAILURE, READ, struct_spppauthfailuresettings_sz); +  _(SPPPSETDNSOPTS, READ, struct_spppdnssettings_sz); +  _(SPPPGETDNSOPTS, READWRITE, struct_spppdnssettings_sz); +  _(SPPPGETDNSADDRS, READWRITE, struct_spppdnsaddrs_sz); +  _(SPPPSETKEEPALIVE, READ, struct_spppkeepalivesettings_sz); +  _(SPPPGETKEEPALIVE, READWRITE, struct_spppkeepalivesettings_sz); +  /* Entries from file: net/if_srt.h */ +  _(SRT_GETNRT, WRITE, sizeof(unsigned int)); +  _(SRT_GETRT, READWRITE, struct_srt_rt_sz); +  _(SRT_SETRT, READ, struct_srt_rt_sz); +  _(SRT_DELRT, READ, sizeof(unsigned int)); +  _(SRT_SFLAGS, READ, sizeof(unsigned int)); +  _(SRT_GFLAGS, WRITE, sizeof(unsigned int)); +  _(SRT_SGFLAGS, READWRITE, sizeof(unsigned int)); +  _(SRT_DEBUG, READ, sizeof(uptr)); +  /* Entries from file: net/if_tap.h */ +  _(TAPGIFNAME, WRITE, struct_ifreq_sz); +  /* Entries from file: net/if_tun.h */ +  _(TUNSDEBUG, READ, sizeof(int)); +  _(TUNGDEBUG, WRITE, sizeof(int)); +  _(TUNSIFMODE, READ, sizeof(int)); +  _(TUNSIFHEAD, READ, sizeof(int)); +  _(TUNGIFHEAD, WRITE, sizeof(int)); +  /* Entries from file: net/pfvar.h */ +  _(DIOCSTART, NONE, 0); +  _(DIOCSTOP, NONE, 0); +  _(DIOCADDRULE, READWRITE, struct_pfioc_rule_sz); +  _(DIOCGETRULES, READWRITE, struct_pfioc_rule_sz); +  _(DIOCGETRULE, READWRITE, struct_pfioc_rule_sz); +  _(DIOCSETLCK, READWRITE, sizeof(u32)); +  _(DIOCCLRSTATES, READWRITE, struct_pfioc_state_kill_sz); +  _(DIOCGETSTATE, READWRITE, struct_pfioc_state_sz); +  _(DIOCSETSTATUSIF, READWRITE, struct_pfioc_if_sz); +  _(DIOCGETSTATUS, READWRITE, struct_pf_status_sz); +  _(DIOCCLRSTATUS, NONE, 0); +  _(DIOCNATLOOK, READWRITE, struct_pfioc_natlook_sz); +  _(DIOCSETDEBUG, READWRITE, sizeof(u32)); +  _(DIOCGETSTATES, READWRITE, struct_pfioc_states_sz); +  _(DIOCCHANGERULE, READWRITE, struct_pfioc_rule_sz); +  _(DIOCSETTIMEOUT, READWRITE, struct_pfioc_tm_sz); +  _(DIOCGETTIMEOUT, READWRITE, struct_pfioc_tm_sz); +  _(DIOCADDSTATE, READWRITE, struct_pfioc_state_sz); +  _(DIOCCLRRULECTRS, NONE, 0); +  _(DIOCGETLIMIT, READWRITE, struct_pfioc_limit_sz); +  _(DIOCSETLIMIT, READWRITE, struct_pfioc_limit_sz); +  _(DIOCKILLSTATES, READWRITE, struct_pfioc_state_kill_sz); +  _(DIOCSTARTALTQ, NONE, 0); +  _(DIOCSTOPALTQ, NONE, 0); +  _(DIOCADDALTQ, READWRITE, struct_pfioc_altq_sz); +  _(DIOCGETALTQS, READWRITE, struct_pfioc_altq_sz); +  _(DIOCGETALTQ, READWRITE, struct_pfioc_altq_sz); +  _(DIOCCHANGEALTQ, READWRITE, struct_pfioc_altq_sz); +  _(DIOCGETQSTATS, READWRITE, struct_pfioc_qstats_sz); +  _(DIOCBEGINADDRS, READWRITE, struct_pfioc_pooladdr_sz); +  _(DIOCADDADDR, READWRITE, struct_pfioc_pooladdr_sz); +  _(DIOCGETADDRS, READWRITE, struct_pfioc_pooladdr_sz); +  _(DIOCGETADDR, READWRITE, struct_pfioc_pooladdr_sz); +  _(DIOCCHANGEADDR, READWRITE, struct_pfioc_pooladdr_sz); +  _(DIOCADDSTATES, READWRITE, struct_pfioc_states_sz); +  _(DIOCGETRULESETS, READWRITE, struct_pfioc_ruleset_sz); +  _(DIOCGETRULESET, READWRITE, struct_pfioc_ruleset_sz); +  _(DIOCRCLRTABLES, READWRITE, struct_pfioc_table_sz); +  _(DIOCRADDTABLES, READWRITE, struct_pfioc_table_sz); +  _(DIOCRDELTABLES, READWRITE, struct_pfioc_table_sz); +  _(DIOCRGETTABLES, READWRITE, struct_pfioc_table_sz); +  _(DIOCRGETTSTATS, READWRITE, struct_pfioc_table_sz); +  _(DIOCRCLRTSTATS, READWRITE, struct_pfioc_table_sz); +  _(DIOCRCLRADDRS, READWRITE, struct_pfioc_table_sz); +  _(DIOCRADDADDRS, READWRITE, struct_pfioc_table_sz); +  _(DIOCRDELADDRS, READWRITE, struct_pfioc_table_sz); +  _(DIOCRSETADDRS, READWRITE, struct_pfioc_table_sz); +  _(DIOCRGETADDRS, READWRITE, struct_pfioc_table_sz); +  _(DIOCRGETASTATS, READWRITE, struct_pfioc_table_sz); +  _(DIOCRCLRASTATS, READWRITE, struct_pfioc_table_sz); +  _(DIOCRTSTADDRS, READWRITE, struct_pfioc_table_sz); +  _(DIOCRSETTFLAGS, READWRITE, struct_pfioc_table_sz); +  _(DIOCRINADEFINE, READWRITE, struct_pfioc_table_sz); +  _(DIOCOSFPFLUSH, NONE, 0); +  _(DIOCOSFPADD, READWRITE, struct_pf_osfp_ioctl_sz); +  _(DIOCOSFPGET, READWRITE, struct_pf_osfp_ioctl_sz); +  _(DIOCXBEGIN, READWRITE, struct_pfioc_trans_sz); +  _(DIOCXCOMMIT, READWRITE, struct_pfioc_trans_sz); +  _(DIOCXROLLBACK, READWRITE, struct_pfioc_trans_sz); +  _(DIOCGETSRCNODES, READWRITE, struct_pfioc_src_nodes_sz); +  _(DIOCCLRSRCNODES, NONE, 0); +  _(DIOCSETHOSTID, READWRITE, sizeof(u32)); +  _(DIOCIGETIFACES, READWRITE, struct_pfioc_iface_sz); +  _(DIOCSETIFFLAG, READWRITE, struct_pfioc_iface_sz); +  _(DIOCCLRIFFLAG, READWRITE, struct_pfioc_iface_sz); +  _(DIOCKILLSRCNODES, READWRITE, struct_pfioc_src_node_kill_sz); +  /* Entries from file: netbt/hci.h */ +  _(SIOCGBTINFO, READWRITE, struct_btreq_sz); +  _(SIOCGBTINFOA, READWRITE, struct_btreq_sz); +  _(SIOCNBTINFO, READWRITE, struct_btreq_sz); +  _(SIOCSBTFLAGS, READWRITE, struct_btreq_sz); +  _(SIOCSBTPOLICY, READWRITE, struct_btreq_sz); +  _(SIOCSBTPTYPE, READWRITE, struct_btreq_sz); +  _(SIOCGBTSTATS, READWRITE, struct_btreq_sz); +  _(SIOCZBTSTATS, READWRITE, struct_btreq_sz); +  _(SIOCBTDUMP, READ, struct_btreq_sz); +  _(SIOCSBTSCOMTU, READWRITE, struct_btreq_sz); +  _(SIOCGBTFEAT, READWRITE, struct_btreq_sz); +  /* Entries from file: netinet/ip_nat.h */ +  _(SIOCADNAT, READ, struct_ipfobj_sz); +  _(SIOCRMNAT, READ, struct_ipfobj_sz); +  _(SIOCGNATS, READWRITE, struct_ipfobj_sz); +  _(SIOCGNATL, READWRITE, struct_ipfobj_sz); +  _(SIOCPURGENAT, READWRITE, struct_ipfobj_sz); +  /* Entries from file: netinet6/in6_var.h */ +  _(SIOCSIFINFO_FLAGS, READWRITE, struct_in6_ndireq_sz); +  _(SIOCAADDRCTL_POLICY, READ, struct_in6_addrpolicy_sz); +  _(SIOCDADDRCTL_POLICY, READ, struct_in6_addrpolicy_sz); +  /* Entries from file: netsmb/smb_dev.h */ +  _(SMBIOC_OPENSESSION, READ, struct_smbioc_ossn_sz); +  _(SMBIOC_OPENSHARE, READ, struct_smbioc_oshare_sz); +  _(SMBIOC_REQUEST, READWRITE, struct_smbioc_rq_sz); +  _(SMBIOC_SETFLAGS, READ, struct_smbioc_flags_sz); +  _(SMBIOC_LOOKUP, READ, struct_smbioc_lookup_sz); +  _(SMBIOC_READ, READWRITE, struct_smbioc_rw_sz); +  _(SMBIOC_WRITE, READWRITE, struct_smbioc_rw_sz); +  /* Entries from file: sys/agpio.h */ +  _(AGPIOC_INFO, WRITE, struct__agp_info_sz); +  _(AGPIOC_ACQUIRE, NONE, 0); +  _(AGPIOC_RELEASE, NONE, 0); +  _(AGPIOC_SETUP, READ, struct__agp_setup_sz); +  _(AGPIOC_ALLOCATE, READWRITE, struct__agp_allocate_sz); +  _(AGPIOC_DEALLOCATE, READ, sizeof(int)); +  _(AGPIOC_BIND, READ, struct__agp_bind_sz); +  _(AGPIOC_UNBIND, READ, struct__agp_unbind_sz); +  /* Entries from file: sys/audioio.h */ +  _(AUDIO_GETINFO, WRITE, struct_audio_info_sz); +  _(AUDIO_SETINFO, READWRITE, struct_audio_info_sz); +  _(AUDIO_DRAIN, NONE, 0); +  _(AUDIO_FLUSH, NONE, 0); +  _(AUDIO_WSEEK, WRITE, sizeof(unsigned long)); +  _(AUDIO_RERROR, WRITE, sizeof(int)); +  _(AUDIO_GETDEV, WRITE, struct_audio_device_sz); +  _(AUDIO_GETENC, READWRITE, struct_audio_encoding_sz); +  _(AUDIO_GETFD, WRITE, sizeof(int)); +  _(AUDIO_SETFD, READWRITE, sizeof(int)); +  _(AUDIO_PERROR, WRITE, sizeof(int)); +  _(AUDIO_GETIOFFS, WRITE, struct_audio_offset_sz); +  _(AUDIO_GETOOFFS, WRITE, struct_audio_offset_sz); +  _(AUDIO_GETPROPS, WRITE, sizeof(int)); +  _(AUDIO_GETBUFINFO, WRITE, struct_audio_info_sz); +  _(AUDIO_SETCHAN, READ, sizeof(int)); +  _(AUDIO_GETCHAN, WRITE, sizeof(int)); +  _(AUDIO_MIXER_READ, READWRITE, struct_mixer_ctrl_sz); +  _(AUDIO_MIXER_WRITE, READWRITE, struct_mixer_ctrl_sz); +  _(AUDIO_MIXER_DEVINFO, READWRITE, struct_mixer_devinfo_sz); +  /* Entries from file: sys/ataio.h */ +  _(ATAIOCCOMMAND, READWRITE, struct_atareq_sz); +  _(ATABUSIOSCAN, READ, struct_atabusioscan_args_sz); +  _(ATABUSIORESET, NONE, 0); +  _(ATABUSIODETACH, READ, struct_atabusiodetach_args_sz); +  /* Entries from file: sys/cdio.h */ +  _(CDIOCPLAYTRACKS, READ, struct_ioc_play_track_sz); +  _(CDIOCPLAYBLOCKS, READ, struct_ioc_play_blocks_sz); +  _(CDIOCREADSUBCHANNEL, READWRITE, struct_ioc_read_subchannel_sz); +  _(CDIOREADTOCHEADER, WRITE, struct_ioc_toc_header_sz); +  _(CDIOREADTOCENTRIES, READWRITE, struct_ioc_read_toc_entry_sz); +  _(CDIOREADMSADDR, READWRITE, sizeof(int)); +  _(CDIOCSETPATCH, READ, struct_ioc_patch_sz); +  _(CDIOCGETVOL, WRITE, struct_ioc_vol_sz); +  _(CDIOCSETVOL, READ, struct_ioc_vol_sz); +  _(CDIOCSETMONO, NONE, 0); +  _(CDIOCSETSTEREO, NONE, 0); +  _(CDIOCSETMUTE, NONE, 0); +  _(CDIOCSETLEFT, NONE, 0); +  _(CDIOCSETRIGHT, NONE, 0); +  _(CDIOCSETDEBUG, NONE, 0); +  _(CDIOCCLRDEBUG, NONE, 0); +  _(CDIOCPAUSE, NONE, 0); +  _(CDIOCRESUME, NONE, 0); +  _(CDIOCRESET, NONE, 0); +  _(CDIOCSTART, NONE, 0); +  _(CDIOCSTOP, NONE, 0); +  _(CDIOCEJECT, NONE, 0); +  _(CDIOCALLOW, NONE, 0); +  _(CDIOCPREVENT, NONE, 0); +  _(CDIOCCLOSE, NONE, 0); +  _(CDIOCPLAYMSF, READ, struct_ioc_play_msf_sz); +  _(CDIOCLOADUNLOAD, READ, struct_ioc_load_unload_sz); +  /* Entries from file: sys/chio.h */ +  _(CHIOMOVE, READ, struct_changer_move_request_sz); +  _(CHIOEXCHANGE, READ, struct_changer_exchange_request_sz); +  _(CHIOPOSITION, READ, struct_changer_position_request_sz); +  _(CHIOSPICKER, READ, sizeof(int)); +  _(CHIOGPARAMS, WRITE, struct_changer_params_sz); +  _(CHIOIELEM, NONE, 0); +  _(OCHIOGSTATUS, READ, struct_ochanger_element_status_request_sz); +  _(CHIOGSTATUS, READ, struct_changer_element_status_request_sz); +  _(CHIOSVOLTAG, READ, struct_changer_set_voltag_request_sz); +  /* Entries from file: sys/clockctl.h */ +  _(CLOCKCTL_SETTIMEOFDAY, READ, struct_clockctl_settimeofday_sz); +  _(CLOCKCTL_ADJTIME, READWRITE, struct_clockctl_adjtime_sz); +  _(CLOCKCTL_CLOCK_SETTIME, READ, struct_clockctl_clock_settime_sz); +  _(CLOCKCTL_NTP_ADJTIME, READWRITE, struct_clockctl_ntp_adjtime_sz); +  /* Entries from file: sys/cpuio.h */ +  _(IOC_CPU_SETSTATE, READ, struct_cpustate_sz); +  _(IOC_CPU_GETSTATE, READWRITE, struct_cpustate_sz); +  _(IOC_CPU_GETCOUNT, WRITE, sizeof(int)); +  _(IOC_CPU_MAPID, READWRITE, sizeof(int)); +  _(IOC_CPU_UCODE_GET_VERSION, READWRITE, struct_cpu_ucode_version_sz); +  _(IOC_CPU_UCODE_APPLY, READ, struct_cpu_ucode_sz); +  /* Entries from file: sys/dkio.h */ +  _(DIOCGDINFO, WRITE, struct_disklabel_sz); +  _(DIOCSDINFO, READ, struct_disklabel_sz); +  _(DIOCWDINFO, READ, 0); +  _(DIOCRFORMAT, READWRITE, struct_format_op_sz); +  _(DIOCWFORMAT, READWRITE, struct_format_op_sz); +  _(DIOCSSTEP, READ, sizeof(int)); +  _(DIOCSRETRIES, READ, sizeof(int)); +  _(DIOCKLABEL, READ, sizeof(int)); +  _(DIOCWLABEL, READ, sizeof(int)); +  _(DIOCSBAD, READ, struct_dkbad_sz); +  _(DIOCEJECT, READ, sizeof(int)); +  _(ODIOCEJECT, NONE, 0); +  _(DIOCLOCK, READ, sizeof(int)); +  _(DIOCGDEFLABEL, WRITE, struct_disklabel_sz); +  _(DIOCCLRLABEL, NONE, 0); +  _(DIOCGCACHE, WRITE, sizeof(int)); +  _(DIOCSCACHE, READ, sizeof(int)); +  _(DIOCCACHESYNC, READ, sizeof(int)); +  _(DIOCBSLIST, READWRITE, struct_disk_badsecinfo_sz); +  _(DIOCBSFLUSH, NONE, 0); +  _(DIOCAWEDGE, READWRITE, struct_dkwedge_info_sz); +  _(DIOCGWEDGEINFO, WRITE, struct_dkwedge_info_sz); +  _(DIOCDWEDGE, READ, struct_dkwedge_info_sz); +  _(DIOCLWEDGES, READWRITE, struct_dkwedge_list_sz); +  _(DIOCGSTRATEGY, WRITE, struct_disk_strategy_sz); +  _(DIOCSSTRATEGY, READ, struct_disk_strategy_sz); +  _(DIOCGDISKINFO, WRITE, struct_plistref_sz); +  _(DIOCTUR, WRITE, sizeof(int)); +  _(DIOCMWEDGES, WRITE, sizeof(int)); +  _(DIOCGSECTORSIZE, WRITE, sizeof(unsigned int)); +  _(DIOCGMEDIASIZE, WRITE, sizeof(uptr)); +  /* Entries from file: sys/drvctlio.h */ +  _(DRVDETACHDEV, READ, struct_devdetachargs_sz); +  _(DRVRESCANBUS, READ, struct_devrescanargs_sz); +  _(DRVCTLCOMMAND, READWRITE, struct_plistref_sz); +  _(DRVRESUMEDEV, READ, struct_devpmargs_sz); +  _(DRVLISTDEV, READWRITE, struct_devlistargs_sz); +  _(DRVGETEVENT, WRITE, struct_plistref_sz); +  _(DRVSUSPENDDEV, READ, struct_devpmargs_sz); +  /* Entries from file: sys/dvdio.h */ +  _(DVD_READ_STRUCT, READWRITE, union_dvd_struct_sz); +  _(DVD_WRITE_STRUCT, READWRITE, union_dvd_struct_sz); +  _(DVD_AUTH, READWRITE, union_dvd_authinfo_sz); +  /* Entries from file: sys/envsys.h */ +  _(ENVSYS_GETDICTIONARY, READWRITE, struct_plistref_sz); +  _(ENVSYS_SETDICTIONARY, READWRITE, struct_plistref_sz); +  _(ENVSYS_REMOVEPROPS, READWRITE, struct_plistref_sz); +  _(ENVSYS_GTREDATA, READWRITE, struct_envsys_tre_data_sz); +  _(ENVSYS_GTREINFO, READWRITE, struct_envsys_basic_info_sz); +  /* Entries from file: sys/event.h */ +  _(KFILTER_BYFILTER, READWRITE, struct_kfilter_mapping_sz); +  _(KFILTER_BYNAME, READWRITE, struct_kfilter_mapping_sz); +  /* Entries from file: sys/fdio.h */ +  _(FDIOCGETOPTS, WRITE, 0); +  _(FDIOCSETOPTS, READ, sizeof(int)); +  _(FDIOCSETFORMAT, READ, struct_fdformat_parms_sz); +  _(FDIOCGETFORMAT, WRITE, struct_fdformat_parms_sz); +  _(FDIOCFORMAT_TRACK, READ, struct_fdformat_cmd_sz); +  /* Entries from file: sys/filio.h */ +  _(FIOCLEX, NONE, 0); +  _(FIONCLEX, NONE, 0); +  _(FIONREAD, WRITE, sizeof(int)); +  _(FIONBIO, READ, sizeof(int)); +  _(FIOASYNC, READ, sizeof(int)); +  _(FIOSETOWN, READ, sizeof(int)); +  _(FIOGETOWN, WRITE, sizeof(int)); +  _(OFIOGETBMAP, READWRITE, sizeof(u32)); +  _(FIOGETBMAP, READWRITE, sizeof(u64)); +  _(FIONWRITE, WRITE, sizeof(int)); +  _(FIONSPACE, WRITE, sizeof(int)); +  /* Entries from file: sys/gpio.h */ +  _(GPIOINFO, WRITE, struct_gpio_info_sz); +  _(GPIOSET, READWRITE, struct_gpio_set_sz); +  _(GPIOUNSET, READWRITE, struct_gpio_set_sz); +  _(GPIOREAD, READWRITE, struct_gpio_req_sz); +  _(GPIOWRITE, READWRITE, struct_gpio_req_sz); +  _(GPIOTOGGLE, READWRITE, struct_gpio_req_sz); +  _(GPIOATTACH, READWRITE, struct_gpio_attach_sz); +  /* Entries from file: sys/ioctl.h */ +  _(PTIOCNETBSD, READ, struct_ioctl_pt_sz); +  _(PTIOCSUNOS, READ, struct_ioctl_pt_sz); +  _(PTIOCLINUX, READ, struct_ioctl_pt_sz); +  _(PTIOCFREEBSD, READ, struct_ioctl_pt_sz); +  _(PTIOCULTRIX, READ, struct_ioctl_pt_sz); +  /* Entries from file: sys/ioctl_compat.h */ +  _(TIOCHPCL, NONE, 0); +  _(TIOCGETP, WRITE, struct_sgttyb_sz); +  _(TIOCSETP, READ, struct_sgttyb_sz); +  _(TIOCSETN, READ, 0); +  _(TIOCSETC, READ, struct_tchars_sz); +  _(TIOCGETC, WRITE, struct_tchars_sz); +  _(TIOCLBIS, READ, sizeof(int)); +  _(TIOCLBIC, READ, sizeof(int)); +  _(TIOCLSET, READ, sizeof(int)); +  _(TIOCLGET, WRITE, sizeof(int)); +  _(TIOCSLTC, READ, struct_ltchars_sz); +  _(TIOCGLTC, WRITE, struct_ltchars_sz); +  _(OTIOCCONS, NONE, 0); +  /* Entries from file: sys/joystick.h */ +  _(JOY_SETTIMEOUT, READ, sizeof(int)); +  _(JOY_GETTIMEOUT, WRITE, sizeof(int)); +  _(JOY_SET_X_OFFSET, READ, sizeof(int)); +  _(JOY_SET_Y_OFFSET, READ, sizeof(int)); +  _(JOY_GET_Y_OFFSET, WRITE, sizeof(int)); +  /* Entries from file: sys/ksyms.h */ +  _(OKIOCGSYMBOL, READ, struct_ksyms_ogsymbol_sz); +  _(OKIOCGVALUE, READ, struct_ksyms_ogsymbol_sz); +  _(KIOCGSIZE, WRITE, sizeof(int)); +  _(KIOCGVALUE, READWRITE, struct_ksyms_gvalue_sz); +  _(KIOCGSYMBOL, READWRITE, struct_ksyms_gsymbol_sz); +  /* Entries from file: sys/lua.h */ +  _(LUAINFO, READWRITE, struct_lua_info_sz); +  _(LUACREATE, READWRITE, struct_lua_create_sz); +  _(LUADESTROY, READWRITE, struct_lua_create_sz); +  _(LUAREQUIRE, READWRITE, struct_lua_require_sz); +  _(LUALOAD, READWRITE, struct_lua_load_sz); +  /* Entries from file: sys/midiio.h */ +  _(MIDI_PRETIME, READWRITE, sizeof(int)); +  _(MIDI_MPUMODE, READWRITE, sizeof(int)); +  _(MIDI_MPUCMD, READWRITE, struct_mpu_command_rec_sz); +  _(SEQUENCER_RESET, NONE, 0); +  _(SEQUENCER_SYNC, NONE, 0); +  _(SEQUENCER_INFO, READWRITE, struct_synth_info_sz); +  _(SEQUENCER_CTRLRATE, READWRITE, sizeof(int)); +  _(SEQUENCER_GETOUTCOUNT, WRITE, sizeof(int)); +  _(SEQUENCER_GETINCOUNT, WRITE, sizeof(int)); +  _(SEQUENCER_RESETSAMPLES, READ, sizeof(int)); +  _(SEQUENCER_NRSYNTHS, WRITE, sizeof(int)); +  _(SEQUENCER_NRMIDIS, WRITE, sizeof(int)); +  _(SEQUENCER_THRESHOLD, READ, sizeof(int)); +  _(SEQUENCER_MEMAVL, READWRITE, sizeof(int)); +  _(SEQUENCER_PANIC, NONE, 0); +  _(SEQUENCER_OUTOFBAND, READ, struct_seq_event_rec_sz); +  _(SEQUENCER_GETTIME, WRITE, sizeof(int)); +  _(SEQUENCER_TMR_TIMEBASE, READWRITE, sizeof(int)); +  _(SEQUENCER_TMR_START, NONE, 0); +  _(SEQUENCER_TMR_STOP, NONE, 0); +  _(SEQUENCER_TMR_CONTINUE, NONE, 0); +  _(SEQUENCER_TMR_TEMPO, READWRITE, sizeof(int)); +  _(SEQUENCER_TMR_SOURCE, READWRITE, sizeof(int)); +  _(SEQUENCER_TMR_METRONOME, READ, sizeof(int)); +  _(SEQUENCER_TMR_SELECT, READ, sizeof(int)); +  /* Entries from file: sys/mtio.h */ +  _(MTIOCTOP, READ, struct_mtop_sz); +  _(MTIOCGET, WRITE, struct_mtget_sz); +  _(MTIOCIEOT, NONE, 0); +  _(MTIOCEEOT, NONE, 0); +  _(MTIOCRDSPOS, WRITE, sizeof(u32)); +  _(MTIOCRDHPOS, WRITE, sizeof(u32)); +  _(MTIOCSLOCATE, READ, sizeof(u32)); +  _(MTIOCHLOCATE, READ, sizeof(u32)); +  /* Entries from file: sys/power.h */ +  _(POWER_EVENT_RECVDICT, READWRITE, struct_plistref_sz); +  _(POWER_IOC_GET_TYPE, WRITE, struct_power_type_sz); +  _(POWER_IOC_GET_TYPE_WITH_LOSSAGE, WRITE, sizeof(uptr)); +  /* Entries from file: sys/radioio.h */ +  _(RIOCGINFO, WRITE, struct_radio_info_sz); +  _(RIOCSINFO, READWRITE, struct_radio_info_sz); +  _(RIOCSSRCH, READ, sizeof(int)); +  /* Entries from file: sys/rndio.h */ +  _(RNDGETENTCNT, WRITE, sizeof(u32)); +  _(RNDGETSRCNUM, READWRITE, struct_rndstat_sz); +  _(RNDGETSRCNAME, READWRITE, struct_rndstat_name_sz); +  _(RNDCTL, READ, struct_rndctl_sz); +  _(RNDADDDATA, READ, struct_rnddata_sz); +  _(RNDGETPOOLSTAT, WRITE, struct_rndpoolstat_sz); +  _(RNDGETESTNUM, READWRITE, struct_rndstat_est_sz); +  _(RNDGETESTNAME, READWRITE, struct_rndstat_est_name_sz); +  /* Entries from file: sys/scanio.h */ +  _(SCIOCGET, WRITE, struct_scan_io_sz); +  _(SCIOCSET, READ, struct_scan_io_sz); +  _(SCIOCRESTART, NONE, 0); +  /* Entries from file: sys/scsiio.h */ +  _(SCIOCCOMMAND, READWRITE, struct_scsireq_sz); +  _(SCIOCDEBUG, READ, sizeof(int)); +  _(SCIOCIDENTIFY, WRITE, struct_scsi_addr_sz); +  _(OSCIOCIDENTIFY, WRITE, struct_oscsi_addr_sz); +  _(SCIOCDECONFIG, NONE, 0); +  _(SCIOCRECONFIG, NONE, 0); +  _(SCIOCRESET, NONE, 0); +  _(SCBUSIOSCAN, READ, struct_scbusioscan_args_sz); +  _(SCBUSIORESET, NONE, 0); +  _(SCBUSIODETACH, READ, struct_scbusiodetach_args_sz); +  _(SCBUSACCEL, READ, struct_scbusaccel_args_sz); +  /* Entries from file: sys/sockio.h */ +  _(SIOCSHIWAT, READ, sizeof(int)); +  _(SIOCGHIWAT, WRITE, sizeof(int)); +  _(SIOCSLOWAT, READ, sizeof(int)); +  _(SIOCGLOWAT, WRITE, sizeof(int)); +  _(SIOCATMARK, WRITE, sizeof(int)); +  _(SIOCSPGRP, READ, sizeof(int)); +  _(SIOCGPGRP, WRITE, sizeof(int)); +  _(SIOCADDRT, READ, struct_ortentry_sz); +  _(SIOCDELRT, READ, struct_ortentry_sz); +  _(SIOCSIFADDR, READ, struct_ifreq_sz); +  _(SIOCGIFADDR, READWRITE, struct_ifreq_sz); +  _(SIOCSIFDSTADDR, READ, struct_ifreq_sz); +  _(SIOCGIFDSTADDR, READWRITE, struct_ifreq_sz); +  _(SIOCSIFFLAGS, READ, struct_ifreq_sz); +  _(SIOCGIFFLAGS, READWRITE, struct_ifreq_sz); +  _(SIOCGIFBRDADDR, READWRITE, struct_ifreq_sz); +  _(SIOCSIFBRDADDR, READ, struct_ifreq_sz); +  _(SIOCGIFCONF, READWRITE, struct_ifconf_sz); +  _(SIOCGIFNETMASK, READWRITE, struct_ifreq_sz); +  _(SIOCSIFNETMASK, READ, struct_ifreq_sz); +  _(SIOCGIFMETRIC, READWRITE, struct_ifreq_sz); +  _(SIOCSIFMETRIC, READ, struct_ifreq_sz); +  _(SIOCDIFADDR, READ, struct_ifreq_sz); +  _(SIOCAIFADDR, READ, struct_ifaliasreq_sz); +  _(SIOCGIFALIAS, READWRITE, struct_ifaliasreq_sz); +  _(SIOCGIFAFLAG_IN, READWRITE, struct_ifreq_sz); +  _(SIOCALIFADDR, READ, struct_if_laddrreq_sz); +  _(SIOCGLIFADDR, READWRITE, struct_if_laddrreq_sz); +  _(SIOCDLIFADDR, READ, struct_if_laddrreq_sz); +  _(SIOCSIFADDRPREF, READ, struct_if_addrprefreq_sz); +  _(SIOCGIFADDRPREF, READWRITE, struct_if_addrprefreq_sz); +  _(SIOCADDMULTI, READ, struct_ifreq_sz); +  _(SIOCDELMULTI, READ, struct_ifreq_sz); +  _(SIOCGETVIFCNT, READWRITE, struct_sioc_vif_req_sz); +  _(SIOCGETSGCNT, READWRITE, struct_sioc_sg_req_sz); +  _(SIOCSIFMEDIA, READWRITE, struct_ifreq_sz); +  _(SIOCGIFMEDIA, READWRITE, struct_ifmediareq_sz); +  _(SIOCSIFGENERIC, READ, struct_ifreq_sz); +  _(SIOCGIFGENERIC, READWRITE, struct_ifreq_sz); +  _(SIOCSIFPHYADDR, READ, struct_ifaliasreq_sz); +  _(SIOCGIFPSRCADDR, READWRITE, struct_ifreq_sz); +  _(SIOCGIFPDSTADDR, READWRITE, struct_ifreq_sz); +  _(SIOCDIFPHYADDR, READ, struct_ifreq_sz); +  _(SIOCSLIFPHYADDR, READ, struct_if_laddrreq_sz); +  _(SIOCGLIFPHYADDR, READWRITE, struct_if_laddrreq_sz); +  _(SIOCSIFMTU, READ, struct_ifreq_sz); +  _(SIOCGIFMTU, READWRITE, struct_ifreq_sz); +  _(SIOCSDRVSPEC, READ, struct_ifdrv_sz); +  _(SIOCGDRVSPEC, READWRITE, struct_ifdrv_sz); +  _(SIOCIFCREATE, READ, struct_ifreq_sz); +  _(SIOCIFDESTROY, READ, struct_ifreq_sz); +  _(SIOCIFGCLONERS, READWRITE, struct_if_clonereq_sz); +  _(SIOCGIFDLT, READWRITE, struct_ifreq_sz); +  _(SIOCGIFCAP, READWRITE, struct_ifcapreq_sz); +  _(SIOCSIFCAP, READ, struct_ifcapreq_sz); +  _(SIOCSVH, READWRITE, struct_ifreq_sz); +  _(SIOCGVH, READWRITE, struct_ifreq_sz); +  _(SIOCINITIFADDR, READWRITE, struct_ifaddr_sz); +  _(SIOCGIFDATA, READWRITE, struct_ifdatareq_sz); +  _(SIOCZIFDATA, READWRITE, struct_ifdatareq_sz); +  _(SIOCGLINKSTR, READWRITE, struct_ifdrv_sz); +  _(SIOCSLINKSTR, READ, struct_ifdrv_sz); +  _(SIOCGETHERCAP, READWRITE, struct_eccapreq_sz); +  _(SIOCGIFINDEX, READWRITE, struct_ifreq_sz); +  _(SIOCSETPFSYNC, READ, struct_ifreq_sz); +  _(SIOCGETPFSYNC, READWRITE, struct_ifreq_sz); +  /* Entries from file: sys/timepps.h */ +  _(PPS_IOC_CREATE, NONE, 0); +  _(PPS_IOC_DESTROY, NONE, 0); +  _(PPS_IOC_SETPARAMS, READ, struct_pps_params_sz); +  _(PPS_IOC_GETPARAMS, WRITE, struct_pps_params_sz); +  _(PPS_IOC_GETCAP, WRITE, sizeof(int)); +  _(PPS_IOC_FETCH, READWRITE, struct_pps_info_sz); +  _(PPS_IOC_KCBIND, READ, sizeof(int)); +  /* Entries from file: sys/ttycom.h */ +  _(TIOCEXCL, NONE, 0); +  _(TIOCNXCL, NONE, 0); +  _(TIOCFLUSH, READ, sizeof(int)); +  _(TIOCGETA, WRITE, struct_termios_sz); +  _(TIOCSETA, READ, struct_termios_sz); +  _(TIOCSETAW, READ, 0); +  _(TIOCSETAF, READ, 0); +  _(TIOCGETD, WRITE, sizeof(int)); +  _(TIOCSETD, READ, sizeof(int)); +  _(TIOCGLINED, WRITE, (32 * sizeof(char))); +  _(TIOCSLINED, READ, (32 * sizeof(char))); +  _(TIOCSBRK, NONE, 0); +  _(TIOCCBRK, NONE, 0); +  _(TIOCSDTR, NONE, 0); +  _(TIOCCDTR, NONE, 0); +  _(TIOCGPGRP, WRITE, sizeof(int)); +  _(TIOCSPGRP, READ, sizeof(int)); +  _(TIOCOUTQ, WRITE, sizeof(int)); +  _(TIOCSTI, READ, sizeof(char)); +  _(TIOCNOTTY, NONE, 0); +  _(TIOCPKT, READ, sizeof(int)); +  _(TIOCSTOP, NONE, 0); +  _(TIOCSTART, NONE, 0); +  _(TIOCMSET, READ, sizeof(int)); +  _(TIOCMBIS, READ, sizeof(int)); +  _(TIOCMBIC, READ, sizeof(int)); +  _(TIOCMGET, WRITE, sizeof(int)); +  _(TIOCREMOTE, READ, sizeof(int)); +  _(TIOCGWINSZ, WRITE, struct_winsize_sz); +  _(TIOCSWINSZ, READ, struct_winsize_sz); +  _(TIOCUCNTL, READ, sizeof(int)); +  _(TIOCSTAT, READ, sizeof(int)); +  _(TIOCGSID, WRITE, sizeof(int)); +  _(TIOCCONS, READ, sizeof(int)); +  _(TIOCSCTTY, NONE, 0); +  _(TIOCEXT, READ, sizeof(int)); +  _(TIOCSIG, NONE, 0); +  _(TIOCDRAIN, NONE, 0); +  _(TIOCGFLAGS, WRITE, sizeof(int)); +  _(TIOCSFLAGS, READ, sizeof(int)); +  _(TIOCDCDTIMESTAMP, WRITE, struct_timeval_sz); +  _(TIOCRCVFRAME, READ, sizeof(uptr)); +  _(TIOCXMTFRAME, READ, sizeof(uptr)); +  _(TIOCPTMGET, WRITE, struct_ptmget_sz); +  _(TIOCGRANTPT, NONE, 0); +  _(TIOCPTSNAME, WRITE, struct_ptmget_sz); +  _(TIOCSQSIZE, READ, sizeof(int)); +  _(TIOCGQSIZE, WRITE, sizeof(int)); +  /* Entries from file: sys/verified_exec.h */ +  _(VERIEXEC_LOAD, READ, struct_plistref_sz); +  _(VERIEXEC_TABLESIZE, READ, struct_plistref_sz); +  _(VERIEXEC_DELETE, READ, struct_plistref_sz); +  _(VERIEXEC_QUERY, READWRITE, struct_plistref_sz); +  _(VERIEXEC_DUMP, WRITE, struct_plistref_sz); +  _(VERIEXEC_FLUSH, NONE, 0); +  /* Entries from file: sys/videoio.h */ +  _(VIDIOC_QUERYCAP, WRITE, struct_v4l2_capability_sz); +  _(VIDIOC_RESERVED, NONE, 0); +  _(VIDIOC_ENUM_FMT, READWRITE, struct_v4l2_fmtdesc_sz); +  _(VIDIOC_G_FMT, READWRITE, struct_v4l2_format_sz); +  _(VIDIOC_S_FMT, READWRITE, struct_v4l2_format_sz); +  _(VIDIOC_REQBUFS, READWRITE, struct_v4l2_requestbuffers_sz); +  _(VIDIOC_QUERYBUF, READWRITE, struct_v4l2_buffer_sz); +  _(VIDIOC_G_FBUF, WRITE, struct_v4l2_framebuffer_sz); +  _(VIDIOC_S_FBUF, READ, struct_v4l2_framebuffer_sz); +  _(VIDIOC_OVERLAY, READ, sizeof(int)); +  _(VIDIOC_QBUF, READWRITE, struct_v4l2_buffer_sz); +  _(VIDIOC_DQBUF, READWRITE, struct_v4l2_buffer_sz); +  _(VIDIOC_STREAMON, READ, sizeof(int)); +  _(VIDIOC_STREAMOFF, READ, sizeof(int)); +  _(VIDIOC_G_PARM, READWRITE, struct_v4l2_streamparm_sz); +  _(VIDIOC_S_PARM, READWRITE, struct_v4l2_streamparm_sz); +  _(VIDIOC_G_STD, WRITE, sizeof(u64)); +  _(VIDIOC_S_STD, READ, sizeof(u64)); +  _(VIDIOC_ENUMSTD, READWRITE, struct_v4l2_standard_sz); +  _(VIDIOC_ENUMINPUT, READWRITE, struct_v4l2_input_sz); +  _(VIDIOC_G_CTRL, READWRITE, struct_v4l2_control_sz); +  _(VIDIOC_S_CTRL, READWRITE, struct_v4l2_control_sz); +  _(VIDIOC_G_TUNER, READWRITE, struct_v4l2_tuner_sz); +  _(VIDIOC_S_TUNER, READ, struct_v4l2_tuner_sz); +  _(VIDIOC_G_AUDIO, WRITE, struct_v4l2_audio_sz); +  _(VIDIOC_S_AUDIO, READ, struct_v4l2_audio_sz); +  _(VIDIOC_QUERYCTRL, READWRITE, struct_v4l2_queryctrl_sz); +  _(VIDIOC_QUERYMENU, READWRITE, struct_v4l2_querymenu_sz); +  _(VIDIOC_G_INPUT, WRITE, sizeof(int)); +  _(VIDIOC_S_INPUT, READWRITE, sizeof(int)); +  _(VIDIOC_G_OUTPUT, WRITE, sizeof(int)); +  _(VIDIOC_S_OUTPUT, READWRITE, sizeof(int)); +  _(VIDIOC_ENUMOUTPUT, READWRITE, struct_v4l2_output_sz); +  _(VIDIOC_G_AUDOUT, WRITE, struct_v4l2_audioout_sz); +  _(VIDIOC_S_AUDOUT, READ, struct_v4l2_audioout_sz); +  _(VIDIOC_G_MODULATOR, READWRITE, struct_v4l2_modulator_sz); +  _(VIDIOC_S_MODULATOR, READ, struct_v4l2_modulator_sz); +  _(VIDIOC_G_FREQUENCY, READWRITE, struct_v4l2_frequency_sz); +  _(VIDIOC_S_FREQUENCY, READ, struct_v4l2_frequency_sz); +  _(VIDIOC_CROPCAP, READWRITE, struct_v4l2_cropcap_sz); +  _(VIDIOC_G_CROP, READWRITE, struct_v4l2_crop_sz); +  _(VIDIOC_S_CROP, READ, struct_v4l2_crop_sz); +  _(VIDIOC_G_JPEGCOMP, WRITE, struct_v4l2_jpegcompression_sz); +  _(VIDIOC_S_JPEGCOMP, READ, struct_v4l2_jpegcompression_sz); +  _(VIDIOC_QUERYSTD, WRITE, sizeof(u64)); +  _(VIDIOC_TRY_FMT, READWRITE, struct_v4l2_format_sz); +  _(VIDIOC_ENUMAUDIO, READWRITE, struct_v4l2_audio_sz); +  _(VIDIOC_ENUMAUDOUT, READWRITE, struct_v4l2_audioout_sz); +  _(VIDIOC_G_PRIORITY, WRITE, enum_v4l2_priority_sz); +  _(VIDIOC_S_PRIORITY, READ, enum_v4l2_priority_sz); +  _(VIDIOC_ENUM_FRAMESIZES, READWRITE, struct_v4l2_frmsizeenum_sz); +  _(VIDIOC_ENUM_FRAMEINTERVALS, READWRITE, struct_v4l2_frmivalenum_sz); +  /* Entries from file: sys/wdog.h */ +  _(WDOGIOC_GMODE, READWRITE, struct_wdog_mode_sz); +  _(WDOGIOC_SMODE, READ, struct_wdog_mode_sz); +  _(WDOGIOC_WHICH, WRITE, struct_wdog_mode_sz); +  _(WDOGIOC_TICKLE, NONE, 0); +  _(WDOGIOC_GTICKLER, WRITE, sizeof(int)); +  _(WDOGIOC_GWDOGS, READWRITE, struct_wdog_conf_sz); +  /* Entries from file: soundcard.h */ +  _(SNDCTL_DSP_RESET, NONE, 0); +  _(SNDCTL_DSP_SYNC, NONE, 0); +  _(SNDCTL_DSP_SPEED, READWRITE, sizeof(int)); +  _(SOUND_PCM_READ_RATE, WRITE, sizeof(int)); +  _(SNDCTL_DSP_STEREO, READWRITE, sizeof(int)); +  _(SNDCTL_DSP_GETBLKSIZE, READWRITE, sizeof(int)); +  _(SNDCTL_DSP_SETFMT, READWRITE, sizeof(int)); +  _(SOUND_PCM_READ_BITS, WRITE, sizeof(int)); +  _(SNDCTL_DSP_CHANNELS, READWRITE, sizeof(int)); +  _(SOUND_PCM_READ_CHANNELS, WRITE, sizeof(int)); +  _(SOUND_PCM_WRITE_FILTER, READWRITE, sizeof(int)); +  _(SOUND_PCM_READ_FILTER, WRITE, sizeof(int)); +  _(SNDCTL_DSP_POST, NONE, 0); +  _(SNDCTL_DSP_SUBDIVIDE, READWRITE, sizeof(int)); +  _(SNDCTL_DSP_SETFRAGMENT, READWRITE, sizeof(int)); +  _(SNDCTL_DSP_GETFMTS, WRITE, sizeof(int)); +  _(SNDCTL_DSP_GETOSPACE, WRITE, struct_audio_buf_info_sz); +  _(SNDCTL_DSP_GETISPACE, WRITE, struct_audio_buf_info_sz); +  _(SNDCTL_DSP_NONBLOCK, NONE, 0); +  _(SNDCTL_DSP_GETCAPS, WRITE, sizeof(int)); +  _(SNDCTL_DSP_GETTRIGGER, WRITE, sizeof(int)); +  _(SNDCTL_DSP_SETTRIGGER, READ, sizeof(int)); +  _(SNDCTL_DSP_GETIPTR, WRITE, struct_count_info_sz); +  _(SNDCTL_DSP_GETOPTR, WRITE, struct_count_info_sz); +  _(SNDCTL_DSP_MAPINBUF, WRITE, struct_buffmem_desc_sz); +  _(SNDCTL_DSP_MAPOUTBUF, WRITE, struct_buffmem_desc_sz); +  _(SNDCTL_DSP_SETSYNCRO, NONE, 0); +  _(SNDCTL_DSP_SETDUPLEX, NONE, 0); +  _(SNDCTL_DSP_PROFILE, READ, sizeof(int)); +  _(SNDCTL_DSP_GETODELAY, WRITE, sizeof(int)); +  _(SOUND_MIXER_INFO, WRITE, struct_mixer_info_sz); +  _(SOUND_OLD_MIXER_INFO, WRITE, struct__old_mixer_info_sz); +  _(OSS_GETVERSION, WRITE, sizeof(int)); +  _(SNDCTL_SYSINFO, WRITE, struct_oss_sysinfo_sz); +  _(SNDCTL_AUDIOINFO, READWRITE, struct_oss_audioinfo_sz); +  _(SNDCTL_ENGINEINFO, READWRITE, struct_oss_audioinfo_sz); +  _(SNDCTL_DSP_GETPLAYVOL, WRITE, sizeof(unsigned int)); +  _(SNDCTL_DSP_SETPLAYVOL, READ, sizeof(unsigned int)); +  _(SNDCTL_DSP_GETRECVOL, WRITE, sizeof(unsigned int)); +  _(SNDCTL_DSP_SETRECVOL, READ, sizeof(unsigned int)); +  _(SNDCTL_DSP_SKIP, NONE, 0); +  _(SNDCTL_DSP_SILENCE, NONE, 0); +#undef _ +} + +static bool ioctl_initialized = false; + +struct ioctl_desc_compare { +  bool operator()(const ioctl_desc &left, const ioctl_desc &right) const { +    return left.req < right.req; +  } +}; + +static void ioctl_init() { +  ioctl_table_fill(); +  Sort(ioctl_table, ioctl_table_size, ioctl_desc_compare()); + +  bool bad = false; +  for (unsigned i = 0; i < ioctl_table_size - 1; ++i) { +    if (ioctl_table[i].req >= ioctl_table[i + 1].req) { +      Printf("Duplicate or unsorted ioctl request id %x >= %x (%s vs %s)\n", +             ioctl_table[i].req, ioctl_table[i + 1].req, ioctl_table[i].name, +             ioctl_table[i + 1].name); +      bad = true; +    } +  } + +  if (bad) +    Die(); + +  ioctl_initialized = true; +} + +static const ioctl_desc *ioctl_table_lookup(unsigned req) { +  int left = 0; +  int right = ioctl_table_size; +  while (left < right) { +    int mid = (left + right) / 2; +    if (ioctl_table[mid].req < req) +      left = mid + 1; +    else +      right = mid; +  } +  if (left == right && ioctl_table[left].req == req) +    return ioctl_table + left; +  else +    return nullptr; +} + +static bool ioctl_decode(unsigned req, ioctl_desc *desc) { +  CHECK(desc); +  desc->req = req; +  desc->name = "<DECODED_IOCTL>"; +  desc->size = IOC_SIZE(req); +  // Sanity check. +  if (desc->size > 0xFFFF) +    return false; +  unsigned dir = IOC_DIR(req); +  switch (dir) { +  case IOC_NONE: +    desc->type = ioctl_desc::NONE; +    break; +  case IOC_READ | IOC_WRITE: +    desc->type = ioctl_desc::READWRITE; +    break; +  case IOC_READ: +    desc->type = ioctl_desc::WRITE; +    break; +  case IOC_WRITE: +    desc->type = ioctl_desc::READ; +    break; +  default: +    return false; +  } +  // Size can be 0 iff type is NONE. +  if ((desc->type == IOC_NONE) != (desc->size == 0)) +    return false; +  // Sanity check. +  if (IOC_TYPE(req) == 0) +    return false; +  return true; +} + +static const ioctl_desc *ioctl_lookup(unsigned req) { +  const ioctl_desc *desc = ioctl_table_lookup(req); +  if (desc) +    return desc; + +  // Try stripping access size from the request id. +  desc = ioctl_table_lookup(req & ~(IOC_SIZEMASK << IOC_SIZESHIFT)); +  // Sanity check: requests that encode access size are either read or write and +  // have size of 0 in the table. +  if (desc && desc->size == 0 && +      (desc->type == ioctl_desc::READWRITE || desc->type == ioctl_desc::WRITE || +       desc->type == ioctl_desc::READ)) +    return desc; +  return nullptr; +} + +static void ioctl_common_pre(void *ctx, const ioctl_desc *desc, int d, +                             unsigned request, void *arg) { +  if (desc->type == ioctl_desc::READ || desc->type == ioctl_desc::READWRITE) { +    unsigned size = desc->size ? desc->size : IOC_SIZE(request); +    COMMON_INTERCEPTOR_READ_RANGE(ctx, arg, size); +  } +  if (desc->type != ioctl_desc::CUSTOM) +    return; +  if (request == IOCTL_SIOCGIFCONF) { +    struct __sanitizer_ifconf *ifc = (__sanitizer_ifconf *)arg; +    COMMON_INTERCEPTOR_READ_RANGE(ctx, (char *)&ifc->ifc_len, +                                  sizeof(ifc->ifc_len)); +  } +} + +static void ioctl_common_post(void *ctx, const ioctl_desc *desc, int res, int d, +                              unsigned request, void *arg) { +  if (desc->type == ioctl_desc::WRITE || desc->type == ioctl_desc::READWRITE) { +    // FIXME: add verbose output +    unsigned size = desc->size ? desc->size : IOC_SIZE(request); +    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, arg, size); +  } +  if (desc->type != ioctl_desc::CUSTOM) +    return; +  if (request == IOCTL_SIOCGIFCONF) { +    struct __sanitizer_ifconf *ifc = (__sanitizer_ifconf *)arg; +    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ifc->ifc_ifcu.ifcu_req, ifc->ifc_len); +  } +} + +#endif // SANITIZER_NETBSD diff --git a/lib/sanitizer_common/sanitizer_interface_internal.h b/lib/sanitizer_common/sanitizer_interface_internal.h index 942f0b1cb586a..f53d9557eab4c 100644 --- a/lib/sanitizer_common/sanitizer_interface_internal.h +++ b/lib/sanitizer_common/sanitizer_interface_internal.h @@ -52,6 +52,12 @@ extern "C" {    SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_dump_trace_pc_guard_coverage();    SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov(__sanitizer::u32 *guard); + +  // Returns 1 on the first call, then returns 0 thereafter.  Called by the tool +  // to ensure only one report is printed when multiple errors occur +  // simultaneously. +  SANITIZER_INTERFACE_ATTRIBUTE int __sanitizer_acquire_crash_state(); +    SANITIZER_INTERFACE_ATTRIBUTE    void __sanitizer_annotate_contiguous_container(const void *beg,                                                   const void *end, diff --git a/lib/sanitizer_common/sanitizer_internal_defs.h b/lib/sanitizer_common/sanitizer_internal_defs.h index dc480e75f98d3..f8a405ba6e4d2 100644 --- a/lib/sanitizer_common/sanitizer_internal_defs.h +++ b/lib/sanitizer_common/sanitizer_internal_defs.h @@ -19,6 +19,9 @@  # define SANITIZER_DEBUG 0  #endif +#define SANITIZER_STRINGIFY_(S) #S +#define SANITIZER_STRINGIFY(S) SANITIZER_STRINGIFY_(S) +  // Only use SANITIZER_*ATTRIBUTE* before the function return type!  #if SANITIZER_WINDOWS  #if SANITIZER_IMPORT_INTERFACE @@ -36,7 +39,8 @@  #endif  // TLS is handled differently on different platforms -#if SANITIZER_LINUX || SANITIZER_NETBSD +#if SANITIZER_LINUX || SANITIZER_NETBSD || \ +  SANITIZER_FREEBSD || SANITIZER_OPENBSD  # define SANITIZER_TLS_INITIAL_EXEC_ATTRIBUTE \      __attribute__((tls_model("initial-exec"))) thread_local  #else @@ -65,7 +69,13 @@  // SANITIZER_SUPPORTS_WEAK_HOOKS means that we support real weak functions that  // will evaluate to a null pointer when not defined.  #ifndef SANITIZER_SUPPORTS_WEAK_HOOKS -#if (SANITIZER_LINUX || SANITIZER_MAC || SANITIZER_SOLARIS) && !SANITIZER_GO +#if (SANITIZER_LINUX || SANITIZER_SOLARIS) && !SANITIZER_GO +# define SANITIZER_SUPPORTS_WEAK_HOOKS 1 +// Before Xcode 4.5, the Darwin linker doesn't reliably support undefined +// weak symbols.  Mac OS X 10.9/Darwin 13 is the first release only supported +// by Xcode >= 4.5. +#elif SANITIZER_MAC && \ +    __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1090 && !SANITIZER_GO  # define SANITIZER_SUPPORTS_WEAK_HOOKS 1  #else  # define SANITIZER_SUPPORTS_WEAK_HOOKS 0 @@ -88,9 +98,16 @@  // We can use .preinit_array section on Linux to call sanitizer initialization  // functions very early in the process startup (unless PIC macro is defined). +// +// On FreeBSD, .preinit_array functions are called with rtld_bind_lock writer +// lock held. It will lead to dead lock if unresolved PLT functions (which helds +// rtld_bind_lock reader lock) are called inside .preinit_array functions. +//  // FIXME: do we have anything like this on Mac? -#if SANITIZER_LINUX && !SANITIZER_ANDROID && !defined(PIC) -# define SANITIZER_CAN_USE_PREINIT_ARRAY 1 +#ifndef SANITIZER_CAN_USE_PREINIT_ARRAY +#if ((SANITIZER_LINUX && !SANITIZER_ANDROID) || SANITIZER_OPENBSD) && \ +    !defined(PIC) +#define SANITIZER_CAN_USE_PREINIT_ARRAY 1  // Before Solaris 11.4, .preinit_array is fully supported only with GNU ld.  // FIXME: Check for those conditions.  #elif SANITIZER_SOLARIS && !defined(PIC) @@ -98,12 +115,18 @@  #else  # define SANITIZER_CAN_USE_PREINIT_ARRAY 0  #endif +#endif  // SANITIZER_CAN_USE_PREINIT_ARRAY  // GCC does not understand __has_feature  #if !defined(__has_feature)  # define __has_feature(x) 0  #endif +// Older GCCs do not understand __has_attribute. +#if !defined(__has_attribute) +# define __has_attribute(x) 0 +#endif +  // For portability reasons we do not include stddef.h, stdint.h or any other  // system header, but we do need some basic types that are not defined  // in a portable way by the language itself. @@ -147,7 +170,8 @@ typedef long pid_t;  typedef int pid_t;  #endif -#if SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_MAC || \ +#if SANITIZER_FREEBSD || SANITIZER_NETBSD || \ +    SANITIZER_OPENBSD || SANITIZER_MAC || \      (SANITIZER_LINUX && defined(__x86_64__))  typedef u64 OFF_T;  #else @@ -158,7 +182,7 @@ typedef u64  OFF64_T;  #if (SANITIZER_WORDSIZE == 64) || SANITIZER_MAC  typedef uptr operator_new_size_type;  #else -# if defined(__s390__) && !defined(__s390x__) +# if SANITIZER_OPENBSD || defined(__s390__) && !defined(__s390x__)  // Special case: 31-bit s390 has unsigned long as size_t.  typedef unsigned long operator_new_size_type;  # else @@ -166,12 +190,7 @@ typedef u32 operator_new_size_type;  # endif  #endif -#if SANITIZER_MAC -// On Darwin, thread IDs are 64-bit even on 32-bit systems.  typedef u64 tid_t; -#else -typedef uptr tid_t; -#endif  // ----------- ATTENTION -------------  // This header should NOT include any other headers to avoid portability issues. @@ -197,6 +216,7 @@ typedef uptr tid_t;  # define LIKELY(x) (x)  # define UNLIKELY(x) (x)  # define PREFETCH(x) /* _mm_prefetch(x, _MM_HINT_NTA) */ (void)0 +# define WARN_UNUSED_RESULT  #else  // _MSC_VER  # define ALWAYS_INLINE inline __attribute__((always_inline))  # define ALIAS(x) __attribute__((alias(x))) @@ -215,6 +235,7 @@ typedef uptr tid_t;  # else  #  define PREFETCH(x) __builtin_prefetch(x)  # endif +# define WARN_UNUSED_RESULT __attribute__((warn_unused_result))  #endif  // _MSC_VER  #if !defined(_MSC_VER) || defined(__clang__) @@ -343,6 +364,12 @@ void NORETURN CheckFailed(const char *file, int line, const char *cond,  #define INT64_MAX              (__INT64_C(9223372036854775807))  #undef UINT64_MAX  #define UINT64_MAX             (__UINT64_C(18446744073709551615)) +#undef UINTPTR_MAX +#if SANITIZER_WORDSIZE == 64 +# define UINTPTR_MAX           (18446744073709551615UL) +#else +# define UINTPTR_MAX           (4294967295U) +#endif  // SANITIZER_WORDSIZE == 64  enum LinkerInitialized { LINKER_INITIALIZED = 0 }; diff --git a/lib/sanitizer_common/sanitizer_libc.cc b/lib/sanitizer_common/sanitizer_libc.cc index d6c8ea2a11a0d..4b462bfe97283 100644 --- a/lib/sanitizer_common/sanitizer_libc.cc +++ b/lib/sanitizer_common/sanitizer_libc.cc @@ -72,17 +72,6 @@ void *internal_memmove(void *dest, const void *src, uptr n) {    return dest;  } -// Semi-fast bzero for 16-aligned data. Still far from peak performance. -void internal_bzero_aligned16(void *s, uptr n) { -  struct ALIGNED(16) S16 { u64 a, b; }; -  CHECK_EQ((reinterpret_cast<uptr>(s) | n) & 15, 0); -  for (S16 *p = reinterpret_cast<S16*>(s), *end = p + n / 16; p < end; p++) { -    p->a = p->b = 0; -    // Make sure this does not become memset. -    SanitizerBreakOptimization(nullptr); -  } -} -  void *internal_memset(void* s, int c, uptr n) {    // The next line prevents Clang from making a call to memset() instead of the    // loop below. @@ -112,14 +101,6 @@ char* internal_strdup(const char *s) {    return s2;  } -char* internal_strndup(const char *s, uptr n) { -  uptr len = internal_strnlen(s, n); -  char *s2 = (char*)InternalAlloc(len + 1); -  internal_memcpy(s2, s, len); -  s2[len] = 0; -  return s2; -} -  int internal_strcmp(const char *s1, const char *s2) {    while (true) {      unsigned c1 = *s1; @@ -234,13 +215,7 @@ char *internal_strstr(const char *haystack, const char *needle) {    return nullptr;  } -uptr internal_wcslen(const wchar_t *s) { -  uptr i = 0; -  while (s[i]) i++; -  return i; -} - -s64 internal_simple_strtoll(const char *nptr, char **endptr, int base) { +s64 internal_simple_strtoll(const char *nptr, const char **endptr, int base) {    CHECK_EQ(base, 10);    while (IsSpace(*nptr)) nptr++;    int sgn = 1; diff --git a/lib/sanitizer_common/sanitizer_libc.h b/lib/sanitizer_common/sanitizer_libc.h index 9c11fb0ad2be2..7ed4e28a56957 100644 --- a/lib/sanitizer_common/sanitizer_libc.h +++ b/lib/sanitizer_common/sanitizer_libc.h @@ -32,8 +32,6 @@ void *internal_memrchr(const void *s, int c, uptr n);  int internal_memcmp(const void* s1, const void* s2, uptr n);  void *internal_memcpy(void *dest, const void *src, uptr n);  void *internal_memmove(void *dest, const void *src, uptr n); -// Set [s, s + n) to 0. Both s and n should be 16-aligned. -void internal_bzero_aligned16(void *s, uptr n);  // Should not be used in performance-critical places.  void *internal_memset(void *s, int c, uptr n);  char* internal_strchr(const char *s, int c); @@ -41,7 +39,6 @@ char *internal_strchrnul(const char *s, int c);  int internal_strcmp(const char *s1, const char *s2);  uptr internal_strcspn(const char *s, const char *reject);  char *internal_strdup(const char *s); -char *internal_strndup(const char *s, uptr n);  uptr internal_strlen(const char *s);  uptr internal_strlcat(char *dst, const char *src, uptr maxlen);  char *internal_strncat(char *dst, const char *src, uptr n); @@ -50,11 +47,9 @@ uptr internal_strlcpy(char *dst, const char *src, uptr maxlen);  char *internal_strncpy(char *dst, const char *src, uptr n);  uptr internal_strnlen(const char *s, uptr maxlen);  char *internal_strrchr(const char *s, int c); -// This is O(N^2), but we are not using it in hot places. -uptr internal_wcslen(const wchar_t *s);  char *internal_strstr(const char *haystack, const char *needle);  // Works only for base=10 and doesn't set errno. -s64 internal_simple_strtoll(const char *nptr, char **endptr, int base); +s64 internal_simple_strtoll(const char *nptr, const char **endptr, int base);  int internal_snprintf(char *buffer, uptr length, const char *format, ...);  // Return true if all bytes in [mem, mem+size) are zero. diff --git a/lib/sanitizer_common/sanitizer_libignore.cc b/lib/sanitizer_common/sanitizer_libignore.cc index 0df055edae97d..49c4ba4294922 100644 --- a/lib/sanitizer_common/sanitizer_libignore.cc +++ b/lib/sanitizer_common/sanitizer_libignore.cc @@ -9,7 +9,8 @@  #include "sanitizer_platform.h" -#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_MAC || SANITIZER_NETBSD +#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_MAC || \ +    SANITIZER_NETBSD || SANITIZER_OPENBSD  #include "sanitizer_libignore.h"  #include "sanitizer_flags.h" @@ -80,7 +81,7 @@ void LibIgnore::OnLibraryLoaded(const char *name) {          lib->name = internal_strdup(mod.full_name());          const uptr idx =              atomic_load(&ignored_ranges_count_, memory_order_relaxed); -        CHECK_LT(idx, kMaxLibs); +        CHECK_LT(idx, ARRAY_SIZE(ignored_code_ranges_));          ignored_code_ranges_[idx].begin = range.beg;          ignored_code_ranges_[idx].end = range.end;          atomic_store(&ignored_ranges_count_, idx + 1, memory_order_release); @@ -109,7 +110,7 @@ void LibIgnore::OnLibraryLoaded(const char *name) {                  range.beg, range.end, mod.full_name());          const uptr idx =              atomic_load(&instrumented_ranges_count_, memory_order_relaxed); -        CHECK_LT(idx, kMaxLibs); +        CHECK_LT(idx, ARRAY_SIZE(instrumented_code_ranges_));          instrumented_code_ranges_[idx].begin = range.beg;          instrumented_code_ranges_[idx].end = range.end;          atomic_store(&instrumented_ranges_count_, idx + 1, diff --git a/lib/sanitizer_common/sanitizer_libignore.h b/lib/sanitizer_common/sanitizer_libignore.h index 17b0f563d47d4..49967b1e8d2ae 100644 --- a/lib/sanitizer_common/sanitizer_libignore.h +++ b/lib/sanitizer_common/sanitizer_libignore.h @@ -66,14 +66,16 @@ class LibIgnore {      return (pc >= range.begin && pc < range.end);    } -  static const uptr kMaxLibs = 128; +  static const uptr kMaxIgnoredRanges = 128; +  static const uptr kMaxInstrumentedRanges = 1024; +  static const uptr kMaxLibs = 1024;    // Hot part:    atomic_uintptr_t ignored_ranges_count_; -  LibCodeRange ignored_code_ranges_[kMaxLibs]; +  LibCodeRange ignored_code_ranges_[kMaxIgnoredRanges];    atomic_uintptr_t instrumented_ranges_count_; -  LibCodeRange instrumented_code_ranges_[kMaxLibs]; +  LibCodeRange instrumented_code_ranges_[kMaxInstrumentedRanges];    // Cold part:    BlockingMutex mutex_; diff --git a/lib/sanitizer_common/sanitizer_linux.cc b/lib/sanitizer_common/sanitizer_linux.cc index 6c83e8db42a5c..96d6c1eff42c3 100644 --- a/lib/sanitizer_common/sanitizer_linux.cc +++ b/lib/sanitizer_common/sanitizer_linux.cc @@ -15,7 +15,7 @@  #include "sanitizer_platform.h"  #if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \ -    SANITIZER_SOLARIS +    SANITIZER_OPENBSD || SANITIZER_SOLARIS  #include "sanitizer_common.h"  #include "sanitizer_flags.h" @@ -26,8 +26,6 @@  #include "sanitizer_mutex.h"  #include "sanitizer_placement_new.h"  #include "sanitizer_procmaps.h" -#include "sanitizer_stacktrace.h" -#include "sanitizer_symbolizer.h"  #if SANITIZER_LINUX  #include <asm/param.h> @@ -55,6 +53,7 @@  #include <link.h>  #include <pthread.h>  #include <sched.h> +#include <signal.h>  #include <sys/mman.h>  #if !SANITIZER_SOLARIS  #include <sys/ptrace.h> @@ -64,7 +63,12 @@  #include <sys/syscall.h>  #include <sys/time.h>  #include <sys/types.h> +#if !SANITIZER_OPENBSD  #include <ucontext.h> +#endif +#if SANITIZER_OPENBSD +#include <sys/futex.h> +#endif  #include <unistd.h>  #if SANITIZER_LINUX @@ -84,13 +88,12 @@ extern "C" {  // FreeBSD 9.2 and 10.0.  #include <sys/umtx.h>  } -extern char **environ;  // provided by crt1 +#include <sys/thr.h>  #endif  // SANITIZER_FREEBSD  #if SANITIZER_NETBSD  #include <limits.h>  // For NAME_MAX  #include <sys/sysctl.h> -extern char **environ;  // provided by crt1  #include <sys/exec.h>  extern struct ps_strings *__ps_strings;  #endif  // SANITIZER_NETBSD @@ -98,14 +101,10 @@ extern struct ps_strings *__ps_strings;  #if SANITIZER_SOLARIS  #include <stdlib.h>  #include <thread.h> - -extern char **_environ;  #define environ _environ  #endif -#if !SANITIZER_ANDROID -#include <sys/signal.h> -#endif +extern char **environ;  #if SANITIZER_LINUX  // <linux/time.h> @@ -122,8 +121,8 @@ const int FUTEX_WAKE = 1;  // Are we using 32-bit or 64-bit Linux syscalls?  // x32 (which defines __x86_64__) has SANITIZER_WORDSIZE == 32  // but it still needs to use 64-bit syscalls. -#if SANITIZER_LINUX && (defined(__x86_64__) || defined(__powerpc64__) || \ -    SANITIZER_WORDSIZE == 64) +#if SANITIZER_LINUX && (defined(__x86_64__) || defined(__powerpc64__) ||       \ +                        SANITIZER_WORDSIZE == 64)  # define SANITIZER_LINUX_USES_64BIT_SYSCALLS 1  #else  # define SANITIZER_LINUX_USES_64BIT_SYSCALLS 0 @@ -135,6 +134,9 @@ extern void internal_sigreturn();  }  #endif +// Note : FreeBSD had implemented both +// Linux and OpenBSD apis, available from +// future 12.x version most likely  #if SANITIZER_LINUX && defined(__NR_getrandom)  # if !defined(GRND_NONBLOCK)  #  define GRND_NONBLOCK 1 @@ -144,6 +146,12 @@ extern void internal_sigreturn();  # define SANITIZER_USE_GETRANDOM 0  #endif  // SANITIZER_LINUX && defined(__NR_getrandom) +#if SANITIZER_OPENBSD +# define SANITIZER_USE_GETENTROPY 1 +#else +# define SANITIZER_USE_GETENTROPY 0 +#endif // SANITIZER_USE_GETENTROPY +  namespace __sanitizer {  #if SANITIZER_LINUX && defined(__x86_64__) @@ -158,11 +166,11 @@ namespace __sanitizer {  // --------------- sanitizer_libc.h  #if !SANITIZER_SOLARIS -#if !SANITIZER_S390 +#if !SANITIZER_S390 && !SANITIZER_OPENBSD  uptr internal_mmap(void *addr, uptr length, int prot, int flags, int fd,                     OFF_T offset) {  #if SANITIZER_NETBSD -  return internal_syscall_ptr(SYSCALL(mmap), addr, length, prot, flags, fd, +  return internal_syscall64(SYSCALL(mmap), addr, length, prot, flags, fd,                                (long)0, offset);  #elif SANITIZER_FREEBSD || SANITIZER_LINUX_USES_64BIT_SYSCALLS    return internal_syscall(SYSCALL(mmap), (uptr)addr, length, prot, flags, fd, @@ -174,8 +182,9 @@ uptr internal_mmap(void *addr, uptr length, int prot, int flags, int fd,                            offset / 4096);  #endif  } -#endif // !SANITIZER_S390 +#endif // !SANITIZER_S390 && !SANITIZER_OPENBSD +#if !SANITIZER_OPENBSD  uptr internal_munmap(void *addr, uptr length) {    return internal_syscall_ptr(SYSCALL(munmap), (uptr)addr, length);  } @@ -183,6 +192,7 @@ uptr internal_munmap(void *addr, uptr length) {  int internal_mprotect(void *addr, uptr length, int prot) {    return internal_syscall_ptr(SYSCALL(mprotect), (uptr)addr, length, prot);  } +#endif  uptr internal_close(fd_t fd) {    return internal_syscall(SYSCALL(close), fd); @@ -298,12 +308,12 @@ static void kernel_stat_to_stat(struct kernel_stat *in, struct stat *out) {  #endif  uptr internal_stat(const char *path, void *buf) { -#if SANITIZER_FREEBSD || SANITIZER_NETBSD -  return internal_syscall_ptr(SYSCALL(fstatat), AT_FDCWD, (uptr)path, -                          (uptr)buf, 0); +#if SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_OPENBSD +  return internal_syscall_ptr(SYSCALL(fstatat), AT_FDCWD, (uptr)path, (uptr)buf, +                              0);  #elif SANITIZER_USES_CANONICAL_LINUX_SYSCALLS -  return internal_syscall(SYSCALL(newfstatat), AT_FDCWD, (uptr)path, -                          (uptr)buf, 0); +  return internal_syscall(SYSCALL(newfstatat), AT_FDCWD, (uptr)path, (uptr)buf, +                          0);  #elif SANITIZER_LINUX_USES_64BIT_SYSCALLS  # if defined(__mips64)    // For mips64, stat syscall fills buffer in the format of kernel_stat @@ -325,12 +335,12 @@ uptr internal_stat(const char *path, void *buf) {  uptr internal_lstat(const char *path, void *buf) {  #if SANITIZER_NETBSD    return internal_syscall_ptr(SYSCALL(lstat), path, buf); -#elif SANITIZER_FREEBSD -  return internal_syscall(SYSCALL(fstatat), AT_FDCWD, (uptr)path, -                          (uptr)buf, AT_SYMLINK_NOFOLLOW); +#elif SANITIZER_FREEBSD || SANITIZER_OPENBSD +  return internal_syscall(SYSCALL(fstatat), AT_FDCWD, (uptr)path, (uptr)buf, +                          AT_SYMLINK_NOFOLLOW);  #elif SANITIZER_USES_CANONICAL_LINUX_SYSCALLS -  return internal_syscall(SYSCALL(newfstatat), AT_FDCWD, (uptr)path, -                         (uptr)buf, AT_SYMLINK_NOFOLLOW); +  return internal_syscall(SYSCALL(newfstatat), AT_FDCWD, (uptr)path, (uptr)buf, +                          AT_SYMLINK_NOFOLLOW);  #elif SANITIZER_LINUX_USES_64BIT_SYSCALLS  # if SANITIZER_MIPS64    // For mips64, lstat syscall fills buffer in the format of kernel_stat @@ -350,8 +360,9 @@ uptr internal_lstat(const char *path, void *buf) {  }  uptr internal_fstat(fd_t fd, void *buf) { -#if SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_LINUX_USES_64BIT_SYSCALLS -# if SANITIZER_MIPS64 && !SANITIZER_NETBSD +#if SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_OPENBSD ||              \ +    SANITIZER_LINUX_USES_64BIT_SYSCALLS +#if SANITIZER_MIPS64 && !SANITIZER_NETBSD && !SANITIZER_OPENBSD    // For mips64, fstat syscall fills buffer in the format of kernel_stat    struct kernel_stat kbuf;    int res = internal_syscall(SYSCALL(fstat), fd, &kbuf); @@ -385,15 +396,18 @@ uptr internal_dup2(int oldfd, int newfd) {  uptr internal_readlink(const char *path, char *buf, uptr bufsize) {  #if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS -  return internal_syscall(SYSCALL(readlinkat), AT_FDCWD, -                          (uptr)path, (uptr)buf, bufsize); +  return internal_syscall(SYSCALL(readlinkat), AT_FDCWD, (uptr)path, (uptr)buf, +                          bufsize); +#elif SANITIZER_OPENBSD +  return internal_syscall_ptr(SYSCALL(readlinkat), AT_FDCWD, (uptr)path, +                              (uptr)buf, bufsize);  #else    return internal_syscall_ptr(SYSCALL(readlink), path, buf, bufsize);  #endif  }  uptr internal_unlink(const char *path) { -#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS +#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS || SANITIZER_OPENBSD    return internal_syscall(SYSCALL(unlinkat), AT_FDCWD, (uptr)path, 0);  #else    return internal_syscall_ptr(SYSCALL(unlink), (uptr)path); @@ -401,7 +415,7 @@ uptr internal_unlink(const char *path) {  }  uptr internal_rename(const char *oldpath, const char *newpath) { -#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS +#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS || SANITIZER_OPENBSD    return internal_syscall(SYSCALL(renameat), AT_FDCWD, (uptr)oldpath, AT_FDCWD,                            (uptr)newpath);  #else @@ -414,7 +428,7 @@ uptr internal_sched_yield() {  }  void internal__exit(int exitcode) { -#if SANITIZER_FREEBSD || SANITIZER_NETBSD +#if SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_OPENBSD    internal_syscall(SYSCALL(exit), exitcode);  #else    internal_syscall(SYSCALL(exit_group), exitcode); @@ -434,7 +448,7 @@ unsigned int internal_sleep(unsigned int seconds) {  uptr internal_execve(const char *filename, char *const argv[],                       char *const envp[]) {    return internal_syscall_ptr(SYSCALL(execve), (uptr)filename, (uptr)argv, -                          (uptr)envp); +                              (uptr)envp);  }  #endif // !SANITIZER_SOLARIS @@ -453,11 +467,15 @@ bool FileExists(const char *filename) {  tid_t GetTid() {  #if SANITIZER_FREEBSD -  return (uptr)pthread_self(); +  long Tid; +  thr_self(&Tid); +  return Tid; +#elif SANITIZER_OPENBSD +  return internal_syscall(SYSCALL(getthrid));  #elif SANITIZER_NETBSD    return _lwp_self();  #elif SANITIZER_SOLARIS -  return (uptr)thr_self(); +  return thr_self();  #else    return internal_syscall(SYSCALL(gettid));  #endif @@ -465,7 +483,7 @@ tid_t GetTid() {  #if !SANITIZER_SOLARIS  u64 NanoTime() { -#if SANITIZER_FREEBSD || SANITIZER_NETBSD +#if SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_OPENBSD    timeval tv;  #else    kernel_timeval tv; @@ -484,7 +502,8 @@ uptr internal_clock_gettime(__sanitizer_clockid_t clk_id, void *tp) {  // 'environ' array (on some others) and does not use libc. This function  // should be called first inside __asan_init.  const char *GetEnv(const char *name) { -#if SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_SOLARIS +#if SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_OPENBSD ||              \ +    SANITIZER_SOLARIS    if (::environ != 0) {      uptr NameLen = internal_strlen(name);      for (char **Env = ::environ; *Env != 0; Env++) { @@ -522,13 +541,14 @@ const char *GetEnv(const char *name) {  #endif  } -#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD +#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD && !SANITIZER_OPENBSD  extern "C" { -  SANITIZER_WEAK_ATTRIBUTE extern void *__libc_stack_end; +SANITIZER_WEAK_ATTRIBUTE extern void *__libc_stack_end;  }  #endif -#if !SANITIZER_GO && !SANITIZER_FREEBSD && !SANITIZER_NETBSD +#if !SANITIZER_GO && !SANITIZER_FREEBSD && !SANITIZER_NETBSD &&                \ +    !SANITIZER_OPENBSD  static void ReadNullSepFileToArray(const char *path, char ***arr,                                     int arr_size) {    char *buff; @@ -553,6 +573,7 @@ static void ReadNullSepFileToArray(const char *path, char ***arr,  }  #endif +#if !SANITIZER_OPENBSD  static void GetArgsAndEnv(char ***argv, char ***envp) {  #if SANITIZER_FREEBSD    // On FreeBSD, retrieving the argument and environment arrays is done via the @@ -568,11 +589,11 @@ static void GetArgsAndEnv(char ***argv, char ***envp) {    *envp = pss->ps_envstr;  #elif SANITIZER_NETBSD    *argv = __ps_strings->ps_argvstr; -  *argv = __ps_strings->ps_envstr; -#else +  *envp = __ps_strings->ps_envstr; +#else // SANITIZER_FREEBSD  #if !SANITIZER_GO    if (&__libc_stack_end) { -#endif +#endif // !SANITIZER_GO      uptr* stack_end = (uptr*)__libc_stack_end;      int argc = *stack_end;      *argv = (char**)(stack_end + 1); @@ -583,8 +604,8 @@ static void GetArgsAndEnv(char ***argv, char ***envp) {      ReadNullSepFileToArray("/proc/self/cmdline", argv, kMaxArgv);      ReadNullSepFileToArray("/proc/self/environ", envp, kMaxEnvp);    } -#endif -#endif +#endif // !SANITIZER_GO +#endif // SANITIZER_FREEBSD  }  char **GetArgv() { @@ -619,6 +640,7 @@ void ReExec() {    Printf("execve failed, errno %d\n", rverrno);    Die();  } +#endif  #if !SANITIZER_SOLARIS  enum MutexState { @@ -672,7 +694,7 @@ void BlockingMutex::CheckLocked() {  // The actual size of this structure is specified by d_reclen.  // Note that getdents64 uses a different structure format. We only provide the  // 32-bit syscall here. -#if SANITIZER_NETBSD +#if SANITIZER_NETBSD || SANITIZER_OPENBSD  // struct dirent is different for Linux and us. At this moment, we use only  // d_fileno (Linux call this d_ino), d_reclen, and d_name.  struct linux_dirent { @@ -825,19 +847,18 @@ int internal_sigaction_syscall(int signum, const void *act, void *oldact) {    __sanitizer_sigaction u_adjust;    internal_memcpy(&u_adjust, act, sizeof(u_adjust));  #if !SANITIZER_ANDROID || !SANITIZER_MIPS32 -    if (u_adjust.sa_restorer == nullptr) { -      u_adjust.sa_restorer = internal_sigreturn; -    } +  if (u_adjust.sa_restorer == nullptr) { +    u_adjust.sa_restorer = internal_sigreturn; +  }  #endif -    return internal_sigaction_norestorer(signum, (const void *)&u_adjust, -                                         oldact); +  return internal_sigaction_norestorer(signum, (const void *)&u_adjust, oldact);  } -#endif // defined(__x86_64__) && !SANITIZER_GO +#endif  // defined(__x86_64__) && !SANITIZER_GO  #endif  // SANITIZER_LINUX  uptr internal_sigprocmask(int how, __sanitizer_sigset_t *set, -    __sanitizer_sigset_t *oldset) { -#if SANITIZER_FREEBSD || SANITIZER_NETBSD +                          __sanitizer_sigset_t *oldset) { +#if SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_OPENBSD    return internal_syscall_ptr(SYSCALL(sigprocmask), how, set, oldset);  #else    __sanitizer_kernel_sigset_t *k_set = (__sanitizer_kernel_sigset_t *)set; @@ -880,71 +901,90 @@ bool internal_sigismember(__sanitizer_sigset_t *set, int signum) {  #endif // !SANITIZER_SOLARIS  // ThreadLister implementation. -ThreadLister::ThreadLister(int pid) -  : pid_(pid), -    descriptor_(-1), -    buffer_(4096), -    error_(true), -    entry_((struct linux_dirent *)buffer_.data()), -    bytes_read_(0) { +ThreadLister::ThreadLister(pid_t pid) : pid_(pid), buffer_(4096) {    char task_directory_path[80];    internal_snprintf(task_directory_path, sizeof(task_directory_path),                      "/proc/%d/task/", pid); -  uptr openrv = internal_open(task_directory_path, O_RDONLY | O_DIRECTORY); -  if (internal_iserror(openrv)) { -    error_ = true; +  descriptor_ = internal_open(task_directory_path, O_RDONLY | O_DIRECTORY); +  if (internal_iserror(descriptor_)) {      Report("Can't open /proc/%d/task for reading.\n", pid); -  } else { -    error_ = false; -    descriptor_ = openrv;    }  } -int ThreadLister::GetNextTID() { -  int tid = -1; -  do { -    if (error_) -      return -1; -    if ((char *)entry_ >= &buffer_[bytes_read_] && !GetDirectoryEntries()) -      return -1; -    if (entry_->d_ino != 0 && entry_->d_name[0] >= '0' && -        entry_->d_name[0] <= '9') { -      // Found a valid tid. -      tid = (int)internal_atoll(entry_->d_name); +ThreadLister::Result ThreadLister::ListThreads( +    InternalMmapVector<tid_t> *threads) { +  if (internal_iserror(descriptor_)) +    return Error; +  internal_lseek(descriptor_, 0, SEEK_SET); +  threads->clear(); + +  Result result = Ok; +  for (bool first_read = true;; first_read = false) { +    // Resize to max capacity if it was downsized by IsAlive. +    buffer_.resize(buffer_.capacity()); +    CHECK_GE(buffer_.size(), 4096); +    uptr read = internal_getdents( +        descriptor_, (struct linux_dirent *)buffer_.data(), buffer_.size()); +    if (!read) +      return result; +    if (internal_iserror(read)) { +      Report("Can't read directory entries from /proc/%d/task.\n", pid_); +      return Error;      } -    entry_ = (struct linux_dirent *)(((char *)entry_) + entry_->d_reclen); -  } while (tid < 0); -  return tid; -} -void ThreadLister::Reset() { -  if (error_ || descriptor_ < 0) -    return; -  internal_lseek(descriptor_, 0, SEEK_SET); -} +    for (uptr begin = (uptr)buffer_.data(), end = begin + read; begin < end;) { +      struct linux_dirent *entry = (struct linux_dirent *)begin; +      begin += entry->d_reclen; +      if (entry->d_ino == 1) { +        // Inode 1 is for bad blocks and also can be a reason for early return. +        // Should be emitted if kernel tried to output terminating thread. +        // See proc_task_readdir implementation in Linux. +        result = Incomplete; +      } +      if (entry->d_ino && *entry->d_name >= '0' && *entry->d_name <= '9') +        threads->push_back(internal_atoll(entry->d_name)); +    } -ThreadLister::~ThreadLister() { -  if (descriptor_ >= 0) -    internal_close(descriptor_); +    // Now we are going to detect short-read or early EOF. In such cases Linux +    // can return inconsistent list with missing alive threads. +    // Code will just remember that the list can be incomplete but it will +    // continue reads to return as much as possible. +    if (!first_read) { +      // The first one was a short-read by definition. +      result = Incomplete; +    } else if (read > buffer_.size() - 1024) { +      // Read was close to the buffer size. So double the size and assume the +      // worst. +      buffer_.resize(buffer_.size() * 2); +      result = Incomplete; +    } else if (!threads->empty() && !IsAlive(threads->back())) { +      // Maybe Linux early returned from read on terminated thread (!pid_alive) +      // and failed to restore read position. +      // See next_tid and proc_task_instantiate in Linux. +      result = Incomplete; +    } +  }  } -bool ThreadLister::error() { return error_; } - -bool ThreadLister::GetDirectoryEntries() { -  CHECK_GE(descriptor_, 0); -  CHECK_NE(error_, true); -  bytes_read_ = internal_getdents(descriptor_, -                                  (struct linux_dirent *)buffer_.data(), -                                  buffer_.size()); -  if (internal_iserror(bytes_read_)) { -    Report("Can't read directory entries from /proc/%d/task.\n", pid_); -    error_ = true; +bool ThreadLister::IsAlive(int tid) { +  // /proc/%d/task/%d/status uses same call to detect alive threads as +  // proc_task_readdir. See task_state implementation in Linux. +  char path[80]; +  internal_snprintf(path, sizeof(path), "/proc/%d/task/%d/status", pid_, tid); +  if (!ReadFileToVector(path, &buffer_) || buffer_.empty())      return false; -  } else if (bytes_read_ == 0) { +  buffer_.push_back(0); +  static const char kPrefix[] = "\nPPid:"; +  const char *field = internal_strstr(buffer_.data(), kPrefix); +  if (!field)      return false; -  } -  entry_ = (struct linux_dirent *)buffer_.data(); -  return true; +  field += internal_strlen(kPrefix); +  return (int)internal_atoll(field) != 0; +} + +ThreadLister::~ThreadLister() { +  if (!internal_iserror(descriptor_)) +    internal_close(descriptor_);  }  #if SANITIZER_WORDSIZE == 32 @@ -983,7 +1023,7 @@ static uptr GetKernelAreaSize() {  #endif  // SANITIZER_WORDSIZE == 32  uptr GetMaxVirtualAddress() { -#if SANITIZER_NETBSD && defined(__x86_64__) +#if (SANITIZER_NETBSD || SANITIZER_OPENBSD) && defined(__x86_64__)    return 0x7f7ffffff000ULL;  // (0x00007f8000000000 - PAGE_SIZE)  #elif SANITIZER_WORDSIZE == 64  # if defined(__powerpc64__) || defined(__aarch64__) @@ -1034,6 +1074,7 @@ uptr GetPageSize() {  #endif  } +#if !SANITIZER_OPENBSD  uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) {  #if SANITIZER_SOLARIS    const char *default_module_name = getexecname(); @@ -1069,6 +1110,7 @@ uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) {    return module_name_len;  #endif  } +#endif // !SANITIZER_OPENBSD  uptr ReadLongProcessName(/*out*/ char *buf, uptr buf_len) {  #if SANITIZER_LINUX @@ -1101,10 +1143,10 @@ bool LibraryNameIs(const char *full_name, const char *base_name) {  // Call cb for each region mapped by map.  void ForEachMappedRegion(link_map *map, void (*cb)(const void *, uptr)) {    CHECK_NE(map, nullptr); -#if !SANITIZER_FREEBSD +#if !SANITIZER_FREEBSD && !SANITIZER_OPENBSD    typedef ElfW(Phdr) Elf_Phdr;    typedef ElfW(Ehdr) Elf_Ehdr; -#endif  // !SANITIZER_FREEBSD +#endif // !SANITIZER_FREEBSD && !SANITIZER_OPENBSD    char *base = (char *)map->l_addr;    Elf_Ehdr *ehdr = (Elf_Ehdr *)base;    char *phdrs = base + ehdr->e_phoff; @@ -1618,6 +1660,8 @@ static HandleSignalMode GetHandleSignalModeImpl(int signum) {        return common_flags()->handle_abort;      case SIGILL:        return common_flags()->handle_sigill; +    case SIGTRAP: +      return common_flags()->handle_sigtrap;      case SIGFPE:        return common_flags()->handle_sigfpe;      case SIGSEGV: @@ -1684,21 +1728,78 @@ static bool Aarch64GetESR(ucontext_t *ucontext, u64 *esr) {  }  #endif +#if SANITIZER_OPENBSD +using Context = sigcontext; +#else +using Context = ucontext_t; +#endif +  SignalContext::WriteFlag SignalContext::GetWriteFlag() const { -  ucontext_t *ucontext = (ucontext_t *)context; +  Context *ucontext = (Context *)context;  #if defined(__x86_64__) || defined(__i386__)    static const uptr PF_WRITE = 1U << 1;  #if SANITIZER_FREEBSD    uptr err = ucontext->uc_mcontext.mc_err;  #elif SANITIZER_NETBSD    uptr err = ucontext->uc_mcontext.__gregs[_REG_ERR]; +#elif SANITIZER_OPENBSD +  uptr err = ucontext->sc_err;  #elif SANITIZER_SOLARIS && defined(__i386__) -# define ERR 13 -  uptr err = ucontext->uc_mcontext.gregs[ERR]; +  const int Err = 13; +  uptr err = ucontext->uc_mcontext.gregs[Err];  #else    uptr err = ucontext->uc_mcontext.gregs[REG_ERR]; -#endif +#endif // SANITIZER_FREEBSD    return err & PF_WRITE ? WRITE : READ; +#elif defined(__mips__) +  uint32_t *exception_source; +  uint32_t faulty_instruction; +  uint32_t op_code; + +  exception_source = (uint32_t *)ucontext->uc_mcontext.pc; +  faulty_instruction = (uint32_t)(*exception_source); + +  op_code = (faulty_instruction >> 26) & 0x3f; + +  // FIXME: Add support for FPU, microMIPS, DSP, MSA memory instructions. +  switch (op_code) { +    case 0x28:  // sb +    case 0x29:  // sh +    case 0x2b:  // sw +    case 0x3f:  // sd +#if __mips_isa_rev < 6 +    case 0x2c:  // sdl +    case 0x2d:  // sdr +    case 0x2a:  // swl +    case 0x2e:  // swr +#endif +      return SignalContext::WRITE; + +    case 0x20:  // lb +    case 0x24:  // lbu +    case 0x21:  // lh +    case 0x25:  // lhu +    case 0x23:  // lw +    case 0x27:  // lwu +    case 0x37:  // ld +#if __mips_isa_rev < 6 +    case 0x1a:  // ldl +    case 0x1b:  // ldr +    case 0x22:  // lwl +    case 0x26:  // lwr +#endif +      return SignalContext::READ; +#if __mips_isa_rev == 6 +    case 0x3b:  // pcrel +      op_code = (faulty_instruction >> 19) & 0x3; +      switch (op_code) { +        case 0x1:  // lwpc +        case 0x2:  // lwupc +          return SignalContext::READ; +      } +#endif +  } +  return SignalContext::UNKNOWN;  #elif defined(__arm__)    static const uptr FSR_WRITE = 1U << 11;    uptr fsr = ucontext->uc_mcontext.error_code; @@ -1725,7 +1826,13 @@ void SignalContext::DumpAllRegisters(void *context) {  }  static void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) { -#if defined(__arm__) +#if SANITIZER_NETBSD +  // This covers all NetBSD architectures +  ucontext_t *ucontext = (ucontext_t *)context; +  *pc = _UC_MACHINE_PC(ucontext); +  *bp = _UC_MACHINE_FP(ucontext); +  *sp = _UC_MACHINE_SP(ucontext); +#elif defined(__arm__)    ucontext_t *ucontext = (ucontext_t*)context;    *pc = ucontext->uc_mcontext.arm_pc;    *bp = ucontext->uc_mcontext.arm_fp; @@ -1747,11 +1854,11 @@ static void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) {    *pc = ucontext->uc_mcontext.mc_rip;    *bp = ucontext->uc_mcontext.mc_rbp;    *sp = ucontext->uc_mcontext.mc_rsp; -#elif SANITIZER_NETBSD -  ucontext_t *ucontext = (ucontext_t *)context; -  *pc = ucontext->uc_mcontext.__gregs[_REG_RIP]; -  *bp = ucontext->uc_mcontext.__gregs[_REG_RBP]; -  *sp = ucontext->uc_mcontext.__gregs[_REG_RSP]; +#elif SANITIZER_OPENBSD +  sigcontext *ucontext = (sigcontext *)context; +  *pc = ucontext->sc_rip; +  *bp = ucontext->sc_rbp; +  *sp = ucontext->sc_rsp;  # else    ucontext_t *ucontext = (ucontext_t*)context;    *pc = ucontext->uc_mcontext.gregs[REG_RIP]; @@ -1764,11 +1871,11 @@ static void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) {    *pc = ucontext->uc_mcontext.mc_eip;    *bp = ucontext->uc_mcontext.mc_ebp;    *sp = ucontext->uc_mcontext.mc_esp; -#elif SANITIZER_NETBSD -  ucontext_t *ucontext = (ucontext_t *)context; -  *pc = ucontext->uc_mcontext.__gregs[_REG_EIP]; -  *bp = ucontext->uc_mcontext.__gregs[_REG_EBP]; -  *sp = ucontext->uc_mcontext.__gregs[_REG_ESP]; +#elif SANITIZER_OPENBSD +  sigcontext *ucontext = (sigcontext *)context; +  *pc = ucontext->sc_eip; +  *bp = ucontext->sc_ebp; +  *sp = ucontext->sc_esp;  # else    ucontext_t *ucontext = (ucontext_t*)context;  # if SANITIZER_SOLARIS @@ -1843,6 +1950,30 @@ void MaybeReexec() {    // No need to re-exec on Linux.  } +void CheckASLR() { +#if SANITIZER_NETBSD +  int mib[3]; +  int paxflags; +  size_t len = sizeof(paxflags); + +  mib[0] = CTL_PROC; +  mib[1] = internal_getpid(); +  mib[2] = PROC_PID_PAXFLAGS; + +  if (UNLIKELY(sysctl(mib, 3, &paxflags, &len, NULL, 0) == -1)) { +    Printf("sysctl failed\n"); +    Die(); +  } + +  if (UNLIKELY(paxflags & CTL_PROC_PAXFLAGS_ASLR)) { +    Printf("This sanitizer is not compatible with enabled ASLR\n"); +    Die(); +  } +#else +  // Do nothing +#endif +} +  void PrintModuleMap() { }  void CheckNoDeepBind(const char *filename, int flag) { @@ -1861,7 +1992,8 @@ void CheckNoDeepBind(const char *filename, int flag) {  }  uptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding, -                              uptr *largest_gap_found) { +                              uptr *largest_gap_found, +                              uptr *max_occupied_addr) {    UNREACHABLE("FindAvailableMemoryRange is not available");    return 0;  } @@ -1869,6 +2001,15 @@ uptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding,  bool GetRandom(void *buffer, uptr length, bool blocking) {    if (!buffer || !length || length > 256)      return false; +#if SANITIZER_USE_GETENTROPY +  uptr rnd = getentropy(buffer, length); +  int rverrno = 0; +  if (internal_iserror(rnd, &rverrno) && rverrno == EFAULT) +    return false; +  else if (rnd == 0) +    return true; +#endif // SANITIZER_USE_GETENTROPY +  #if SANITIZER_USE_GETRANDOM    static atomic_uint8_t skip_getrandom_syscall;    if (!atomic_load_relaxed(&skip_getrandom_syscall)) { @@ -1881,7 +2022,7 @@ bool GetRandom(void *buffer, uptr length, bool blocking) {      else if (res == length)        return true;    } -#endif  // SANITIZER_USE_GETRANDOM +#endif // SANITIZER_USE_GETRANDOM    // Up to 256 bytes, a read off /dev/urandom will not be interrupted.    // blocking is moot here, O_NONBLOCK has no effect when opening /dev/urandom.    uptr fd = internal_open("/dev/urandom", O_RDONLY); @@ -1896,6 +2037,4 @@ bool GetRandom(void *buffer, uptr length, bool blocking) {  } // namespace __sanitizer -#endif  // SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || -        // SANITIZER_SOLARIS - +#endif diff --git a/lib/sanitizer_common/sanitizer_linux.h b/lib/sanitizer_common/sanitizer_linux.h index 2d227f82a99e4..975d6541d88a1 100644 --- a/lib/sanitizer_common/sanitizer_linux.h +++ b/lib/sanitizer_common/sanitizer_linux.h @@ -14,11 +14,12 @@  #define SANITIZER_LINUX_H  #include "sanitizer_platform.h" -#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \ -    SANITIZER_SOLARIS +#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD ||                \ +    SANITIZER_OPENBSD || SANITIZER_SOLARIS  #include "sanitizer_common.h"  #include "sanitizer_internal_defs.h"  #include "sanitizer_platform_limits_netbsd.h" +#include "sanitizer_platform_limits_openbsd.h"  #include "sanitizer_platform_limits_posix.h"  #include "sanitizer_platform_limits_solaris.h"  #include "sanitizer_posix.h" @@ -73,23 +74,21 @@ uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,  // This class reads thread IDs from /proc/<pid>/task using only syscalls.  class ThreadLister {   public: -  explicit ThreadLister(int pid); +  explicit ThreadLister(pid_t pid);    ~ThreadLister(); -  // GetNextTID returns -1 if the list of threads is exhausted, or if there has -  // been an error. -  int GetNextTID(); -  void Reset(); -  bool error(); +  enum Result { +    Error, +    Incomplete, +    Ok, +  }; +  Result ListThreads(InternalMmapVector<tid_t> *threads);   private: -  bool GetDirectoryEntries(); - -  int pid_; -  int descriptor_; -  InternalScopedBuffer<char> buffer_; -  bool error_; -  struct linux_dirent* entry_; -  int bytes_read_; +  bool IsAlive(int tid); + +  pid_t pid_; +  int descriptor_ = -1; +  InternalMmapVector<char> buffer_;  };  // Exposed for testing. @@ -145,6 +144,5 @@ ALWAYS_INLINE uptr *get_android_tls_ptr() {  }  // namespace __sanitizer -#endif  // SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || -        // SANITIZER_SOLARIS +#endif  #endif  // SANITIZER_LINUX_H diff --git a/lib/sanitizer_common/sanitizer_linux_libcdep.cc b/lib/sanitizer_common/sanitizer_linux_libcdep.cc index 56fdfc8705f33..1c7fb7db8844f 100644 --- a/lib/sanitizer_common/sanitizer_linux_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_linux_libcdep.cc @@ -14,8 +14,8 @@  #include "sanitizer_platform.h" -#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \ -    SANITIZER_SOLARIS +#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD ||                \ +    SANITIZER_OPENBSD || SANITIZER_SOLARIS  #include "sanitizer_allocator_internal.h"  #include "sanitizer_atomic.h" @@ -26,7 +26,6 @@  #include "sanitizer_linux.h"  #include "sanitizer_placement_new.h"  #include "sanitizer_procmaps.h" -#include "sanitizer_stacktrace.h"  #include <dlfcn.h>  // for dlsym()  #include <link.h> @@ -42,6 +41,11 @@  #define pthread_getattr_np pthread_attr_get_np  #endif +#if SANITIZER_OPENBSD +#include <pthread_np.h> +#include <sys/sysctl.h> +#endif +  #if SANITIZER_NETBSD  #include <sys/sysctl.h>  #include <sys/tls.h> @@ -51,10 +55,6 @@  #include <thread.h>  #endif -#if SANITIZER_LINUX -#include <sys/prctl.h> -#endif -  #if SANITIZER_ANDROID  #include <android/api-level.h>  #if !defined(CPU_COUNT) && !defined(__aarch64__) @@ -127,7 +127,12 @@ void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,    CHECK_EQ(thr_stksegment(&ss), 0);    stacksize = ss.ss_size;    stackaddr = (char *)ss.ss_sp - stacksize; -#else // !SANITIZER_SOLARIS +#elif SANITIZER_OPENBSD +  stack_t sattr; +  CHECK_EQ(pthread_stackseg_np(pthread_self(), &sattr), 0); +  stackaddr = sattr.ss_sp; +  stacksize = sattr.ss_size; +#else  // !SANITIZER_SOLARIS    pthread_attr_t attr;    pthread_attr_init(&attr);    CHECK_EQ(pthread_getattr_np(pthread_self(), &attr), 0); @@ -152,50 +157,98 @@ bool SetEnv(const char *name, const char *value) {  }  #endif -bool SanitizerSetThreadName(const char *name) { -#ifdef PR_SET_NAME -  return 0 == prctl(PR_SET_NAME, (unsigned long)name, 0, 0, 0);  // NOLINT -#else -  return false; -#endif -} - -bool SanitizerGetThreadName(char *name, int max_len) { -#ifdef PR_GET_NAME -  char buff[17]; -  if (prctl(PR_GET_NAME, (unsigned long)buff, 0, 0, 0))  // NOLINT +__attribute__((unused)) static bool GetLibcVersion(int *major, int *minor, +                                                   int *patch) { +#ifdef _CS_GNU_LIBC_VERSION +  char buf[64]; +  uptr len = confstr(_CS_GNU_LIBC_VERSION, buf, sizeof(buf)); +  if (len >= sizeof(buf))      return false; -  internal_strncpy(name, buff, max_len); -  name[max_len] = 0; +  buf[len] = 0; +  static const char kGLibC[] = "glibc "; +  if (internal_strncmp(buf, kGLibC, sizeof(kGLibC) - 1) != 0) +    return false; +  const char *p = buf + sizeof(kGLibC) - 1; +  *major = internal_simple_strtoll(p, &p, 10); +  *minor = (*p == '.') ? internal_simple_strtoll(p + 1, &p, 10) : 0; +  *patch = (*p == '.') ? internal_simple_strtoll(p + 1, &p, 10) : 0;    return true;  #else    return false;  #endif  } -#if !SANITIZER_FREEBSD && !SANITIZER_ANDROID && !SANITIZER_GO && \ -    !SANITIZER_NETBSD && !SANITIZER_SOLARIS +#if !SANITIZER_FREEBSD && !SANITIZER_ANDROID && !SANITIZER_GO &&               \ +    !SANITIZER_NETBSD && !SANITIZER_OPENBSD && !SANITIZER_SOLARIS  static uptr g_tls_size;  #ifdef __i386__ +# ifndef __GLIBC_PREREQ +#  define CHECK_GET_TLS_STATIC_INFO_VERSION 1 +# else +#  define CHECK_GET_TLS_STATIC_INFO_VERSION (!__GLIBC_PREREQ(2, 27)) +# endif +#else +# define CHECK_GET_TLS_STATIC_INFO_VERSION 0 +#endif + +#if CHECK_GET_TLS_STATIC_INFO_VERSION  # define DL_INTERNAL_FUNCTION __attribute__((regparm(3), stdcall))  #else  # define DL_INTERNAL_FUNCTION  #endif +namespace { +struct GetTlsStaticInfoCall { +  typedef void (*get_tls_func)(size_t*, size_t*); +}; +struct GetTlsStaticInfoRegparmCall { +  typedef void (*get_tls_func)(size_t*, size_t*) DL_INTERNAL_FUNCTION; +}; + +template <typename T> +void CallGetTls(void* ptr, size_t* size, size_t* align) { +  typename T::get_tls_func get_tls; +  CHECK_EQ(sizeof(get_tls), sizeof(ptr)); +  internal_memcpy(&get_tls, &ptr, sizeof(ptr)); +  CHECK_NE(get_tls, 0); +  get_tls(size, align); +} + +bool CmpLibcVersion(int major, int minor, int patch) { +  int ma; +  int mi; +  int pa; +  if (!GetLibcVersion(&ma, &mi, &pa)) +    return false; +  if (ma > major) +    return true; +  if (ma < major) +    return false; +  if (mi > minor) +    return true; +  if (mi < minor) +    return false; +  return pa >= patch; +} + +}  // namespace +  void InitTlsSize() { -// all current supported platforms have 16 bytes stack alignment +  // all current supported platforms have 16 bytes stack alignment    const size_t kStackAlign = 16; -  typedef void (*get_tls_func)(size_t*, size_t*) DL_INTERNAL_FUNCTION; -  get_tls_func get_tls;    void *get_tls_static_info_ptr = dlsym(RTLD_NEXT, "_dl_get_tls_static_info"); -  CHECK_EQ(sizeof(get_tls), sizeof(get_tls_static_info_ptr)); -  internal_memcpy(&get_tls, &get_tls_static_info_ptr, -                  sizeof(get_tls_static_info_ptr)); -  CHECK_NE(get_tls, 0);    size_t tls_size = 0;    size_t tls_align = 0; -  get_tls(&tls_size, &tls_align); +  // On i?86, _dl_get_tls_static_info used to be internal_function, i.e. +  // __attribute__((regparm(3), stdcall)) before glibc 2.27 and is normal +  // function in 2.27 and later. +  if (CHECK_GET_TLS_STATIC_INFO_VERSION && !CmpLibcVersion(2, 27, 0)) +    CallGetTls<GetTlsStaticInfoRegparmCall>(get_tls_static_info_ptr, +                                            &tls_size, &tls_align); +  else +    CallGetTls<GetTlsStaticInfoCall>(get_tls_static_info_ptr, +                                     &tls_size, &tls_align);    if (tls_align < kStackAlign)      tls_align = kStackAlign;    g_tls_size = RoundUpTo(tls_size, tls_align); @@ -205,77 +258,59 @@ void InitTlsSize() { }  #endif  // !SANITIZER_FREEBSD && !SANITIZER_ANDROID && !SANITIZER_GO &&          // !SANITIZER_NETBSD && !SANITIZER_SOLARIS -#if (defined(__x86_64__) || defined(__i386__) || defined(__mips__) \ -    || defined(__aarch64__) || defined(__powerpc64__) || defined(__s390__) \ -    || defined(__arm__)) && SANITIZER_LINUX && !SANITIZER_ANDROID +#if (defined(__x86_64__) || defined(__i386__) || defined(__mips__) ||          \ +     defined(__aarch64__) || defined(__powerpc64__) || defined(__s390__) ||    \ +     defined(__arm__)) &&                                                      \ +    SANITIZER_LINUX && !SANITIZER_ANDROID  // sizeof(struct pthread) from glibc. -static atomic_uintptr_t kThreadDescriptorSize; +static atomic_uintptr_t thread_descriptor_size;  uptr ThreadDescriptorSize() { -  uptr val = atomic_load(&kThreadDescriptorSize, memory_order_relaxed); +  uptr val = atomic_load_relaxed(&thread_descriptor_size);    if (val)      return val;  #if defined(__x86_64__) || defined(__i386__) || defined(__arm__) -#ifdef _CS_GNU_LIBC_VERSION -  char buf[64]; -  uptr len = confstr(_CS_GNU_LIBC_VERSION, buf, sizeof(buf)); -  if (len < sizeof(buf) && internal_strncmp(buf, "glibc 2.", 8) == 0) { -    char *end; -    int minor = internal_simple_strtoll(buf + 8, &end, 10); -    if (end != buf + 8 && (*end == '\0' || *end == '.' || *end == '-')) { -      int patch = 0; -      if (*end == '.') -        // strtoll will return 0 if no valid conversion could be performed -        patch = internal_simple_strtoll(end + 1, nullptr, 10); - -      /* sizeof(struct pthread) values from various glibc versions.  */ -      if (SANITIZER_X32) -        val = 1728;  // Assume only one particular version for x32. -      // For ARM sizeof(struct pthread) changed in Glibc 2.23. -      else if (SANITIZER_ARM) -        val = minor <= 22 ? 1120 : 1216; -      else if (minor <= 3) -        val = FIRST_32_SECOND_64(1104, 1696); -      else if (minor == 4) -        val = FIRST_32_SECOND_64(1120, 1728); -      else if (minor == 5) -        val = FIRST_32_SECOND_64(1136, 1728); -      else if (minor <= 9) -        val = FIRST_32_SECOND_64(1136, 1712); -      else if (minor == 10) -        val = FIRST_32_SECOND_64(1168, 1776); -      else if (minor == 11 || (minor == 12 && patch == 1)) -        val = FIRST_32_SECOND_64(1168, 2288); -      else if (minor <= 13) -        val = FIRST_32_SECOND_64(1168, 2304); -      else -        val = FIRST_32_SECOND_64(1216, 2304); -    } -    if (val) -      atomic_store(&kThreadDescriptorSize, val, memory_order_relaxed); -    return val; +  int major; +  int minor; +  int patch; +  if (GetLibcVersion(&major, &minor, &patch) && major == 2) { +    /* sizeof(struct pthread) values from various glibc versions.  */ +    if (SANITIZER_X32) +      val = 1728; // Assume only one particular version for x32. +    // For ARM sizeof(struct pthread) changed in Glibc 2.23. +    else if (SANITIZER_ARM) +      val = minor <= 22 ? 1120 : 1216; +    else if (minor <= 3) +      val = FIRST_32_SECOND_64(1104, 1696); +    else if (minor == 4) +      val = FIRST_32_SECOND_64(1120, 1728); +    else if (minor == 5) +      val = FIRST_32_SECOND_64(1136, 1728); +    else if (minor <= 9) +      val = FIRST_32_SECOND_64(1136, 1712); +    else if (minor == 10) +      val = FIRST_32_SECOND_64(1168, 1776); +    else if (minor == 11 || (minor == 12 && patch == 1)) +      val = FIRST_32_SECOND_64(1168, 2288); +    else if (minor <= 13) +      val = FIRST_32_SECOND_64(1168, 2304); +    else +      val = FIRST_32_SECOND_64(1216, 2304);    } -#endif  #elif defined(__mips__)    // TODO(sagarthakur): add more values as per different glibc versions.    val = FIRST_32_SECOND_64(1152, 1776); -  if (val) -    atomic_store(&kThreadDescriptorSize, val, memory_order_relaxed); -  return val;  #elif defined(__aarch64__)    // The sizeof (struct pthread) is the same from GLIBC 2.17 to 2.22.    val = 1776; -  atomic_store(&kThreadDescriptorSize, val, memory_order_relaxed); -  return val;  #elif defined(__powerpc64__)    val = 1776; // from glibc.ppc64le 2.20-8.fc21 -  atomic_store(&kThreadDescriptorSize, val, memory_order_relaxed); -  return val;  #elif defined(__s390__)    val = FIRST_32_SECOND_64(1152, 1776); // valid for glibc 2.22 -  atomic_store(&kThreadDescriptorSize, val, memory_order_relaxed);  #endif -  return 0; +  if (val) +    atomic_store_relaxed(&thread_descriptor_size, val); +  return val;  }  // The offset at which pointer to self is located in the thread descriptor. @@ -432,6 +467,9 @@ static void GetTls(uptr *addr, uptr *size) {        *addr = (uptr)tcb->tcb_dtv[1];      }    } +#elif SANITIZER_OPENBSD +  *addr = 0; +  *size = 0;  #elif SANITIZER_ANDROID    *addr = 0;    *size = 0; @@ -447,8 +485,8 @@ static void GetTls(uptr *addr, uptr *size) {  #if !SANITIZER_GO  uptr GetTlsSize() { -#if SANITIZER_FREEBSD || SANITIZER_ANDROID || SANITIZER_NETBSD || \ -    SANITIZER_SOLARIS +#if SANITIZER_FREEBSD || SANITIZER_ANDROID || SANITIZER_NETBSD ||              \ +    SANITIZER_OPENBSD || SANITIZER_SOLARIS    uptr addr, size;    GetTls(&addr, &size);    return size; @@ -485,13 +523,13 @@ void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,  #endif  } -# if !SANITIZER_FREEBSD +#if !SANITIZER_FREEBSD && !SANITIZER_OPENBSD  typedef ElfW(Phdr) Elf_Phdr; -# elif SANITIZER_WORDSIZE == 32 && __FreeBSD_version <= 902001  // v9.2 -#  define Elf_Phdr XElf32_Phdr -#  define dl_phdr_info xdl_phdr_info -#  define dl_iterate_phdr(c, b) xdl_iterate_phdr((c), (b)) -# endif +#elif SANITIZER_WORDSIZE == 32 && __FreeBSD_version <= 902001 // v9.2 +#define Elf_Phdr XElf32_Phdr +#define dl_phdr_info xdl_phdr_info +#define dl_iterate_phdr(c, b) xdl_iterate_phdr((c), (b)) +#endif // !SANITIZER_FREEBSD && !SANITIZER_OPENBSD  struct DlIteratePhdrData {    InternalMmapVectorNoCtor<LoadedModule> *modules; @@ -512,7 +550,7 @@ static int dl_iterate_phdr_cb(dl_phdr_info *info, size_t size, void *arg) {      return 0;    LoadedModule cur_module;    cur_module.set(module_name.data(), info->dlpi_addr); -  for (int i = 0; i < info->dlpi_phnum; i++) { +  for (int i = 0; i < (int)info->dlpi_phnum; i++) {      const Elf_Phdr *phdr = &info->dlpi_phdr[i];      if (phdr->p_type == PT_LOAD) {        uptr cur_beg = info->dlpi_addr + phdr->p_vaddr; @@ -611,7 +649,7 @@ uptr GetRSS() {  // sysconf(_SC_NPROCESSORS_{CONF,ONLN}) cannot be used on most platforms as  // they allocate memory.  u32 GetNumberOfCPUs() { -#if SANITIZER_FREEBSD || SANITIZER_NETBSD +#if SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_OPENBSD    u32 ncpu;    int req[2];    size_t len = sizeof(ncpu); @@ -628,7 +666,7 @@ u32 GetNumberOfCPUs() {    uptr fd = internal_open("/sys/devices/system/cpu", O_RDONLY | O_DIRECTORY);    if (internal_iserror(fd))      return 0; -  InternalScopedBuffer<u8> buffer(4096); +  InternalMmapVector<u8> buffer(4096);    uptr bytes_read = buffer.size();    uptr n_cpus = 0;    u8 *d_type; @@ -770,4 +808,4 @@ u64 MonotonicNanoTime() {  } // namespace __sanitizer -#endif  // SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD +#endif diff --git a/lib/sanitizer_common/sanitizer_linux_s390.cc b/lib/sanitizer_common/sanitizer_linux_s390.cc index a6da82ecb1d23..ad8c87f2d6b6a 100644 --- a/lib/sanitizer_common/sanitizer_linux_s390.cc +++ b/lib/sanitizer_common/sanitizer_linux_s390.cc @@ -126,7 +126,7 @@ static bool FixedCVE_2016_2143() {    // This should never fail, but just in case...    if (uname(&buf))      return false; -  char *ptr = buf.release; +  const char *ptr = buf.release;    major = internal_simple_strtoll(ptr, &ptr, 10);    // At least first 2 should be matched.    if (ptr[0] != '.') diff --git a/lib/sanitizer_common/sanitizer_mac.cc b/lib/sanitizer_common/sanitizer_mac.cc index e1c51f5808740..180d7c199aef8 100644 --- a/lib/sanitizer_common/sanitizer_mac.cc +++ b/lib/sanitizer_common/sanitizer_mac.cc @@ -59,7 +59,9 @@ extern "C" {  #include <libkern/OSAtomic.h>  #include <mach-o/dyld.h>  #include <mach/mach.h> +#include <mach/mach_time.h>  #include <mach/vm_statistics.h> +#include <malloc/malloc.h>  #include <pthread.h>  #include <sched.h>  #include <signal.h> @@ -100,9 +102,15 @@ extern "C" void *__mmap(void *addr, size_t len, int prot, int flags, int fildes,  extern "C" int __munmap(void *, size_t) SANITIZER_WEAK_ATTRIBUTE;  // ---------------------- sanitizer_libc.h + +// From <mach/vm_statistics.h>, but not on older OSs. +#ifndef VM_MEMORY_SANITIZER +#define VM_MEMORY_SANITIZER 99 +#endif +  uptr internal_mmap(void *addr, size_t length, int prot, int flags,                     int fd, u64 offset) { -  if (fd == -1) fd = VM_MAKE_TAG(VM_MEMORY_ANALYSIS_TOOL); +  if (fd == -1) fd = VM_MAKE_TAG(VM_MEMORY_SANITIZER);    if (&__mmap) return (uptr)__mmap(addr, length, prot, flags, fd, offset);    return (uptr)mmap(addr, length, prot, flags, fd, offset);  } @@ -338,10 +346,37 @@ void ReExec() {    UNIMPLEMENTED();  } +void CheckASLR() { +  // Do nothing +} +  uptr GetPageSize() {    return sysconf(_SC_PAGESIZE);  } +extern "C" unsigned malloc_num_zones; +extern "C" malloc_zone_t **malloc_zones; +malloc_zone_t sanitizer_zone; + +// We need to make sure that sanitizer_zone is registered as malloc_zones[0]. If +// libmalloc tries to set up a different zone as malloc_zones[0], it will call +// mprotect(malloc_zones, ..., PROT_READ).  This interceptor will catch that and +// make sure we are still the first (default) zone. +void MprotectMallocZones(void *addr, int prot) { +  if (addr == malloc_zones && prot == PROT_READ) { +    if (malloc_num_zones > 1 && malloc_zones[0] != &sanitizer_zone) { +      for (unsigned i = 1; i < malloc_num_zones; i++) { +        if (malloc_zones[i] == &sanitizer_zone) { +          // Swap malloc_zones[0] and malloc_zones[i]. +          malloc_zones[i] = malloc_zones[0]; +          malloc_zones[0] = &sanitizer_zone; +          break; +        } +      } +    } +  } +} +  BlockingMutex::BlockingMutex() {    internal_memset(this, 0, sizeof(*this));  } @@ -362,11 +397,17 @@ void BlockingMutex::CheckLocked() {  }  u64 NanoTime() { -  return 0; +  timeval tv; +  internal_memset(&tv, 0, sizeof(tv)); +  gettimeofday(&tv, 0); +  return (u64)tv.tv_sec * 1000*1000*1000 + tv.tv_usec * 1000;  } +// This needs to be called during initialization to avoid being racy.  u64 MonotonicNanoTime() { -  return 0; +  static mach_timebase_info_data_t timebase_info; +  if (timebase_info.denom == 0) mach_timebase_info(&timebase_info); +  return (mach_absolute_time() * timebase_info.numer) / timebase_info.denom;  }  uptr GetTlsSize() { @@ -428,6 +469,8 @@ static HandleSignalMode GetHandleSignalModeImpl(int signum) {        return common_flags()->handle_abort;      case SIGILL:        return common_flags()->handle_sigill; +    case SIGTRAP: +      return common_flags()->handle_sigtrap;      case SIGFPE:        return common_flags()->handle_sigfpe;      case SIGSEGV: @@ -673,6 +716,9 @@ bool DyldNeedsEnvVariable() {  }  void MaybeReexec() { +  // FIXME: This should really live in some "InitializePlatform" method. +  MonotonicNanoTime(); +    if (ReexecDisabled()) return;    // Make sure the dynamic runtime library is preloaded so that the @@ -875,10 +921,9 @@ uptr GetMaxVirtualAddress() {    return GetMaxUserVirtualAddress();  } -uptr FindAvailableMemoryRange(uptr shadow_size, -                              uptr alignment, -                              uptr left_padding, -                              uptr *largest_gap_found) { +uptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding, +                              uptr *largest_gap_found, +                              uptr *max_occupied_addr) {    typedef vm_region_submap_short_info_data_64_t RegionInfo;    enum { kRegionInfoSize = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64 };    // Start searching for available memory region past PAGEZERO, which is @@ -890,6 +935,7 @@ uptr FindAvailableMemoryRange(uptr shadow_size,    mach_vm_address_t free_begin = start_address;    kern_return_t kr = KERN_SUCCESS;    if (largest_gap_found) *largest_gap_found = 0; +  if (max_occupied_addr) *max_occupied_addr = 0;    while (kr == KERN_SUCCESS) {      mach_vm_size_t vmsize = 0;      natural_t depth = 0; @@ -901,13 +947,15 @@ uptr FindAvailableMemoryRange(uptr shadow_size,        // No more regions beyond "address", consider the gap at the end of VM.        address = GetMaxVirtualAddress() + 1;        vmsize = 0; +    } else { +      if (max_occupied_addr) *max_occupied_addr = address + vmsize;      }      if (free_begin != address) {        // We found a free region [free_begin..address-1].        uptr gap_start = RoundUpTo((uptr)free_begin + left_padding, alignment);        uptr gap_end = RoundDownTo((uptr)address, alignment);        uptr gap_size = gap_end > gap_start ? gap_end - gap_start : 0; -      if (shadow_size < gap_size) { +      if (size < gap_size) {          return gap_start;        } @@ -994,9 +1042,10 @@ void FormatUUID(char *out, uptr size, const u8 *uuid) {  void PrintModuleMap() {    Printf("Process module map:\n");    MemoryMappingLayout memory_mapping(false); -  InternalMmapVector<LoadedModule> modules(/*initial_capacity*/ 128); +  InternalMmapVector<LoadedModule> modules; +  modules.reserve(128);    memory_mapping.DumpListOfModules(&modules); -  InternalSort(&modules, modules.size(), CompareBaseAddress); +  Sort(modules.data(), modules.size(), CompareBaseAddress);    for (uptr i = 0; i < modules.size(); ++i) {      char uuid_str[128];      FormatUUID(uuid_str, sizeof(uuid_str), modules[i].uuid()); diff --git a/lib/sanitizer_common/sanitizer_malloc_mac.inc b/lib/sanitizer_common/sanitizer_malloc_mac.inc index 5699c59043e9a..e69d6f94b0e13 100644 --- a/lib/sanitizer_common/sanitizer_malloc_mac.inc +++ b/lib/sanitizer_common/sanitizer_malloc_mac.inc @@ -29,7 +29,9 @@  // Similar code is used in Google Perftools,  // https://github.com/gperftools/gperftools. -static malloc_zone_t sanitizer_zone; +namespace __sanitizer { +extern malloc_zone_t sanitizer_zone; +}  INTERCEPTOR(malloc_zone_t *, malloc_create_zone,                               vm_size_t start_size, unsigned zone_flags) { @@ -65,29 +67,6 @@ INTERCEPTOR(void, malloc_destroy_zone, malloc_zone_t *zone) {    COMMON_MALLOC_FREE(zone);  } -extern unsigned malloc_num_zones; -extern malloc_zone_t **malloc_zones; - -// We need to make sure that sanitizer_zone is registered as malloc_zones[0]. If -// libmalloc tries to set up a different zone as malloc_zones[0], it will call -// mprotect(malloc_zones, ..., PROT_READ).  This interceptor will catch that and -// make sure we are still the first (default) zone. -INTERCEPTOR(int, mprotect, void *addr, size_t len, int prot) { -  if (addr == malloc_zones && prot == PROT_READ) { -    if (malloc_num_zones > 1 && malloc_zones[0] != &sanitizer_zone) { -      for (unsigned i = 1; i < malloc_num_zones; i++) { -        if (malloc_zones[i] == &sanitizer_zone) { -          // Swap malloc_zones[0] and malloc_zones[i]. -          malloc_zones[i] = malloc_zones[0]; -          malloc_zones[0] = &sanitizer_zone; -          break; -        } -      } -    } -  } -  return REAL(mprotect)(addr, len, prot); -} -  INTERCEPTOR(malloc_zone_t *, malloc_default_zone, void) {    COMMON_MALLOC_ENTER();    return &sanitizer_zone; @@ -170,12 +149,8 @@ INTERCEPTOR(size_t, malloc_good_size, size_t size) {  INTERCEPTOR(int, posix_memalign, void **memptr, size_t alignment, size_t size) {    COMMON_MALLOC_ENTER();    CHECK(memptr); -  COMMON_MALLOC_MEMALIGN(alignment, size); -  if (p) { -    *memptr = p; -    return 0; -  } -  return -1; +  COMMON_MALLOC_POSIX_MEMALIGN(memptr, alignment, size); +  return res;  }  namespace { diff --git a/lib/sanitizer_common/sanitizer_openbsd.cc b/lib/sanitizer_common/sanitizer_openbsd.cc new file mode 100644 index 0000000000000..2aea7cb148759 --- /dev/null +++ b/lib/sanitizer_common/sanitizer_openbsd.cc @@ -0,0 +1,101 @@ +//===-- sanitizer_openbsd.cc ----------------------------------------------===// +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is shared between various sanitizers' runtime libraries and +// implements Solaris-specific functions. +//===----------------------------------------------------------------------===// + +#include "sanitizer_platform.h" +#if SANITIZER_OPENBSD + +#include <stdio.h> + +#include "sanitizer_common.h" +#include "sanitizer_flags.h" +#include "sanitizer_internal_defs.h" +#include "sanitizer_libc.h" +#include "sanitizer_placement_new.h" +#include "sanitizer_platform_limits_posix.h" +#include "sanitizer_procmaps.h" + +#include <errno.h> +#include <fcntl.h> +#include <limits.h> +#include <pthread.h> +#include <sched.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/mman.h> +#include <sys/shm.h> +#include <sys/sysctl.h> +#include <sys/types.h> +#include <unistd.h> + +extern char **environ; + +namespace __sanitizer { + +uptr internal_mmap(void *addr, size_t length, int prot, int flags, int fd, +                   u64 offset) { +  return (uptr)mmap(addr, length, prot, flags, fd, offset); +} + +uptr internal_munmap(void *addr, uptr length) { return munmap(addr, length); } + +int internal_mprotect(void *addr, uptr length, int prot) { +  return mprotect(addr, length, prot); +} + +uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) { +  // On OpenBSD we cannot get the full path +  struct kinfo_proc kp; +  size_t kl; +  const int Mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, getpid()}; +  if (sysctl(Mib, ARRAY_SIZE(Mib), &kp, &kl, NULL, 0) != -1) +    return internal_snprintf(buf, +                             (KI_MAXCOMLEN < buf_len ? KI_MAXCOMLEN : buf_len), +                             "%s", kp.p_comm); +  return (uptr)0; +} + +static void GetArgsAndEnv(char ***argv, char ***envp) { +  size_t nargv; +  size_t nenv; +  int argvmib[4] = {CTL_KERN, KERN_PROC_ARGS, getpid(), KERN_PROC_ARGV}; +  int envmib[4] = {CTL_KERN, KERN_PROC_ARGS, getpid(), KERN_PROC_ENV}; +  if (sysctl(argvmib, 4, NULL, &nargv, NULL, 0) == -1) { +    Printf("sysctl KERN_PROC_NARGV failed\n"); +    Die(); +  } +  if (sysctl(envmib, 4, NULL, &nenv, NULL, 0) == -1) { +    Printf("sysctl KERN_PROC_NENV failed\n"); +    Die(); +  } +  if (sysctl(argvmib, 4, &argv, &nargv, NULL, 0) == -1) { +    Printf("sysctl KERN_PROC_ARGV failed\n"); +    Die(); +  } +  if (sysctl(envmib, 4, &envp, &nenv, NULL, 0) == -1) { +    Printf("sysctl KERN_PROC_ENV failed\n"); +    Die(); +  } +} + +char **GetArgv() { +  char **argv, **envp; +  GetArgsAndEnv(&argv, &envp); +  return argv; +} + +void ReExec() { +  UNIMPLEMENTED(); +} + +}  // namespace __sanitizer + +#endif  // SANITIZER_OPENBSD diff --git a/lib/sanitizer_common/sanitizer_platform.h b/lib/sanitizer_common/sanitizer_platform.h index 334903c26f9fe..d81e25580d9e3 100644 --- a/lib/sanitizer_common/sanitizer_platform.h +++ b/lib/sanitizer_common/sanitizer_platform.h @@ -14,7 +14,8 @@  #define SANITIZER_PLATFORM_H  #if !defined(__linux__) && !defined(__FreeBSD__) && !defined(__NetBSD__) && \ -  !defined(__APPLE__) && !defined(_WIN32) && !defined(__Fuchsia__) && \ +  !defined(__OpenBSD__) && !defined(__APPLE__) && !defined(_WIN32) && \ +  !defined(__Fuchsia__) && !defined(__rtems__) && \    !(defined(__sun__) && defined(__svr4__))  # error "This operating system is not supported"  #endif @@ -37,6 +38,12 @@  # define SANITIZER_NETBSD 0  #endif +#if defined(__OpenBSD__) +# define SANITIZER_OPENBSD 1 +#else +# define SANITIZER_OPENBSD 0 +#endif +  #if defined(__sun__) && defined(__svr4__)  # define SANITIZER_SOLARIS 1  #else @@ -98,9 +105,15 @@  # define SANITIZER_FUCHSIA 0  #endif +#if defined(__rtems__) +# define SANITIZER_RTEMS 1 +#else +# define SANITIZER_RTEMS 0 +#endif +  #define SANITIZER_POSIX \    (SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_MAC || \ -    SANITIZER_NETBSD || SANITIZER_SOLARIS) +    SANITIZER_NETBSD || SANITIZER_OPENBSD || SANITIZER_SOLARIS)  #if __LP64__ || defined(_WIN64)  #  define SANITIZER_WORDSIZE 64 @@ -195,6 +208,12 @@  # define SANITIZER_SOLARIS32 0  #endif +#if defined(__myriad2__) +# define SANITIZER_MYRIAD2 1 +#else +# define SANITIZER_MYRIAD2 0 +#endif +  // By default we allow to use SizeClassAllocator64 on 64-bit platform.  // But in some cases (e.g. AArch64's 39-bit address space) SizeClassAllocator64  // does not work well and we need to fallback to SizeClassAllocator32. @@ -296,10 +315,26 @@  # define SANITIZER_SUPPRESS_LEAK_ON_PTHREAD_EXIT 0  #endif -#if SANITIZER_FREEBSD || SANITIZER_MAC || SANITIZER_NETBSD || SANITIZER_SOLARIS +#if SANITIZER_FREEBSD || SANITIZER_MAC || SANITIZER_NETBSD || \ +  SANITIZER_OPENBSD || SANITIZER_SOLARIS  # define SANITIZER_MADVISE_DONTNEED MADV_FREE  #else  # define SANITIZER_MADVISE_DONTNEED MADV_DONTNEED  #endif +// Older gcc have issues aligning to a constexpr, and require an integer. +// See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56859 among others. +#if defined(__powerpc__) || defined(__powerpc64__) +# define SANITIZER_CACHE_LINE_SIZE 128 +#else +# define SANITIZER_CACHE_LINE_SIZE 64 +#endif + +// Enable offline markup symbolizer for Fuchsia and RTEMS. +#if SANITIZER_FUCHSIA || SANITIZER_RTEMS +#define SANITIZER_SYMBOLIZER_MARKUP 1 +#else +#define SANITIZER_SYMBOLIZER_MARKUP 0 +#endif +  #endif // SANITIZER_PLATFORM_H diff --git a/lib/sanitizer_common/sanitizer_platform_interceptors.h b/lib/sanitizer_common/sanitizer_platform_interceptors.h index b99ac4480586f..f95539a73c695 100644 --- a/lib/sanitizer_common/sanitizer_platform_interceptors.h +++ b/lib/sanitizer_common/sanitizer_platform_interceptors.h @@ -28,12 +28,13 @@  # define SI_WINDOWS 1  #endif -#if (SI_POSIX != 0) == (SI_WINDOWS != 0) && !SANITIZER_FUCHSIA +#if SI_WINDOWS && SI_POSIX  # error "Windows is not POSIX!"  #endif  #if SI_POSIX  # include "sanitizer_platform_limits_netbsd.h" +#include "sanitizer_platform_limits_openbsd.h"  # include "sanitizer_platform_limits_posix.h"  # include "sanitizer_platform_limits_solaris.h"  #endif @@ -62,6 +63,12 @@  # define SI_NETBSD 0  #endif +#if SANITIZER_OPENBSD +#define SI_OPENBSD 1 +#else +#define SI_OPENBSD 0 +#endif +  #if SANITIZER_LINUX  # define SI_LINUX 1  #else @@ -88,6 +95,12 @@  # define SI_NOT_FUCHSIA 1  #endif +#if SANITIZER_RTEMS +# define SI_NOT_RTEMS 0 +#else +# define SI_NOT_RTEMS 1 +#endif +  #if SANITIZER_SOLARIS  # define SI_SOLARIS 1  #else @@ -141,7 +154,8 @@  // FIXME: enable memmem on Windows.  #define SANITIZER_INTERCEPT_MEMMEM (SI_POSIX && !SI_MAC_DEPLOYMENT_BELOW_10_7)  #define SANITIZER_INTERCEPT_MEMCHR SI_NOT_FUCHSIA -#define SANITIZER_INTERCEPT_MEMRCHR (SI_FREEBSD || SI_LINUX || SI_NETBSD) +#define SANITIZER_INTERCEPT_MEMRCHR \ +  (SI_FREEBSD || SI_LINUX || SI_NETBSD || SI_OPENBSD)  #define SANITIZER_INTERCEPT_READ SI_POSIX  #define SANITIZER_INTERCEPT_PREAD SI_POSIX @@ -150,6 +164,9 @@  #define SANITIZER_INTERCEPT_FREAD SI_POSIX  #define SANITIZER_INTERCEPT_FWRITE SI_POSIX +#define SANITIZER_INTERCEPT_FGETS SI_POSIX +#define SANITIZER_INTERCEPT_FPUTS SI_POSIX +#define SANITIZER_INTERCEPT_PUTS SI_POSIX  #define SANITIZER_INTERCEPT_PREAD64 SI_LINUX_NOT_ANDROID || SI_SOLARIS32  #define SANITIZER_INTERCEPT_PWRITE64 SI_LINUX_NOT_ANDROID || SI_SOLARIS32 @@ -158,7 +175,7 @@  #define SANITIZER_INTERCEPT_WRITEV SI_POSIX  #define SANITIZER_INTERCEPT_PREADV \ -  (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID) +  (SI_FREEBSD || SI_NETBSD || SI_OPENBSD || SI_LINUX_NOT_ANDROID)  #define SANITIZER_INTERCEPT_PWRITEV SI_LINUX_NOT_ANDROID  #define SANITIZER_INTERCEPT_PREADV64 SI_LINUX_NOT_ANDROID  #define SANITIZER_INTERCEPT_PWRITEV64 SI_LINUX_NOT_ANDROID @@ -184,24 +201,26 @@  #define SANITIZER_INTERCEPT_FREXPF_FREXPL SI_POSIX  #define SANITIZER_INTERCEPT_GETPWNAM_AND_FRIENDS SI_POSIX -#define SANITIZER_INTERCEPT_GETPWNAM_R_AND_FRIENDS \ -  (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS) -#define SANITIZER_INTERCEPT_GETPWENT \ -  (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS) +#define SANITIZER_INTERCEPT_GETPWNAM_R_AND_FRIENDS                            \ +  (SI_FREEBSD || SI_NETBSD || SI_OPENBSD || SI_MAC || SI_LINUX_NOT_ANDROID || \ +  SI_SOLARIS) +#define SANITIZER_INTERCEPT_GETPWENT                                          \ +  (SI_FREEBSD || SI_NETBSD || SI_OPENBSD || SI_MAC || SI_LINUX_NOT_ANDROID || \ +  SI_SOLARIS)  #define SANITIZER_INTERCEPT_FGETPWENT SI_LINUX_NOT_ANDROID || SI_SOLARIS  #define SANITIZER_INTERCEPT_GETPWENT_R \ -  (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS) +  (SI_FREEBSD || SI_NETBSD || SI_OPENBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS)  #define SANITIZER_INTERCEPT_SETPWENT \    (SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS)  #define SANITIZER_INTERCEPT_CLOCK_GETTIME \ -  (SI_FREEBSD || SI_NETBSD || SI_LINUX || SI_SOLARIS) +  (SI_FREEBSD || SI_NETBSD || SI_OPENBSD || SI_LINUX || SI_SOLARIS)  #define SANITIZER_INTERCEPT_GETITIMER SI_POSIX  #define SANITIZER_INTERCEPT_TIME SI_POSIX  #define SANITIZER_INTERCEPT_GLOB SI_LINUX_NOT_ANDROID || SI_SOLARIS  #define SANITIZER_INTERCEPT_GLOB64 SI_LINUX_NOT_ANDROID  #define SANITIZER_INTERCEPT_WAIT SI_POSIX  #define SANITIZER_INTERCEPT_INET SI_POSIX -#define SANITIZER_INTERCEPT_PTHREAD_GETSCHEDPARAM SI_POSIX +#define SANITIZER_INTERCEPT_PTHREAD_GETSCHEDPARAM (SI_POSIX && !SI_OPENBSD)  #define SANITIZER_INTERCEPT_GETADDRINFO SI_POSIX  #define SANITIZER_INTERCEPT_GETNAMEINFO SI_POSIX  #define SANITIZER_INTERCEPT_GETSOCKNAME SI_POSIX @@ -217,10 +236,14 @@    (SI_FREEBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS)  #define SANITIZER_INTERCEPT_GETSOCKOPT SI_POSIX  #define SANITIZER_INTERCEPT_ACCEPT SI_POSIX -#define SANITIZER_INTERCEPT_ACCEPT4 SI_LINUX_NOT_ANDROID +#define SANITIZER_INTERCEPT_ACCEPT4 \ +  (SI_LINUX_NOT_ANDROID || SI_NETBSD || SI_OPENBSD) +#define SANITIZER_INTERCEPT_PACCEPT SI_NETBSD  #define SANITIZER_INTERCEPT_MODF SI_POSIX  #define SANITIZER_INTERCEPT_RECVMSG SI_POSIX  #define SANITIZER_INTERCEPT_SENDMSG SI_POSIX +#define SANITIZER_INTERCEPT_RECVMMSG SI_LINUX +#define SANITIZER_INTERCEPT_SENDMMSG SI_LINUX  #define SANITIZER_INTERCEPT_GETPEERNAME SI_POSIX  #define SANITIZER_INTERCEPT_IOCTL SI_POSIX  #define SANITIZER_INTERCEPT_INET_ATON SI_POSIX @@ -243,23 +266,30 @@  #define SANITIZER_INTERCEPT_MBSNRTOWCS \    (SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS)  #define SANITIZER_INTERCEPT_WCSTOMBS SI_POSIX -#define SANITIZER_INTERCEPT_WCSNRTOMBS \ -  (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS) -#define SANITIZER_INTERCEPT_WCRTOMB \ -  (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS) +#define SANITIZER_INTERCEPT_STRXFRM SI_POSIX +#define SANITIZER_INTERCEPT___STRXFRM_L SI_LINUX +#define SANITIZER_INTERCEPT_WCSXFRM SI_POSIX +#define SANITIZER_INTERCEPT___WCSXFRM_L SI_LINUX +#define SANITIZER_INTERCEPT_WCSNRTOMBS                                        \ +  (SI_FREEBSD || SI_NETBSD || SI_OPENBSD || SI_MAC || SI_LINUX_NOT_ANDROID || \ +  SI_SOLARIS) +#define SANITIZER_INTERCEPT_WCRTOMB                                           \ +  (SI_FREEBSD || SI_NETBSD || SI_OPENBSD || SI_MAC || SI_LINUX_NOT_ANDROID || \ +  SI_SOLARIS)  #define SANITIZER_INTERCEPT_TCGETATTR SI_LINUX_NOT_ANDROID || SI_SOLARIS  #define SANITIZER_INTERCEPT_REALPATH SI_POSIX  #define SANITIZER_INTERCEPT_CANONICALIZE_FILE_NAME \    (SI_LINUX_NOT_ANDROID || SI_SOLARIS) -#define SANITIZER_INTERCEPT_CONFSTR \ -  (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS) +#define SANITIZER_INTERCEPT_CONFSTR                                           \ +  (SI_FREEBSD || SI_NETBSD || SI_OPENBSD || SI_MAC || SI_LINUX_NOT_ANDROID || \ +  SI_SOLARIS)  #define SANITIZER_INTERCEPT_SCHED_GETAFFINITY SI_LINUX_NOT_ANDROID  #define SANITIZER_INTERCEPT_SCHED_GETPARAM SI_LINUX_NOT_ANDROID || SI_SOLARIS  #define SANITIZER_INTERCEPT_STRERROR SI_POSIX  #define SANITIZER_INTERCEPT_STRERROR_R SI_POSIX  #define SANITIZER_INTERCEPT_XPG_STRERROR_R SI_LINUX_NOT_ANDROID  #define SANITIZER_INTERCEPT_SCANDIR \ -  (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS) +  (SI_FREEBSD || SI_NETBSD || SI_OPENBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS)  #define SANITIZER_INTERCEPT_SCANDIR64 SI_LINUX_NOT_ANDROID || SI_SOLARIS32  #define SANITIZER_INTERCEPT_GETGROUPS SI_POSIX  #define SANITIZER_INTERCEPT_POLL SI_POSIX @@ -275,7 +305,7 @@  #define SANITIZER_INTERCEPT_SIGPENDING SI_POSIX  #define SANITIZER_INTERCEPT_SIGPROCMASK SI_POSIX  #define SANITIZER_INTERCEPT_BACKTRACE \ -  (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS) +  (SI_FREEBSD || SI_NETBSD || SI_OPENBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS)  #define SANITIZER_INTERCEPT_GETMNTENT SI_LINUX  #define SANITIZER_INTERCEPT_GETMNTENT_R SI_LINUX_NOT_ANDROID  #define SANITIZER_INTERCEPT_STATFS \ @@ -283,24 +313,26 @@  #define SANITIZER_INTERCEPT_STATFS64 \    ((SI_MAC && !SI_IOS) || SI_LINUX_NOT_ANDROID)  #define SANITIZER_INTERCEPT_STATVFS \ -  (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID) +  (SI_FREEBSD || SI_NETBSD || SI_OPENBSD || SI_LINUX_NOT_ANDROID)  #define SANITIZER_INTERCEPT_STATVFS64 SI_LINUX_NOT_ANDROID  #define SANITIZER_INTERCEPT_INITGROUPS SI_POSIX -#define SANITIZER_INTERCEPT_ETHER_NTOA_ATON SI_POSIX +#define SANITIZER_INTERCEPT_ETHER_NTOA_ATON (SI_POSIX && !SI_OPENBSD)  #define SANITIZER_INTERCEPT_ETHER_HOST \    (SI_FREEBSD || SI_MAC || SI_LINUX_NOT_ANDROID)  #define SANITIZER_INTERCEPT_ETHER_R (SI_FREEBSD || SI_LINUX_NOT_ANDROID) -#define SANITIZER_INTERCEPT_SHMCTL                       \ -  (SI_NETBSD || SI_SOLARIS || ((SI_FREEBSD || SI_LINUX_NOT_ANDROID) && \ -                 SANITIZER_WORDSIZE == 64))  // NOLINT +#define SANITIZER_INTERCEPT_SHMCTL          \ +  (SI_NETBSD || SI_OPENBSD || SI_SOLARIS || \ +  ((SI_FREEBSD || SI_LINUX_NOT_ANDROID) && \ +    SANITIZER_WORDSIZE == 64))  // NOLINT  #define SANITIZER_INTERCEPT_RANDOM_R SI_LINUX_NOT_ANDROID  #define SANITIZER_INTERCEPT_PTHREAD_ATTR_GET SI_POSIX  #define SANITIZER_INTERCEPT_PTHREAD_ATTR_GETINHERITSCHED \    (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS)  #define SANITIZER_INTERCEPT_PTHREAD_ATTR_GETAFFINITY_NP SI_LINUX_NOT_ANDROID +#define SANITIZER_INTERCEPT_PTHREAD_ATTR_GET_SCHED (SI_POSIX && !SI_OPENBSD)  #define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETPSHARED \ -  (SI_POSIX && !SI_NETBSD) -#define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETTYPE SI_POSIX +  (SI_POSIX && !SI_NETBSD && !SI_OPENBSD) +#define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETTYPE (SI_POSIX && !SI_OPENBSD)  #define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETPROTOCOL \    (SI_MAC || SI_NETBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS)  #define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETPRIOCEILING \ @@ -309,14 +341,15 @@    (SI_LINUX_NOT_ANDROID || SI_SOLARIS)  #define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETROBUST_NP SI_LINUX_NOT_ANDROID  #define SANITIZER_INTERCEPT_PTHREAD_RWLOCKATTR_GETPSHARED \ -  (SI_POSIX && !SI_NETBSD) +  (SI_POSIX && !SI_NETBSD && !SI_OPENBSD)  #define SANITIZER_INTERCEPT_PTHREAD_RWLOCKATTR_GETKIND_NP SI_LINUX_NOT_ANDROID  #define SANITIZER_INTERCEPT_PTHREAD_CONDATTR_GETPSHARED \ -  (SI_POSIX && !SI_NETBSD) +  (SI_POSIX && !SI_NETBSD && !SI_OPENBSD)  #define SANITIZER_INTERCEPT_PTHREAD_CONDATTR_GETCLOCK \    (SI_LINUX_NOT_ANDROID || SI_SOLARIS)  #define SANITIZER_INTERCEPT_PTHREAD_BARRIERATTR_GETPSHARED \ -  (SI_LINUX_NOT_ANDROID && !SI_NETBSD) +  (SI_LINUX_NOT_ANDROID && !SI_NETBSD && !SI_OPENBSD) +#define SANITIZER_INTERCEPT_THR_EXIT SI_FREEBSD  #define SANITIZER_INTERCEPT_TMPNAM SI_POSIX  #define SANITIZER_INTERCEPT_TMPNAM_R SI_LINUX_NOT_ANDROID || SI_SOLARIS  #define SANITIZER_INTERCEPT_TTYNAME_R SI_POSIX @@ -327,35 +360,40 @@  #define SANITIZER_INTERCEPT_LGAMMA_R (SI_FREEBSD || SI_LINUX || SI_SOLARIS)  #define SANITIZER_INTERCEPT_LGAMMAL_R SI_LINUX_NOT_ANDROID || SI_SOLARIS  #define SANITIZER_INTERCEPT_DRAND48_R SI_LINUX_NOT_ANDROID -#define SANITIZER_INTERCEPT_RAND_R \ -  (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS) +#define SANITIZER_INTERCEPT_RAND_R                                            \ +  (SI_FREEBSD || SI_NETBSD || SI_OPENBSD || SI_MAC || SI_LINUX_NOT_ANDROID || \ +  SI_SOLARIS)  #define SANITIZER_INTERCEPT_ICONV \ -  (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS) +  (SI_FREEBSD || SI_NETBSD || SI_OPENBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS)  #define SANITIZER_INTERCEPT_TIMES SI_POSIX  // FIXME: getline seems to be available on OSX 10.7  #define SANITIZER_INTERCEPT_GETLINE \ -  (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS) +  (SI_FREEBSD || SI_NETBSD || SI_OPENBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS)  #define SANITIZER_INTERCEPT__EXIT \ -  (SI_LINUX || SI_FREEBSD || SI_NETBSD || SI_MAC || SI_SOLARIS) +  (SI_LINUX || SI_FREEBSD || SI_NETBSD || SI_OPENBSD || SI_MAC || SI_SOLARIS) -#define SANITIZER_INTERCEPT_PHTREAD_MUTEX SI_POSIX +#define SANITIZER_INTERCEPT_PTHREAD_MUTEX SI_POSIX +#define SANITIZER_INTERCEPT___PTHREAD_MUTEX SI_LINUX_NOT_ANDROID +#define SANITIZER_INTERCEPT___LIBC_MUTEX SI_NETBSD  #define SANITIZER_INTERCEPT_PTHREAD_SETNAME_NP \ -  (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS) +  (SI_FREEBSD || SI_NETBSD || SI_OPENBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS)  #define SANITIZER_INTERCEPT_PTHREAD_GETNAME_NP \    (SI_FREEBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS)  #define SANITIZER_INTERCEPT_TLS_GET_ADDR \ -  (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS) +  (SI_FREEBSD || SI_NETBSD || SI_OPENBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS)  #define SANITIZER_INTERCEPT_LISTXATTR SI_LINUX  #define SANITIZER_INTERCEPT_GETXATTR SI_LINUX  #define SANITIZER_INTERCEPT_GETRESID SI_LINUX -#define SANITIZER_INTERCEPT_GETIFADDRS \ -  (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID || SI_MAC || SI_SOLARIS) -#define SANITIZER_INTERCEPT_IF_INDEXTONAME \ -  (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID || SI_MAC || SI_SOLARIS) +#define SANITIZER_INTERCEPT_GETIFADDRS                                        \ +  (SI_FREEBSD || SI_NETBSD || SI_OPENBSD || SI_LINUX_NOT_ANDROID || SI_MAC || \ +  SI_SOLARIS) +#define SANITIZER_INTERCEPT_IF_INDEXTONAME                                    \ +  (SI_FREEBSD || SI_NETBSD || SI_OPENBSD || SI_LINUX_NOT_ANDROID || SI_MAC || \ +  SI_SOLARIS)  #define SANITIZER_INTERCEPT_CAPGET SI_LINUX_NOT_ANDROID  #if SI_LINUX && defined(__arm__)  #define SANITIZER_INTERCEPT_AEABI_MEM 1 @@ -363,26 +401,28 @@  #define SANITIZER_INTERCEPT_AEABI_MEM 0  #endif  #define SANITIZER_INTERCEPT___BZERO SI_MAC -#define SANITIZER_INTERCEPT_FTIME (!SI_FREEBSD && !SI_NETBSD && SI_POSIX) +#define SANITIZER_INTERCEPT_FTIME \ +  (!SI_FREEBSD && !SI_NETBSD && !SI_OPENBSD && SI_POSIX)  #define SANITIZER_INTERCEPT_XDR SI_LINUX_NOT_ANDROID || SI_SOLARIS  #define SANITIZER_INTERCEPT_TSEARCH \ -  (SI_LINUX_NOT_ANDROID || SI_MAC || SI_NETBSD || SI_SOLARIS) +  (SI_LINUX_NOT_ANDROID || SI_MAC || SI_NETBSD || SI_OPENBSD || SI_SOLARIS)  #define SANITIZER_INTERCEPT_LIBIO_INTERNALS SI_LINUX_NOT_ANDROID  #define SANITIZER_INTERCEPT_FOPEN SI_POSIX  #define SANITIZER_INTERCEPT_FOPEN64 SI_LINUX_NOT_ANDROID || SI_SOLARIS32  #define SANITIZER_INTERCEPT_OPEN_MEMSTREAM \ -  (SI_LINUX_NOT_ANDROID || SI_NETBSD || SI_SOLARIS) +  (SI_LINUX_NOT_ANDROID || SI_NETBSD || SI_OPENBSD || SI_SOLARIS)  #define SANITIZER_INTERCEPT_OBSTACK SI_LINUX_NOT_ANDROID  #define SANITIZER_INTERCEPT_FFLUSH SI_POSIX  #define SANITIZER_INTERCEPT_FCLOSE SI_POSIX  #ifndef SANITIZER_INTERCEPT_DLOPEN_DLCLOSE -#define SANITIZER_INTERCEPT_DLOPEN_DLCLOSE \ -  (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID || SI_MAC || SI_SOLARIS) +#define SANITIZER_INTERCEPT_DLOPEN_DLCLOSE                                    \ +  (SI_FREEBSD || SI_NETBSD || SI_OPENBSD || SI_LINUX_NOT_ANDROID || SI_MAC || \ +  SI_SOLARIS)  #endif  #define SANITIZER_INTERCEPT_GETPASS \ -  (SI_LINUX_NOT_ANDROID || SI_MAC || SI_NETBSD) +  (SI_LINUX_NOT_ANDROID || SI_MAC || SI_NETBSD || SI_OPENBSD)  #define SANITIZER_INTERCEPT_TIMERFD SI_LINUX_NOT_ANDROID  #define SANITIZER_INTERCEPT_MLOCKX SI_POSIX @@ -390,19 +430,22 @@  #define SANITIZER_INTERCEPT_SEM \    (SI_LINUX || SI_FREEBSD || SI_NETBSD || SI_SOLARIS)  #define SANITIZER_INTERCEPT_PTHREAD_SETCANCEL SI_POSIX -#define SANITIZER_INTERCEPT_MINCORE (SI_LINUX || SI_NETBSD || SI_SOLARIS) +#define SANITIZER_INTERCEPT_MINCORE \ +  (SI_LINUX || SI_NETBSD || SI_OPENBSD || SI_SOLARIS)  #define SANITIZER_INTERCEPT_PROCESS_VM_READV SI_LINUX  #define SANITIZER_INTERCEPT_CTERMID \ -  (SI_LINUX || SI_MAC || SI_FREEBSD || SI_NETBSD || SI_SOLARIS) +  (SI_LINUX || SI_MAC || SI_FREEBSD || SI_NETBSD || SI_OPENBSD || SI_SOLARIS)  #define SANITIZER_INTERCEPT_CTERMID_R (SI_MAC || SI_FREEBSD || SI_SOLARIS) -#define SANITIZER_INTERCEPTOR_HOOKS (SI_LINUX || SI_MAC || SI_WINDOWS) +#define SANITIZER_INTERCEPTOR_HOOKS \ +  (SI_LINUX || SI_MAC || SI_WINDOWS || SI_NETBSD)  #define SANITIZER_INTERCEPT_RECV_RECVFROM SI_POSIX  #define SANITIZER_INTERCEPT_SEND_SENDTO SI_POSIX  #define SANITIZER_INTERCEPT_EVENTFD_READ_WRITE SI_LINUX  #define SANITIZER_INTERCEPT_STAT \ -  (SI_FREEBSD || SI_MAC || SI_ANDROID || SI_NETBSD || SI_SOLARIS) +  (SI_FREEBSD || SI_MAC || SI_ANDROID || SI_NETBSD || SI_OPENBSD || SI_SOLARIS) +#define SANITIZER_INTERCEPT_LSTAT (SI_NETBSD || SI_FREEBSD)  #define SANITIZER_INTERCEPT___XSTAT (!SANITIZER_INTERCEPT_STAT && SI_POSIX)  #define SANITIZER_INTERCEPT___XSTAT64 SI_LINUX_NOT_ANDROID  #define SANITIZER_INTERCEPT___LXSTAT SANITIZER_INTERCEPT___XSTAT @@ -414,20 +457,58 @@    (SI_LINUX_NOT_ANDROID || SI_MAC || SI_FREEBSD || SI_NETBSD)  #define SANITIZER_INTERCEPT_GETLOADAVG \ -  (SI_LINUX_NOT_ANDROID || SI_MAC || SI_FREEBSD || SI_NETBSD) +  (SI_LINUX_NOT_ANDROID || SI_MAC || SI_FREEBSD || SI_NETBSD || SI_OPENBSD) +#define SANITIZER_INTERCEPT_MMAP SI_POSIX +#define SANITIZER_INTERCEPT_MMAP64 SI_LINUX_NOT_ANDROID  #define SANITIZER_INTERCEPT_MALLOPT_AND_MALLINFO \ -  (!SI_FREEBSD && !SI_MAC && !SI_NETBSD && SI_NOT_FUCHSIA) -#define SANITIZER_INTERCEPT_MEMALIGN (!SI_FREEBSD && !SI_MAC && !SI_NETBSD) +  (!SI_FREEBSD && !SI_MAC && !SI_NETBSD && !SI_OPENBSD && SI_NOT_FUCHSIA && \ +  SI_NOT_RTEMS) +#define SANITIZER_INTERCEPT_MEMALIGN \ +  (!SI_FREEBSD && !SI_MAC && !SI_NETBSD && !SI_OPENBSD && SI_NOT_RTEMS)  #define SANITIZER_INTERCEPT_PVALLOC \ -  (!SI_FREEBSD && !SI_MAC && !SI_NETBSD && SI_NOT_FUCHSIA) +  (!SI_FREEBSD && !SI_MAC && !SI_NETBSD && !SI_OPENBSD && SI_NOT_FUCHSIA && \ +  SI_NOT_RTEMS)  #define SANITIZER_INTERCEPT_CFREE \ -  (!SI_FREEBSD && !SI_MAC && !SI_NETBSD && SI_NOT_FUCHSIA) -#define SANITIZER_INTERCEPT_ALIGNED_ALLOC (!SI_MAC) -#define SANITIZER_INTERCEPT_MALLOC_USABLE_SIZE (!SI_MAC) +  (!SI_FREEBSD && !SI_MAC && !SI_NETBSD && !SI_OPENBSD && SI_NOT_FUCHSIA && \ +  SI_NOT_RTEMS) +#define SANITIZER_INTERCEPT_ALIGNED_ALLOC (!SI_MAC && SI_NOT_RTEMS) +#define SANITIZER_INTERCEPT_MALLOC_USABLE_SIZE (!SI_MAC && !SI_OPENBSD)  #define SANITIZER_INTERCEPT_MCHECK_MPROBE SI_LINUX_NOT_ANDROID  #define SANITIZER_INTERCEPT_WCSCAT SI_POSIX  #define SANITIZER_INTERCEPT_SIGNAL_AND_SIGACTION (!SI_WINDOWS && SI_NOT_FUCHSIA)  #define SANITIZER_INTERCEPT_BSD_SIGNAL SI_ANDROID +#define SANITIZER_INTERCEPT_ACCT (SI_NETBSD || SI_OPENBSD || SI_FREEBSD) +#define SANITIZER_INTERCEPT_USER_FROM_UID SI_NETBSD +#define SANITIZER_INTERCEPT_UID_FROM_USER SI_NETBSD +#define SANITIZER_INTERCEPT_GROUP_FROM_GID SI_NETBSD +#define SANITIZER_INTERCEPT_GID_FROM_GROUP SI_NETBSD +#define SANITIZER_INTERCEPT_ACCESS (SI_NETBSD || SI_OPENBSD || SI_FREEBSD) +#define SANITIZER_INTERCEPT_FACCESSAT (SI_NETBSD || SI_OPENBSD || SI_FREEBSD) +#define SANITIZER_INTERCEPT_GETGROUPLIST (SI_NETBSD || SI_OPENBSD) +#define SANITIZER_INTERCEPT_STRLCPY                                            \ +  (SI_NETBSD || SI_FREEBSD || SI_OPENBSD || SI_MAC || SI_ANDROID) + +#define SANITIZER_INTERCEPT_NAME_TO_HANDLE_AT SI_LINUX_NOT_ANDROID +#define SANITIZER_INTERCEPT_OPEN_BY_HANDLE_AT SI_LINUX_NOT_ANDROID + +#define SANITIZER_INTERCEPT_READLINK SI_POSIX +#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && \ +    __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 101000 +# define SI_MAC_DEPLOYMENT_BELOW_10_10 1 +#else +# define SI_MAC_DEPLOYMENT_BELOW_10_10 0 +#endif +#define SANITIZER_INTERCEPT_READLINKAT \ +  (SI_POSIX && !SI_MAC_DEPLOYMENT_BELOW_10_10) + +#define SANITIZER_INTERCEPT_DEVNAME (SI_NETBSD || SI_OPENBSD || SI_FREEBSD) +#define SANITIZER_INTERCEPT_DEVNAME_R (SI_NETBSD || SI_FREEBSD) +#define SANITIZER_INTERCEPT_FGETLN (SI_NETBSD || SI_FREEBSD) +#define SANITIZER_INTERCEPT_STRMODE (SI_NETBSD || SI_FREEBSD) +#define SANITIZER_INTERCEPT_TTYENT SI_NETBSD +#define SANITIZER_INTERCEPT_PROTOENT SI_NETBSD +#define SANITIZER_INTERCEPT_NETENT SI_NETBSD +  #endif  // #ifndef SANITIZER_PLATFORM_INTERCEPTORS_H diff --git a/lib/sanitizer_common/sanitizer_platform_limits_netbsd.cc b/lib/sanitizer_common/sanitizer_platform_limits_netbsd.cc index 108e196e7a051..3c6bb2090fa54 100644 --- a/lib/sanitizer_common/sanitizer_platform_limits_netbsd.cc +++ b/lib/sanitizer_common/sanitizer_platform_limits_netbsd.cc @@ -15,7 +15,53 @@  #include "sanitizer_platform.h"  #if SANITIZER_NETBSD +#include <sys/param.h> +#include <sys/types.h> + +#include <altq/altq.h> +#include <altq/altq_afmap.h> +#include <altq/altq_blue.h> +#include <altq/altq_cbq.h> +#include <altq/altq_cdnr.h> +#include <altq/altq_fifoq.h> +#include <altq/altq_hfsc.h> +#include <altq/altq_jobs.h> +#include <altq/altq_priq.h> +#include <altq/altq_red.h> +#include <altq/altq_rio.h> +#include <altq/altq_wfq.h>  #include <arpa/inet.h> +#include <crypto/cryptodev.h> +#include <dev/apm/apmio.h> +#include <dev/dm/netbsd-dm.h> +#include <dev/dmover/dmover_io.h> +#include <dev/dtv/dtvio_demux.h> +#include <dev/dtv/dtvio_frontend.h> +#include <dev/filemon/filemon.h> +#include <dev/hdaudio/hdaudioio.h> +#include <dev/hdmicec/hdmicecio.h> +#include <dev/hpc/hpcfbio.h> +#include <dev/i2o/iopio.h> +#include <dev/ic/athioctl.h> +#include <dev/ic/bt8xx.h> +#include <dev/ic/icp_ioctl.h> +#include <dev/ic/isp_ioctl.h> +#include <dev/ic/mlxio.h> +#include <dev/ic/nvmeio.h> +#include <dev/ir/irdaio.h> +#include <dev/isa/isvio.h> +#include <dev/isa/satlinkio.h> +#include <dev/isa/wtreg.h> +#include <dev/iscsi/iscsi_ioctl.h> +#include <dev/ofw/openfirmio.h> +#include <dev/pci/amrio.h> + +#include <dev/pci/mlyreg.h> +#include <dev/pci/mlyio.h> + +#include <dev/pci/pciio.h> +#include <dev/pci/tweio.h> +#include <dev/pcmcia/if_cnwioctl.h>  #include <dirent.h>  #include <glob.h>  #include <grp.h> @@ -28,6 +74,8 @@  #include <net/route.h>  #include <netdb.h>  #include <netinet/in.h> +#include <netinet/ip_compat.h> +#include <netinet/ip_fil.h>  #include <netinet/ip_mroute.h>  #include <poll.h>  #include <pthread.h> @@ -35,6 +83,93 @@  #include <semaphore.h>  #include <signal.h>  #include <stddef.h> +#include <stdio.h> +#include <sys/disk.h> +#include <sys/disklabel.h> +#include <sys/mount.h> +#define RAY_DO_SIGLEV +#include <dev/biovar.h> +#include <dev/bluetooth/btdev.h> +#include <dev/bluetooth/btsco.h> +#include <dev/ccdvar.h> +#include <dev/cgdvar.h> +#include <dev/fssvar.h> +#include <dev/kttcpio.h> +#include <dev/lockstat.h> +#include <dev/md.h> +#include <dev/pcmcia/if_rayreg.h> +#include <dev/raidframe/raidframeio.h> +#include <dev/sbus/mbppio.h> +#include <dev/scsipi/ses.h> +#include <dev/spkrio.h> +#include <dev/sun/disklabel.h> +#include <dev/sun/fbio.h> +#include <dev/sun/kbio.h> +#include <dev/sun/vuid_event.h> +#include <dev/tc/sticio.h> +#include <dev/usb/ukyopon.h> +#include <dev/usb/urio.h> +#include <dev/usb/usb.h> +#include <dev/usb/utoppy.h> +#include <dev/vme/xio.h> +#include <dev/vndvar.h> +#include <dev/wscons/wsconsio.h> +#include <dev/wscons/wsdisplay_usl_io.h> +#include <net/bpf.h> +#include <net/if_atm.h> +#include <net/if_gre.h> +#include <net/if_ppp.h> +#include <net/if_pppoe.h> +#include <net/if_sppp.h> +#include <net/if_srt.h> +#include <net/if_tap.h> +#include <net/if_tun.h> +#include <net/npf.h> +#include <net/pfvar.h> +#include <net/slip.h> +#include <netbt/hci.h> +#include <netinet/ip_nat.h> +#include <netinet/ip_proxy.h> +#include <netinet6/in6_var.h> +#include <netinet6/nd6.h> +#include <netnatm/natm.h> +#include <netsmb/smb_dev.h> +#include <soundcard.h> +#include <sys/agpio.h> +#include <sys/ataio.h> +#include <sys/audioio.h> +#include <sys/cdio.h> +#include <sys/chio.h> +#include <sys/clockctl.h> +#include <sys/cpuio.h> +#include <sys/dkio.h> +#include <sys/drvctlio.h> +#include <sys/dvdio.h> +#include <sys/envsys.h> +#include <sys/event.h> +#include <sys/fdio.h> +#include <sys/filio.h> +#include <sys/gpio.h> +#include <sys/ioctl.h> +#include <sys/ioctl_compat.h> +#include <sys/joystick.h> +#include <sys/ksyms.h> +#include <sys/lua.h> +#include <sys/midiio.h> +#include <sys/mtio.h> +#include <sys/power.h> +#include <sys/radioio.h> +#include <sys/rndio.h> +#include <sys/scanio.h> +#include <sys/scsiio.h> +#include <sys/sockio.h> +#include <sys/timepps.h> +#include <sys/ttycom.h> +#include <sys/verified_exec.h> +#include <sys/videoio.h> +#include <sys/wdog.h> +//#include <xen/xenio.h> +#include <sys/event.h>  #include <sys/filio.h>  #include <sys/ipc.h>  #include <sys/mman.h> @@ -44,6 +179,7 @@  #include <sys/mtio.h>  #include <sys/ptrace.h>  #include <sys/resource.h> +#include <sys/sem.h>  #include <sys/shm.h>  #include <sys/signal.h>  #include <sys/socket.h> @@ -62,6 +198,7 @@  #include <term.h>  #include <termios.h>  #include <time.h> +#include <ttyent.h>  #include <utime.h>  #include <utmp.h>  #include <utmpx.h> @@ -99,18 +236,81 @@ unsigned struct_sockaddr_sz = sizeof(struct sockaddr);  unsigned ucontext_t_sz = sizeof(ucontext_t);  unsigned struct_rlimit_sz = sizeof(struct rlimit);  unsigned struct_timespec_sz = sizeof(struct timespec); +unsigned struct_sembuf_sz = sizeof(struct sembuf); +unsigned struct_kevent_sz = sizeof(struct kevent);  unsigned struct_utimbuf_sz = sizeof(struct utimbuf);  unsigned struct_itimerspec_sz = sizeof(struct itimerspec);  unsigned struct_timex_sz = sizeof(struct timex);  unsigned struct_msqid_ds_sz = sizeof(struct msqid_ds);  unsigned struct_mq_attr_sz = sizeof(struct mq_attr);  unsigned struct_statvfs_sz = sizeof(struct statvfs); +unsigned struct_sigaltstack_sz = sizeof(stack_t);  const uptr sig_ign = (uptr)SIG_IGN;  const uptr sig_dfl = (uptr)SIG_DFL;  const uptr sig_err = (uptr)SIG_ERR;  const uptr sa_siginfo = (uptr)SA_SIGINFO; +int ptrace_pt_io = PT_IO; +int ptrace_pt_lwpinfo = PT_LWPINFO; +int ptrace_pt_set_event_mask = PT_SET_EVENT_MASK; +int ptrace_pt_get_event_mask = PT_GET_EVENT_MASK; +int ptrace_pt_get_process_state = PT_GET_PROCESS_STATE; +int ptrace_pt_set_siginfo = PT_SET_SIGINFO; +int ptrace_pt_get_siginfo = PT_GET_SIGINFO; +int ptrace_piod_read_d = PIOD_READ_D; +int ptrace_piod_write_d = PIOD_WRITE_D; +int ptrace_piod_read_i = PIOD_READ_I; +int ptrace_piod_write_i = PIOD_WRITE_I; +int ptrace_piod_read_auxv = PIOD_READ_AUXV; + +#if defined(PT_SETREGS) && defined(PT_GETREGS) +int ptrace_pt_setregs = PT_SETREGS; +int ptrace_pt_getregs = PT_GETREGS; +#else +int ptrace_pt_setregs = -1; +int ptrace_pt_getregs = -1; +#endif + +#if defined(PT_SETFPREGS) && defined(PT_GETFPREGS) +int ptrace_pt_setfpregs = PT_SETFPREGS; +int ptrace_pt_getfpregs = PT_GETFPREGS; +#else +int ptrace_pt_setfpregs = -1; +int ptrace_pt_getfpregs = -1; +#endif + +#if defined(PT_SETDBREGS) && defined(PT_GETDBREGS) +int ptrace_pt_setdbregs = PT_SETDBREGS; +int ptrace_pt_getdbregs = PT_GETDBREGS; +#else +int ptrace_pt_setdbregs = -1; +int ptrace_pt_getdbregs = -1; +#endif + +unsigned struct_ptrace_ptrace_io_desc_struct_sz = sizeof(struct ptrace_io_desc); +unsigned struct_ptrace_ptrace_lwpinfo_struct_sz = sizeof(struct ptrace_lwpinfo); +unsigned struct_ptrace_ptrace_event_struct_sz = sizeof(ptrace_event_t); +unsigned struct_ptrace_ptrace_siginfo_struct_sz = sizeof(ptrace_siginfo_t); + +#if defined(PT_SETREGS) +unsigned struct_ptrace_reg_struct_sz = sizeof(struct reg); +#else +unsigned struct_ptrace_reg_struct_sz = -1; +#endif + +#if defined(PT_SETFPREGS) +unsigned struct_ptrace_fpreg_struct_sz = sizeof(struct fpreg); +#else +unsigned struct_ptrace_fpreg_struct_sz = -1; +#endif + +#if defined(PT_SETDBREGS) +unsigned struct_ptrace_dbreg_struct_sz = sizeof(struct dbreg); +#else +unsigned struct_ptrace_dbreg_struct_sz = -1; +#endif +  int shmctl_ipc_stat = (int)IPC_STAT;  unsigned struct_utmp_sz = sizeof(struct utmp); @@ -137,65 +337,1729 @@ int glob_altdirfunc = GLOB_ALTDIRFUNC;  unsigned path_max = PATH_MAX; +int struct_ttyent_sz = sizeof(struct ttyent); +  // ioctl arguments -unsigned struct_ifreq_sz = sizeof(struct ifreq); -unsigned struct_termios_sz = sizeof(struct termios); -unsigned struct_winsize_sz = sizeof(struct winsize); -unsigned struct_mtget_sz = sizeof(struct mtget); -unsigned struct_mtop_sz = sizeof(struct mtop); -unsigned struct_audio_buf_info_sz = sizeof(struct audio_buf_info); -unsigned struct_ppp_stats_sz = sizeof(struct ppp_stats); -unsigned struct_sioc_sg_req_sz = sizeof(struct sioc_sg_req); -unsigned struct_sioc_vif_req_sz = sizeof(struct sioc_vif_req); +unsigned struct_altqreq_sz = sizeof(altqreq); +unsigned struct_amr_user_ioctl_sz = sizeof(amr_user_ioctl); +unsigned struct_ap_control_sz = sizeof(ap_control); +unsigned struct_apm_ctl_sz = sizeof(apm_ctl); +unsigned struct_apm_event_info_sz = sizeof(apm_event_info); +unsigned struct_apm_power_info_sz = sizeof(apm_power_info); +unsigned struct_atabusiodetach_args_sz = sizeof(atabusiodetach_args); +unsigned struct_atabusioscan_args_sz = sizeof(atabusioscan_args); +unsigned struct_ath_diag_sz = sizeof(ath_diag); +unsigned struct_atm_flowmap_sz = sizeof(atm_flowmap); +unsigned struct_atm_pseudoioctl_sz = sizeof(atm_pseudoioctl); +unsigned struct_audio_buf_info_sz = sizeof(audio_buf_info); +unsigned struct_audio_device_sz = sizeof(audio_device); +unsigned struct_audio_encoding_sz = sizeof(audio_encoding); +unsigned struct_audio_info_sz = sizeof(audio_info); +unsigned struct_audio_offset_sz = sizeof(audio_offset); +unsigned struct_bio_locate_sz = sizeof(bio_locate); +unsigned struct_bioc_alarm_sz = sizeof(bioc_alarm); +unsigned struct_bioc_blink_sz = sizeof(bioc_blink); +unsigned struct_bioc_disk_sz = sizeof(bioc_disk); +unsigned struct_bioc_inq_sz = sizeof(bioc_inq); +unsigned struct_bioc_setstate_sz = sizeof(bioc_setstate); +unsigned struct_bioc_vol_sz = sizeof(bioc_vol); +unsigned struct_bioc_volops_sz = sizeof(bioc_volops); +unsigned struct_bktr_chnlset_sz = sizeof(bktr_chnlset); +unsigned struct_bktr_remote_sz = sizeof(bktr_remote); +unsigned struct_blue_conf_sz = sizeof(blue_conf); +unsigned struct_blue_interface_sz = sizeof(blue_interface); +unsigned struct_blue_stats_sz = sizeof(blue_stats); +unsigned struct_bpf_dltlist_sz = sizeof(bpf_dltlist); +unsigned struct_bpf_program_sz = sizeof(bpf_program); +unsigned struct_bpf_stat_old_sz = sizeof(bpf_stat_old); +unsigned struct_bpf_stat_sz = sizeof(bpf_stat); +unsigned struct_bpf_version_sz = sizeof(bpf_version); +unsigned struct_btreq_sz = sizeof(btreq); +unsigned struct_btsco_info_sz = sizeof(btsco_info); +unsigned struct_buffmem_desc_sz = sizeof(buffmem_desc); +unsigned struct_cbq_add_class_sz = sizeof(cbq_add_class); +unsigned struct_cbq_add_filter_sz = sizeof(cbq_add_filter); +unsigned struct_cbq_delete_class_sz = sizeof(cbq_delete_class); +unsigned struct_cbq_delete_filter_sz = sizeof(cbq_delete_filter); +unsigned struct_cbq_getstats_sz = sizeof(cbq_getstats); +unsigned struct_cbq_interface_sz = sizeof(cbq_interface); +unsigned struct_cbq_modify_class_sz = sizeof(cbq_modify_class); +unsigned struct_ccd_ioctl_sz = sizeof(ccd_ioctl); +unsigned struct_cdnr_add_element_sz = sizeof(cdnr_add_element); +unsigned struct_cdnr_add_filter_sz = sizeof(cdnr_add_filter); +unsigned struct_cdnr_add_tbmeter_sz = sizeof(cdnr_add_tbmeter); +unsigned struct_cdnr_add_trtcm_sz = sizeof(cdnr_add_trtcm); +unsigned struct_cdnr_add_tswtcm_sz = sizeof(cdnr_add_tswtcm); +unsigned struct_cdnr_delete_element_sz = sizeof(cdnr_delete_element); +unsigned struct_cdnr_delete_filter_sz = sizeof(cdnr_delete_filter); +unsigned struct_cdnr_get_stats_sz = sizeof(cdnr_get_stats); +unsigned struct_cdnr_interface_sz = sizeof(cdnr_interface); +unsigned struct_cdnr_modify_tbmeter_sz = sizeof(cdnr_modify_tbmeter); +unsigned struct_cdnr_modify_trtcm_sz = sizeof(cdnr_modify_trtcm); +unsigned struct_cdnr_modify_tswtcm_sz = sizeof(cdnr_modify_tswtcm); +unsigned struct_cdnr_tbmeter_stats_sz = sizeof(cdnr_tbmeter_stats); +unsigned struct_cdnr_tcm_stats_sz = sizeof(cdnr_tcm_stats); +unsigned struct_cgd_ioctl_sz = sizeof(cgd_ioctl); +unsigned struct_cgd_user_sz = sizeof(cgd_user); +unsigned struct_changer_element_status_request_sz = +    sizeof(changer_element_status_request); +unsigned struct_changer_exchange_request_sz = sizeof(changer_exchange_request); +unsigned struct_changer_move_request_sz = sizeof(changer_move_request); +unsigned struct_changer_params_sz = sizeof(changer_params); +unsigned struct_changer_position_request_sz = sizeof(changer_position_request); +unsigned struct_changer_set_voltag_request_sz = +    sizeof(changer_set_voltag_request); +unsigned struct_clockctl_adjtime_sz = sizeof(clockctl_adjtime); +unsigned struct_clockctl_clock_settime_sz = sizeof(clockctl_clock_settime); +unsigned struct_clockctl_ntp_adjtime_sz = sizeof(clockctl_ntp_adjtime); +unsigned struct_clockctl_settimeofday_sz = sizeof(clockctl_settimeofday); +unsigned struct_cnwistats_sz = sizeof(cnwistats); +unsigned struct_cnwitrail_sz = sizeof(cnwitrail); +unsigned struct_cnwstatus_sz = sizeof(cnwstatus); +unsigned struct_count_info_sz = sizeof(count_info); +unsigned struct_cpu_ucode_sz = sizeof(cpu_ucode); +unsigned struct_cpu_ucode_version_sz = sizeof(cpu_ucode_version); +unsigned struct_crypt_kop_sz = sizeof(crypt_kop); +unsigned struct_crypt_mkop_sz = sizeof(crypt_mkop); +unsigned struct_crypt_mop_sz = sizeof(crypt_mop); +unsigned struct_crypt_op_sz = sizeof(crypt_op); +unsigned struct_crypt_result_sz = sizeof(crypt_result); +unsigned struct_crypt_sfop_sz = sizeof(crypt_sfop); +unsigned struct_crypt_sgop_sz = sizeof(crypt_sgop); +unsigned struct_cryptret_sz = sizeof(cryptret); +unsigned struct_devdetachargs_sz = sizeof(devdetachargs); +unsigned struct_devlistargs_sz = sizeof(devlistargs); +unsigned struct_devpmargs_sz = sizeof(devpmargs); +unsigned struct_devrescanargs_sz = sizeof(devrescanargs); +unsigned struct_disk_badsecinfo_sz = sizeof(disk_badsecinfo); +unsigned struct_disk_strategy_sz = sizeof(disk_strategy); +unsigned struct_disklabel_sz = sizeof(disklabel); +unsigned struct_dkbad_sz = sizeof(dkbad); +unsigned struct_dkwedge_info_sz = sizeof(dkwedge_info); +unsigned struct_dkwedge_list_sz = sizeof(dkwedge_list); +unsigned struct_dmio_setfunc_sz = sizeof(dmio_setfunc); +unsigned struct_dmx_pes_filter_params_sz = sizeof(dmx_pes_filter_params); +unsigned struct_dmx_sct_filter_params_sz = sizeof(dmx_sct_filter_params); +unsigned struct_dmx_stc_sz = sizeof(dmx_stc); +unsigned struct_dvb_diseqc_master_cmd_sz = sizeof(dvb_diseqc_master_cmd); +unsigned struct_dvb_diseqc_slave_reply_sz = sizeof(dvb_diseqc_slave_reply); +unsigned struct_dvb_frontend_event_sz = sizeof(dvb_frontend_event); +unsigned struct_dvb_frontend_info_sz = sizeof(dvb_frontend_info); +unsigned struct_dvb_frontend_parameters_sz = sizeof(dvb_frontend_parameters); +unsigned struct_eccapreq_sz = sizeof(eccapreq); +unsigned struct_fbcmap_sz = sizeof(fbcmap); +unsigned struct_fbcurpos_sz = sizeof(fbcurpos); +unsigned struct_fbcursor_sz = sizeof(fbcursor); +unsigned struct_fbgattr_sz = sizeof(fbgattr); +unsigned struct_fbsattr_sz = sizeof(fbsattr); +unsigned struct_fbtype_sz = sizeof(fbtype); +unsigned struct_fdformat_cmd_sz = sizeof(fdformat_cmd); +unsigned struct_fdformat_parms_sz = sizeof(fdformat_parms); +unsigned struct_fifoq_conf_sz = sizeof(fifoq_conf); +unsigned struct_fifoq_getstats_sz = sizeof(fifoq_getstats); +unsigned struct_fifoq_interface_sz = sizeof(fifoq_interface); +unsigned struct_format_op_sz = sizeof(format_op); +unsigned struct_fss_get_sz = sizeof(fss_get); +unsigned struct_fss_set_sz = sizeof(fss_set); +unsigned struct_gpio_attach_sz = sizeof(gpio_attach); +unsigned struct_gpio_info_sz = sizeof(gpio_info); +unsigned struct_gpio_req_sz = sizeof(gpio_req); +unsigned struct_gpio_set_sz = sizeof(gpio_set); +unsigned struct_hfsc_add_class_sz = sizeof(hfsc_add_class); +unsigned struct_hfsc_add_filter_sz = sizeof(hfsc_add_filter); +unsigned struct_hfsc_attach_sz = sizeof(hfsc_attach); +unsigned struct_hfsc_class_stats_sz = sizeof(hfsc_class_stats); +unsigned struct_hfsc_delete_class_sz = sizeof(hfsc_delete_class); +unsigned struct_hfsc_delete_filter_sz = sizeof(hfsc_delete_filter); +unsigned struct_hfsc_interface_sz = sizeof(hfsc_interface); +unsigned struct_hfsc_modify_class_sz = sizeof(hfsc_modify_class); +unsigned struct_hpcfb_dsp_op_sz = sizeof(hpcfb_dsp_op); +unsigned struct_hpcfb_dspconf_sz = sizeof(hpcfb_dspconf); +unsigned struct_hpcfb_fbconf_sz = sizeof(hpcfb_fbconf); +unsigned struct_if_addrprefreq_sz = sizeof(if_addrprefreq); +unsigned struct_if_clonereq_sz = sizeof(if_clonereq); +unsigned struct_if_laddrreq_sz = sizeof(if_laddrreq); +unsigned struct_ifaddr_sz = sizeof(ifaddr); +unsigned struct_ifaliasreq_sz = sizeof(ifaliasreq); +unsigned struct_ifcapreq_sz = sizeof(ifcapreq); +unsigned struct_ifconf_sz = sizeof(ifconf); +unsigned struct_ifdatareq_sz = sizeof(ifdatareq); +unsigned struct_ifdrv_sz = sizeof(ifdrv); +unsigned struct_ifmediareq_sz = sizeof(ifmediareq); +unsigned struct_ifpppcstatsreq_sz = sizeof(ifpppcstatsreq); +unsigned struct_ifpppstatsreq_sz = sizeof(ifpppstatsreq); +unsigned struct_ifreq_sz = sizeof(ifreq); +unsigned struct_in6_addrpolicy_sz = sizeof(in6_addrpolicy); +unsigned struct_in6_ndireq_sz = sizeof(in6_ndireq); +unsigned struct_ioc_load_unload_sz = sizeof(ioc_load_unload); +unsigned struct_ioc_patch_sz = sizeof(ioc_patch); +unsigned struct_ioc_play_blocks_sz = sizeof(ioc_play_blocks); +unsigned struct_ioc_play_msf_sz = sizeof(ioc_play_msf); +unsigned struct_ioc_play_track_sz = sizeof(ioc_play_track); +unsigned struct_ioc_read_subchannel_sz = sizeof(ioc_read_subchannel); +unsigned struct_ioc_read_toc_entry_sz = sizeof(ioc_read_toc_entry); +unsigned struct_ioc_toc_header_sz = sizeof(ioc_toc_header); +unsigned struct_ioc_vol_sz = sizeof(ioc_vol); +unsigned struct_ioctl_pt_sz = sizeof(ioctl_pt); +unsigned struct_ioppt_sz = sizeof(ioppt); +unsigned struct_iovec_sz = sizeof(iovec); +unsigned struct_ipfobj_sz = sizeof(ipfobj); +unsigned struct_irda_params_sz = sizeof(irda_params); +unsigned struct_isp_fc_device_sz = sizeof(isp_fc_device); +unsigned struct_isp_fc_tsk_mgmt_sz = sizeof(isp_fc_tsk_mgmt); +unsigned struct_isp_hba_device_sz = sizeof(isp_hba_device); +unsigned struct_isv_cmd_sz = sizeof(isv_cmd); +unsigned struct_jobs_add_class_sz = sizeof(jobs_add_class); +unsigned struct_jobs_add_filter_sz = sizeof(jobs_add_filter); +unsigned struct_jobs_attach_sz = sizeof(jobs_attach); +unsigned struct_jobs_class_stats_sz = sizeof(jobs_class_stats); +unsigned struct_jobs_delete_class_sz = sizeof(jobs_delete_class); +unsigned struct_jobs_delete_filter_sz = sizeof(jobs_delete_filter); +unsigned struct_jobs_interface_sz = sizeof(jobs_interface); +unsigned struct_jobs_modify_class_sz = sizeof(jobs_modify_class); +unsigned struct_kbentry_sz = sizeof(kbentry); +unsigned struct_kfilter_mapping_sz = sizeof(kfilter_mapping); +unsigned struct_kiockeymap_sz = sizeof(kiockeymap); +unsigned struct_ksyms_gsymbol_sz = sizeof(ksyms_gsymbol); +unsigned struct_ksyms_gvalue_sz = sizeof(ksyms_gvalue); +unsigned struct_ksyms_ogsymbol_sz = sizeof(ksyms_ogsymbol); +unsigned struct_kttcp_io_args_sz = sizeof(kttcp_io_args); +unsigned struct_ltchars_sz = sizeof(ltchars); +unsigned struct_lua_create_sz = sizeof(struct lua_create); +unsigned struct_lua_info_sz = sizeof(struct lua_info); +unsigned struct_lua_load_sz = sizeof(struct lua_load); +unsigned struct_lua_require_sz = sizeof(lua_require); +unsigned struct_mbpp_param_sz = sizeof(mbpp_param); +unsigned struct_md_conf_sz = sizeof(md_conf); +unsigned struct_meteor_capframe_sz = sizeof(meteor_capframe); +unsigned struct_meteor_counts_sz = sizeof(meteor_counts); +unsigned struct_meteor_geomet_sz = sizeof(meteor_geomet); +unsigned struct_meteor_pixfmt_sz = sizeof(meteor_pixfmt); +unsigned struct_meteor_video_sz = sizeof(meteor_video); +unsigned struct_mlx_cinfo_sz = sizeof(mlx_cinfo); +unsigned struct_mlx_pause_sz = sizeof(mlx_pause); +unsigned struct_mlx_rebuild_request_sz = sizeof(mlx_rebuild_request); +unsigned struct_mlx_rebuild_status_sz = sizeof(mlx_rebuild_status); +unsigned struct_mlx_usercommand_sz = sizeof(mlx_usercommand); +unsigned struct_mly_user_command_sz = sizeof(mly_user_command); +unsigned struct_mly_user_health_sz = sizeof(mly_user_health); +unsigned struct_mtget_sz = sizeof(mtget); +unsigned struct_mtop_sz = sizeof(mtop); +unsigned struct_npf_ioctl_table_sz = sizeof(npf_ioctl_table); +unsigned struct_npioctl_sz = sizeof(npioctl); +unsigned struct_nvme_pt_command_sz = sizeof(nvme_pt_command); +unsigned struct_ochanger_element_status_request_sz = +    sizeof(ochanger_element_status_request); +unsigned struct_ofiocdesc_sz = sizeof(ofiocdesc); +unsigned struct_okiockey_sz = sizeof(okiockey); +unsigned struct_ortentry_sz = sizeof(ortentry); +unsigned struct_oscsi_addr_sz = sizeof(oscsi_addr); +unsigned struct_oss_audioinfo_sz = sizeof(oss_audioinfo); +unsigned struct_oss_sysinfo_sz = sizeof(oss_sysinfo); +unsigned struct_pciio_bdf_cfgreg_sz = sizeof(pciio_bdf_cfgreg); +unsigned struct_pciio_businfo_sz = sizeof(pciio_businfo); +unsigned struct_pciio_cfgreg_sz = sizeof(pciio_cfgreg); +unsigned struct_pciio_drvname_sz = sizeof(pciio_drvname); +unsigned struct_pciio_drvnameonbus_sz = sizeof(pciio_drvnameonbus); +unsigned struct_pcvtid_sz = sizeof(pcvtid); +unsigned struct_pf_osfp_ioctl_sz = sizeof(pf_osfp_ioctl); +unsigned struct_pf_status_sz = sizeof(pf_status); +unsigned struct_pfioc_altq_sz = sizeof(pfioc_altq); +unsigned struct_pfioc_if_sz = sizeof(pfioc_if); +unsigned struct_pfioc_iface_sz = sizeof(pfioc_iface); +unsigned struct_pfioc_limit_sz = sizeof(pfioc_limit); +unsigned struct_pfioc_natlook_sz = sizeof(pfioc_natlook); +unsigned struct_pfioc_pooladdr_sz = sizeof(pfioc_pooladdr); +unsigned struct_pfioc_qstats_sz = sizeof(pfioc_qstats); +unsigned struct_pfioc_rule_sz = sizeof(pfioc_rule); +unsigned struct_pfioc_ruleset_sz = sizeof(pfioc_ruleset); +unsigned struct_pfioc_src_node_kill_sz = sizeof(pfioc_src_node_kill); +unsigned struct_pfioc_src_nodes_sz = sizeof(pfioc_src_nodes); +unsigned struct_pfioc_state_kill_sz = sizeof(pfioc_state_kill); +unsigned struct_pfioc_state_sz = sizeof(pfioc_state); +unsigned struct_pfioc_states_sz = sizeof(pfioc_states); +unsigned struct_pfioc_table_sz = sizeof(pfioc_table); +unsigned struct_pfioc_tm_sz = sizeof(pfioc_tm); +unsigned struct_pfioc_trans_sz = sizeof(pfioc_trans); +unsigned struct_plistref_sz = sizeof(plistref); +unsigned struct_power_type_sz = sizeof(power_type); +unsigned struct_ppp_idle_sz = sizeof(ppp_idle); +unsigned struct_ppp_option_data_sz = sizeof(ppp_option_data); +unsigned struct_ppp_rawin_sz = sizeof(ppp_rawin); +unsigned struct_pppoeconnectionstate_sz = sizeof(pppoeconnectionstate); +unsigned struct_pppoediscparms_sz = sizeof(pppoediscparms); +unsigned struct_priq_add_class_sz = sizeof(priq_add_class); +unsigned struct_priq_add_filter_sz = sizeof(priq_add_filter); +unsigned struct_priq_class_stats_sz = sizeof(priq_class_stats); +unsigned struct_priq_delete_class_sz = sizeof(priq_delete_class); +unsigned struct_priq_delete_filter_sz = sizeof(priq_delete_filter); +unsigned struct_priq_interface_sz = sizeof(priq_interface); +unsigned struct_priq_modify_class_sz = sizeof(priq_modify_class); +unsigned struct_ptmget_sz = sizeof(ptmget); +unsigned struct_pvctxreq_sz = sizeof(pvctxreq); +unsigned struct_radio_info_sz = sizeof(radio_info); +unsigned struct_red_conf_sz = sizeof(red_conf); +unsigned struct_red_interface_sz = sizeof(red_interface); +unsigned struct_red_stats_sz = sizeof(red_stats); +unsigned struct_redparams_sz = sizeof(redparams); +unsigned struct_rf_pmparams_sz = sizeof(rf_pmparams); +unsigned struct_rf_pmstat_sz = sizeof(rf_pmstat); +unsigned struct_rf_recon_req_sz = sizeof(rf_recon_req); +unsigned struct_rio_conf_sz = sizeof(rio_conf); +unsigned struct_rio_interface_sz = sizeof(rio_interface); +unsigned struct_rio_stats_sz = sizeof(rio_stats); +unsigned struct_satlink_id_sz = sizeof(satlink_id); +unsigned struct_scan_io_sz = sizeof(scan_io); +unsigned struct_scbusaccel_args_sz = sizeof(scbusaccel_args); +unsigned struct_scbusiodetach_args_sz = sizeof(scbusiodetach_args); +unsigned struct_scbusioscan_args_sz = sizeof(scbusioscan_args); +unsigned struct_scsi_addr_sz = sizeof(scsi_addr); +unsigned struct_seq_event_rec_sz = sizeof(seq_event_rec); +unsigned struct_session_op_sz = sizeof(session_op); +unsigned struct_sgttyb_sz = sizeof(sgttyb); +unsigned struct_sioc_sg_req_sz = sizeof(sioc_sg_req); +unsigned struct_sioc_vif_req_sz = sizeof(sioc_vif_req); +unsigned struct_smbioc_flags_sz = sizeof(smbioc_flags); +unsigned struct_smbioc_lookup_sz = sizeof(smbioc_lookup); +unsigned struct_smbioc_oshare_sz = sizeof(smbioc_oshare); +unsigned struct_smbioc_ossn_sz = sizeof(smbioc_ossn); +unsigned struct_smbioc_rq_sz = sizeof(smbioc_rq); +unsigned struct_smbioc_rw_sz = sizeof(smbioc_rw); +unsigned struct_spppauthcfg_sz = sizeof(spppauthcfg); +unsigned struct_spppauthfailuresettings_sz = sizeof(spppauthfailuresettings); +unsigned struct_spppauthfailurestats_sz = sizeof(spppauthfailurestats); +unsigned struct_spppdnsaddrs_sz = sizeof(spppdnsaddrs); +unsigned struct_spppdnssettings_sz = sizeof(spppdnssettings); +unsigned struct_spppidletimeout_sz = sizeof(spppidletimeout); +unsigned struct_spppkeepalivesettings_sz = sizeof(spppkeepalivesettings); +unsigned struct_sppplcpcfg_sz = sizeof(sppplcpcfg); +unsigned struct_spppstatus_sz = sizeof(spppstatus); +unsigned struct_spppstatusncp_sz = sizeof(spppstatusncp); +unsigned struct_srt_rt_sz = sizeof(srt_rt); +unsigned struct_stic_xinfo_sz = sizeof(stic_xinfo); +unsigned struct_sun_dkctlr_sz = sizeof(sun_dkctlr); +unsigned struct_sun_dkgeom_sz = sizeof(sun_dkgeom); +unsigned struct_sun_dkpart_sz = sizeof(sun_dkpart); +unsigned struct_synth_info_sz = sizeof(synth_info); +unsigned struct_tbrreq_sz = sizeof(tbrreq); +unsigned struct_tchars_sz = sizeof(tchars); +unsigned struct_termios_sz = sizeof(termios); +unsigned struct_timeval_sz = sizeof(timeval); +unsigned struct_twe_drivecommand_sz = sizeof(twe_drivecommand); +unsigned struct_twe_paramcommand_sz = sizeof(twe_paramcommand); +unsigned struct_twe_usercommand_sz = sizeof(twe_usercommand); +unsigned struct_ukyopon_identify_sz = sizeof(ukyopon_identify); +unsigned struct_urio_command_sz = sizeof(urio_command); +unsigned struct_usb_alt_interface_sz = sizeof(usb_alt_interface); +unsigned struct_usb_bulk_ra_wb_opt_sz = sizeof(usb_bulk_ra_wb_opt); +unsigned struct_usb_config_desc_sz = sizeof(usb_config_desc); +unsigned struct_usb_ctl_report_desc_sz = sizeof(usb_ctl_report_desc); +unsigned struct_usb_ctl_report_sz = sizeof(usb_ctl_report); +unsigned struct_usb_ctl_request_sz = sizeof(usb_ctl_request); +unsigned struct_usb_device_info_old_sz = sizeof(usb_device_info_old); +unsigned struct_usb_device_info_sz = sizeof(usb_device_info); +unsigned struct_usb_device_stats_sz = sizeof(usb_device_stats); +unsigned struct_usb_endpoint_desc_sz = sizeof(usb_endpoint_desc); +unsigned struct_usb_full_desc_sz = sizeof(usb_full_desc); +unsigned struct_usb_interface_desc_sz = sizeof(usb_interface_desc); +unsigned struct_usb_string_desc_sz = sizeof(usb_string_desc); +unsigned struct_utoppy_readfile_sz = sizeof(utoppy_readfile); +unsigned struct_utoppy_rename_sz = sizeof(utoppy_rename); +unsigned struct_utoppy_stats_sz = sizeof(utoppy_stats); +unsigned struct_utoppy_writefile_sz = sizeof(utoppy_writefile); +unsigned struct_v4l2_audio_sz = sizeof(v4l2_audio); +unsigned struct_v4l2_audioout_sz = sizeof(v4l2_audioout); +unsigned struct_v4l2_buffer_sz = sizeof(v4l2_buffer); +unsigned struct_v4l2_capability_sz = sizeof(v4l2_capability); +unsigned struct_v4l2_control_sz = sizeof(v4l2_control); +unsigned struct_v4l2_crop_sz = sizeof(v4l2_crop); +unsigned struct_v4l2_cropcap_sz = sizeof(v4l2_cropcap); +unsigned struct_v4l2_fmtdesc_sz = sizeof(v4l2_fmtdesc); +unsigned struct_v4l2_format_sz = sizeof(v4l2_format); +unsigned struct_v4l2_framebuffer_sz = sizeof(v4l2_framebuffer); +unsigned struct_v4l2_frequency_sz = sizeof(v4l2_frequency); +unsigned struct_v4l2_frmivalenum_sz = sizeof(v4l2_frmivalenum); +unsigned struct_v4l2_frmsizeenum_sz = sizeof(v4l2_frmsizeenum); +unsigned struct_v4l2_input_sz = sizeof(v4l2_input); +unsigned struct_v4l2_jpegcompression_sz = sizeof(v4l2_jpegcompression); +unsigned struct_v4l2_modulator_sz = sizeof(v4l2_modulator); +unsigned struct_v4l2_output_sz = sizeof(v4l2_output); +unsigned struct_v4l2_queryctrl_sz = sizeof(v4l2_queryctrl); +unsigned struct_v4l2_querymenu_sz = sizeof(v4l2_querymenu); +unsigned struct_v4l2_requestbuffers_sz = sizeof(v4l2_requestbuffers); +unsigned struct_v4l2_standard_sz = sizeof(v4l2_standard); +unsigned struct_v4l2_streamparm_sz = sizeof(v4l2_streamparm); +unsigned struct_v4l2_tuner_sz = sizeof(v4l2_tuner); +unsigned struct_vnd_ioctl_sz = sizeof(vnd_ioctl); +unsigned struct_vnd_user_sz = sizeof(vnd_user); +unsigned struct_vt_stat_sz = sizeof(vt_stat); +unsigned struct_wdog_conf_sz = sizeof(wdog_conf); +unsigned struct_wdog_mode_sz = sizeof(wdog_mode); +unsigned struct_wfq_conf_sz = sizeof(wfq_conf); +unsigned struct_wfq_getqid_sz = sizeof(wfq_getqid); +unsigned struct_wfq_getstats_sz = sizeof(wfq_getstats); +unsigned struct_wfq_interface_sz = sizeof(wfq_interface); +unsigned struct_wfq_setweight_sz = sizeof(wfq_setweight); +unsigned struct_winsize_sz = sizeof(winsize); +unsigned struct_wscons_event_sz = sizeof(wscons_event); +unsigned struct_wsdisplay_addscreendata_sz = sizeof(wsdisplay_addscreendata); +unsigned struct_wsdisplay_char_sz = sizeof(wsdisplay_char); +unsigned struct_wsdisplay_cmap_sz = sizeof(wsdisplay_cmap); +unsigned struct_wsdisplay_curpos_sz = sizeof(wsdisplay_curpos); +unsigned struct_wsdisplay_cursor_sz = sizeof(wsdisplay_cursor); +unsigned struct_wsdisplay_delscreendata_sz = sizeof(wsdisplay_delscreendata); +unsigned struct_wsdisplay_fbinfo_sz = sizeof(wsdisplay_fbinfo); +unsigned struct_wsdisplay_font_sz = sizeof(wsdisplay_font); +unsigned struct_wsdisplay_kbddata_sz = sizeof(wsdisplay_kbddata); +unsigned struct_wsdisplay_msgattrs_sz = sizeof(wsdisplay_msgattrs); +unsigned struct_wsdisplay_param_sz = sizeof(wsdisplay_param); +unsigned struct_wsdisplay_scroll_data_sz = sizeof(wsdisplay_scroll_data); +unsigned struct_wsdisplay_usefontdata_sz = sizeof(wsdisplay_usefontdata); +unsigned struct_wsdisplayio_blit_sz = sizeof(wsdisplayio_blit); +unsigned struct_wsdisplayio_bus_id_sz = sizeof(wsdisplayio_bus_id); +unsigned struct_wsdisplayio_edid_info_sz = sizeof(wsdisplayio_edid_info); +unsigned struct_wsdisplayio_fbinfo_sz = sizeof(wsdisplayio_fbinfo); +unsigned struct_wskbd_bell_data_sz = sizeof(wskbd_bell_data); +unsigned struct_wskbd_keyrepeat_data_sz = sizeof(wskbd_keyrepeat_data); +unsigned struct_wskbd_map_data_sz = sizeof(wskbd_map_data); +unsigned struct_wskbd_scroll_data_sz = sizeof(wskbd_scroll_data); +unsigned struct_wsmouse_calibcoords_sz = sizeof(wsmouse_calibcoords); +unsigned struct_wsmouse_id_sz = sizeof(wsmouse_id); +unsigned struct_wsmouse_repeat_sz = sizeof(wsmouse_repeat); +unsigned struct_wsmux_device_list_sz = sizeof(wsmux_device_list); +unsigned struct_wsmux_device_sz = sizeof(wsmux_device); +unsigned struct_xd_iocmd_sz = sizeof(xd_iocmd); + +unsigned struct_scsireq_sz = sizeof(struct scsireq); +unsigned struct_tone_sz = sizeof(tone_t); +unsigned union_twe_statrequest_sz = sizeof(union twe_statrequest); +unsigned struct_usb_device_descriptor_sz = sizeof(usb_device_descriptor_t); +unsigned struct_vt_mode_sz = sizeof(struct vt_mode); +unsigned struct__old_mixer_info_sz = sizeof(struct _old_mixer_info); +unsigned struct__agp_allocate_sz = sizeof(struct _agp_allocate); +unsigned struct__agp_bind_sz = sizeof(struct _agp_bind); +unsigned struct__agp_info_sz = sizeof(struct _agp_info); +unsigned struct__agp_setup_sz = sizeof(struct _agp_setup); +unsigned struct__agp_unbind_sz = sizeof(struct _agp_unbind); +unsigned struct_atareq_sz = sizeof(struct atareq); +unsigned struct_cpustate_sz = sizeof(struct cpustate); +unsigned struct_dmx_caps_sz = sizeof(struct dmx_caps); +unsigned enum_dmx_source_sz = sizeof(dmx_source_t); +unsigned union_dvd_authinfo_sz = sizeof(dvd_authinfo); +unsigned union_dvd_struct_sz = sizeof(dvd_struct); +unsigned enum_v4l2_priority_sz = sizeof(enum v4l2_priority); +unsigned struct_envsys_basic_info_sz = sizeof(struct envsys_basic_info); +unsigned struct_envsys_tre_data_sz = sizeof(struct envsys_tre_data); +unsigned enum_fe_sec_mini_cmd_sz = sizeof(enum fe_sec_mini_cmd); +unsigned enum_fe_sec_tone_mode_sz = sizeof(enum fe_sec_tone_mode); +unsigned enum_fe_sec_voltage_sz = sizeof(enum fe_sec_voltage); +unsigned enum_fe_status_sz = sizeof(enum fe_status); +unsigned struct_gdt_ctrt_sz = sizeof(struct gdt_ctrt); +unsigned struct_gdt_event_sz = sizeof(struct gdt_event); +unsigned struct_gdt_osv_sz = sizeof(struct gdt_osv); +unsigned struct_gdt_rescan_sz = sizeof(struct gdt_rescan); +unsigned struct_gdt_statist_sz = sizeof(struct gdt_statist); +unsigned struct_gdt_ucmd_sz = sizeof(struct gdt_ucmd); +unsigned struct_iscsi_conn_status_parameters_sz = +    sizeof(iscsi_conn_status_parameters_t); +unsigned struct_iscsi_get_version_parameters_sz = +    sizeof(iscsi_get_version_parameters_t); +unsigned struct_iscsi_iocommand_parameters_sz = +    sizeof(iscsi_iocommand_parameters_t); +unsigned struct_iscsi_login_parameters_sz = sizeof(iscsi_login_parameters_t); +unsigned struct_iscsi_logout_parameters_sz = sizeof(iscsi_logout_parameters_t); +unsigned struct_iscsi_register_event_parameters_sz = +    sizeof(iscsi_register_event_parameters_t); +unsigned struct_iscsi_remove_parameters_sz = sizeof(iscsi_remove_parameters_t); +unsigned struct_iscsi_send_targets_parameters_sz = +    sizeof(iscsi_send_targets_parameters_t); +unsigned struct_iscsi_set_node_name_parameters_sz = +    sizeof(iscsi_set_node_name_parameters_t); +unsigned struct_iscsi_wait_event_parameters_sz = +    sizeof(iscsi_wait_event_parameters_t); +unsigned struct_isp_stats_sz = sizeof(isp_stats_t); +unsigned struct_lsenable_sz = sizeof(struct lsenable); +unsigned struct_lsdisable_sz = sizeof(struct lsdisable); +unsigned struct_mixer_ctrl_sz = sizeof(struct mixer_ctrl); +unsigned struct_mixer_devinfo_sz = sizeof(struct mixer_devinfo); +unsigned struct_mpu_command_rec_sz = sizeof(mpu_command_rec); +unsigned struct_rndstat_sz = sizeof(rndstat_t); +unsigned struct_rndstat_name_sz = sizeof(rndstat_name_t); +unsigned struct_rndctl_sz = sizeof(rndctl_t); +unsigned struct_rnddata_sz = sizeof(rnddata_t); +unsigned struct_rndpoolstat_sz = sizeof(rndpoolstat_t); +unsigned struct_rndstat_est_sz = sizeof(rndstat_est_t); +unsigned struct_rndstat_est_name_sz = sizeof(rndstat_est_name_t); +unsigned struct_pps_params_sz = sizeof(pps_params_t); +unsigned struct_pps_info_sz = sizeof(pps_info_t); +unsigned struct_mixer_info_sz = sizeof(struct mixer_info); +unsigned struct_RF_SparetWait_sz = sizeof(RF_SparetWait_t); +unsigned struct_RF_ComponentLabel_sz = sizeof(RF_ComponentLabel_t); +unsigned struct_RF_SingleComponent_sz = sizeof(RF_SingleComponent_t); +unsigned struct_RF_ProgressInfo_sz = sizeof(RF_ProgressInfo_t);  const unsigned IOCTL_NOT_PRESENT = 0; -unsigned IOCTL_FIOASYNC = FIOASYNC; +unsigned IOCTL_AFM_ADDFMAP = AFM_ADDFMAP; +unsigned IOCTL_AFM_DELFMAP = AFM_DELFMAP; +unsigned IOCTL_AFM_CLEANFMAP = AFM_CLEANFMAP; +unsigned IOCTL_AFM_GETFMAP = AFM_GETFMAP; +unsigned IOCTL_ALTQGTYPE = ALTQGTYPE; +unsigned IOCTL_ALTQTBRSET = ALTQTBRSET; +unsigned IOCTL_ALTQTBRGET = ALTQTBRGET; +unsigned IOCTL_BLUE_IF_ATTACH = BLUE_IF_ATTACH; +unsigned IOCTL_BLUE_IF_DETACH = BLUE_IF_DETACH; +unsigned IOCTL_BLUE_ENABLE = BLUE_ENABLE; +unsigned IOCTL_BLUE_DISABLE = BLUE_DISABLE; +unsigned IOCTL_BLUE_CONFIG = BLUE_CONFIG; +unsigned IOCTL_BLUE_GETSTATS = BLUE_GETSTATS; +unsigned IOCTL_CBQ_IF_ATTACH = CBQ_IF_ATTACH; +unsigned IOCTL_CBQ_IF_DETACH = CBQ_IF_DETACH; +unsigned IOCTL_CBQ_ENABLE = CBQ_ENABLE; +unsigned IOCTL_CBQ_DISABLE = CBQ_DISABLE; +unsigned IOCTL_CBQ_CLEAR_HIERARCHY = CBQ_CLEAR_HIERARCHY; +unsigned IOCTL_CBQ_ADD_CLASS = CBQ_ADD_CLASS; +unsigned IOCTL_CBQ_DEL_CLASS = CBQ_DEL_CLASS; +unsigned IOCTL_CBQ_MODIFY_CLASS = CBQ_MODIFY_CLASS; +unsigned IOCTL_CBQ_ADD_FILTER = CBQ_ADD_FILTER; +unsigned IOCTL_CBQ_DEL_FILTER = CBQ_DEL_FILTER; +unsigned IOCTL_CBQ_GETSTATS = CBQ_GETSTATS; +unsigned IOCTL_CDNR_IF_ATTACH = CDNR_IF_ATTACH; +unsigned IOCTL_CDNR_IF_DETACH = CDNR_IF_DETACH; +unsigned IOCTL_CDNR_ENABLE = CDNR_ENABLE; +unsigned IOCTL_CDNR_DISABLE = CDNR_DISABLE; +unsigned IOCTL_CDNR_ADD_FILTER = CDNR_ADD_FILTER; +unsigned IOCTL_CDNR_DEL_FILTER = CDNR_DEL_FILTER; +unsigned IOCTL_CDNR_GETSTATS = CDNR_GETSTATS; +unsigned IOCTL_CDNR_ADD_ELEM = CDNR_ADD_ELEM; +unsigned IOCTL_CDNR_DEL_ELEM = CDNR_DEL_ELEM; +unsigned IOCTL_CDNR_ADD_TBM = CDNR_ADD_TBM; +unsigned IOCTL_CDNR_MOD_TBM = CDNR_MOD_TBM; +unsigned IOCTL_CDNR_TBM_STATS = CDNR_TBM_STATS; +unsigned IOCTL_CDNR_ADD_TCM = CDNR_ADD_TCM; +unsigned IOCTL_CDNR_MOD_TCM = CDNR_MOD_TCM; +unsigned IOCTL_CDNR_TCM_STATS = CDNR_TCM_STATS; +unsigned IOCTL_CDNR_ADD_TSW = CDNR_ADD_TSW; +unsigned IOCTL_CDNR_MOD_TSW = CDNR_MOD_TSW; +unsigned IOCTL_FIFOQ_IF_ATTACH = FIFOQ_IF_ATTACH; +unsigned IOCTL_FIFOQ_IF_DETACH = FIFOQ_IF_DETACH; +unsigned IOCTL_FIFOQ_ENABLE = FIFOQ_ENABLE; +unsigned IOCTL_FIFOQ_DISABLE = FIFOQ_DISABLE; +unsigned IOCTL_FIFOQ_CONFIG = FIFOQ_CONFIG; +unsigned IOCTL_FIFOQ_GETSTATS = FIFOQ_GETSTATS; +unsigned IOCTL_HFSC_IF_ATTACH = HFSC_IF_ATTACH; +unsigned IOCTL_HFSC_IF_DETACH = HFSC_IF_DETACH; +unsigned IOCTL_HFSC_ENABLE = HFSC_ENABLE; +unsigned IOCTL_HFSC_DISABLE = HFSC_DISABLE; +unsigned IOCTL_HFSC_CLEAR_HIERARCHY = HFSC_CLEAR_HIERARCHY; +unsigned IOCTL_HFSC_ADD_CLASS = HFSC_ADD_CLASS; +unsigned IOCTL_HFSC_DEL_CLASS = HFSC_DEL_CLASS; +unsigned IOCTL_HFSC_MOD_CLASS = HFSC_MOD_CLASS; +unsigned IOCTL_HFSC_ADD_FILTER = HFSC_ADD_FILTER; +unsigned IOCTL_HFSC_DEL_FILTER = HFSC_DEL_FILTER; +unsigned IOCTL_HFSC_GETSTATS = HFSC_GETSTATS; +unsigned IOCTL_JOBS_IF_ATTACH = JOBS_IF_ATTACH; +unsigned IOCTL_JOBS_IF_DETACH = JOBS_IF_DETACH; +unsigned IOCTL_JOBS_ENABLE = JOBS_ENABLE; +unsigned IOCTL_JOBS_DISABLE = JOBS_DISABLE; +unsigned IOCTL_JOBS_CLEAR = JOBS_CLEAR; +unsigned IOCTL_JOBS_ADD_CLASS = JOBS_ADD_CLASS; +unsigned IOCTL_JOBS_DEL_CLASS = JOBS_DEL_CLASS; +unsigned IOCTL_JOBS_MOD_CLASS = JOBS_MOD_CLASS; +unsigned IOCTL_JOBS_ADD_FILTER = JOBS_ADD_FILTER; +unsigned IOCTL_JOBS_DEL_FILTER = JOBS_DEL_FILTER; +unsigned IOCTL_JOBS_GETSTATS = JOBS_GETSTATS; +unsigned IOCTL_PRIQ_IF_ATTACH = PRIQ_IF_ATTACH; +unsigned IOCTL_PRIQ_IF_DETACH = PRIQ_IF_DETACH; +unsigned IOCTL_PRIQ_ENABLE = PRIQ_ENABLE; +unsigned IOCTL_PRIQ_DISABLE = PRIQ_DISABLE; +unsigned IOCTL_PRIQ_CLEAR = PRIQ_CLEAR; +unsigned IOCTL_PRIQ_ADD_CLASS = PRIQ_ADD_CLASS; +unsigned IOCTL_PRIQ_DEL_CLASS = PRIQ_DEL_CLASS; +unsigned IOCTL_PRIQ_MOD_CLASS = PRIQ_MOD_CLASS; +unsigned IOCTL_PRIQ_ADD_FILTER = PRIQ_ADD_FILTER; +unsigned IOCTL_PRIQ_DEL_FILTER = PRIQ_DEL_FILTER; +unsigned IOCTL_PRIQ_GETSTATS = PRIQ_GETSTATS; +unsigned IOCTL_RED_IF_ATTACH = RED_IF_ATTACH; +unsigned IOCTL_RED_IF_DETACH = RED_IF_DETACH; +unsigned IOCTL_RED_ENABLE = RED_ENABLE; +unsigned IOCTL_RED_DISABLE = RED_DISABLE; +unsigned IOCTL_RED_CONFIG = RED_CONFIG; +unsigned IOCTL_RED_GETSTATS = RED_GETSTATS; +unsigned IOCTL_RED_SETDEFAULTS = RED_SETDEFAULTS; +unsigned IOCTL_RIO_IF_ATTACH = RIO_IF_ATTACH; +unsigned IOCTL_RIO_IF_DETACH = RIO_IF_DETACH; +unsigned IOCTL_RIO_ENABLE = RIO_ENABLE; +unsigned IOCTL_RIO_DISABLE = RIO_DISABLE; +unsigned IOCTL_RIO_CONFIG = RIO_CONFIG; +unsigned IOCTL_RIO_GETSTATS = RIO_GETSTATS; +unsigned IOCTL_RIO_SETDEFAULTS = RIO_SETDEFAULTS; +unsigned IOCTL_WFQ_IF_ATTACH = WFQ_IF_ATTACH; +unsigned IOCTL_WFQ_IF_DETACH = WFQ_IF_DETACH; +unsigned IOCTL_WFQ_ENABLE = WFQ_ENABLE; +unsigned IOCTL_WFQ_DISABLE = WFQ_DISABLE; +unsigned IOCTL_WFQ_CONFIG = WFQ_CONFIG; +unsigned IOCTL_WFQ_GET_STATS = WFQ_GET_STATS; +unsigned IOCTL_WFQ_GET_QID = WFQ_GET_QID; +unsigned IOCTL_WFQ_SET_WEIGHT = WFQ_SET_WEIGHT; +unsigned IOCTL_CRIOGET = CRIOGET; +unsigned IOCTL_CIOCFSESSION = CIOCFSESSION; +unsigned IOCTL_CIOCKEY = CIOCKEY; +unsigned IOCTL_CIOCNFKEYM = CIOCNFKEYM; +unsigned IOCTL_CIOCNFSESSION = CIOCNFSESSION; +unsigned IOCTL_CIOCNCRYPTRETM = CIOCNCRYPTRETM; +unsigned IOCTL_CIOCNCRYPTRET = CIOCNCRYPTRET; +unsigned IOCTL_CIOCGSESSION = CIOCGSESSION; +unsigned IOCTL_CIOCNGSESSION = CIOCNGSESSION; +unsigned IOCTL_CIOCCRYPT = CIOCCRYPT; +unsigned IOCTL_CIOCNCRYPTM = CIOCNCRYPTM; +unsigned IOCTL_CIOCASYMFEAT = CIOCASYMFEAT; +unsigned IOCTL_APM_IOC_REJECT = APM_IOC_REJECT; +unsigned IOCTL_APM_IOC_STANDBY = APM_IOC_STANDBY; +unsigned IOCTL_APM_IOC_SUSPEND = APM_IOC_SUSPEND; +unsigned IOCTL_OAPM_IOC_GETPOWER = OAPM_IOC_GETPOWER; +unsigned IOCTL_APM_IOC_GETPOWER = APM_IOC_GETPOWER; +unsigned IOCTL_APM_IOC_NEXTEVENT = APM_IOC_NEXTEVENT; +unsigned IOCTL_APM_IOC_DEV_CTL = APM_IOC_DEV_CTL; +unsigned IOCTL_NETBSD_DM_IOCTL = NETBSD_DM_IOCTL; +unsigned IOCTL_DMIO_SETFUNC = DMIO_SETFUNC; +unsigned IOCTL_DMX_START = DMX_START; +unsigned IOCTL_DMX_STOP = DMX_STOP; +unsigned IOCTL_DMX_SET_FILTER = DMX_SET_FILTER; +unsigned IOCTL_DMX_SET_PES_FILTER = DMX_SET_PES_FILTER; +unsigned IOCTL_DMX_SET_BUFFER_SIZE = DMX_SET_BUFFER_SIZE; +unsigned IOCTL_DMX_GET_STC = DMX_GET_STC; +unsigned IOCTL_DMX_ADD_PID = DMX_ADD_PID; +unsigned IOCTL_DMX_REMOVE_PID = DMX_REMOVE_PID; +unsigned IOCTL_DMX_GET_CAPS = DMX_GET_CAPS; +unsigned IOCTL_DMX_SET_SOURCE = DMX_SET_SOURCE; +unsigned IOCTL_FE_READ_STATUS = FE_READ_STATUS; +unsigned IOCTL_FE_READ_BER = FE_READ_BER; +unsigned IOCTL_FE_READ_SNR = FE_READ_SNR; +unsigned IOCTL_FE_READ_SIGNAL_STRENGTH = FE_READ_SIGNAL_STRENGTH; +unsigned IOCTL_FE_READ_UNCORRECTED_BLOCKS = FE_READ_UNCORRECTED_BLOCKS; +unsigned IOCTL_FE_SET_FRONTEND = FE_SET_FRONTEND; +unsigned IOCTL_FE_GET_FRONTEND = FE_GET_FRONTEND; +unsigned IOCTL_FE_GET_EVENT = FE_GET_EVENT; +unsigned IOCTL_FE_GET_INFO = FE_GET_INFO; +unsigned IOCTL_FE_DISEQC_RESET_OVERLOAD = FE_DISEQC_RESET_OVERLOAD; +unsigned IOCTL_FE_DISEQC_SEND_MASTER_CMD = FE_DISEQC_SEND_MASTER_CMD; +unsigned IOCTL_FE_DISEQC_RECV_SLAVE_REPLY = FE_DISEQC_RECV_SLAVE_REPLY; +unsigned IOCTL_FE_DISEQC_SEND_BURST = FE_DISEQC_SEND_BURST; +unsigned IOCTL_FE_SET_TONE = FE_SET_TONE; +unsigned IOCTL_FE_SET_VOLTAGE = FE_SET_VOLTAGE; +unsigned IOCTL_FE_ENABLE_HIGH_LNB_VOLTAGE = FE_ENABLE_HIGH_LNB_VOLTAGE; +unsigned IOCTL_FE_SET_FRONTEND_TUNE_MODE = FE_SET_FRONTEND_TUNE_MODE; +unsigned IOCTL_FE_DISHNETWORK_SEND_LEGACY_CMD = FE_DISHNETWORK_SEND_LEGACY_CMD; +unsigned IOCTL_FILEMON_SET_FD = FILEMON_SET_FD; +unsigned IOCTL_FILEMON_SET_PID = FILEMON_SET_PID; +unsigned IOCTL_HDAUDIO_FGRP_INFO = HDAUDIO_FGRP_INFO; +unsigned IOCTL_HDAUDIO_FGRP_GETCONFIG = HDAUDIO_FGRP_GETCONFIG; +unsigned IOCTL_HDAUDIO_FGRP_SETCONFIG = HDAUDIO_FGRP_SETCONFIG; +unsigned IOCTL_HDAUDIO_FGRP_WIDGET_INFO = HDAUDIO_FGRP_WIDGET_INFO; +unsigned IOCTL_HDAUDIO_FGRP_CODEC_INFO = HDAUDIO_FGRP_CODEC_INFO; +unsigned IOCTL_HDAUDIO_AFG_WIDGET_INFO = HDAUDIO_AFG_WIDGET_INFO; +unsigned IOCTL_HDAUDIO_AFG_CODEC_INFO = HDAUDIO_AFG_CODEC_INFO; +unsigned IOCTL_CEC_GET_PHYS_ADDR = CEC_GET_PHYS_ADDR; +unsigned IOCTL_CEC_GET_LOG_ADDRS = CEC_GET_LOG_ADDRS; +unsigned IOCTL_CEC_SET_LOG_ADDRS = CEC_SET_LOG_ADDRS; +unsigned IOCTL_CEC_GET_VENDOR_ID = CEC_GET_VENDOR_ID; +unsigned IOCTL_HPCFBIO_GCONF = HPCFBIO_GCONF; +unsigned IOCTL_HPCFBIO_SCONF = HPCFBIO_SCONF; +unsigned IOCTL_HPCFBIO_GDSPCONF = HPCFBIO_GDSPCONF; +unsigned IOCTL_HPCFBIO_SDSPCONF = HPCFBIO_SDSPCONF; +unsigned IOCTL_HPCFBIO_GOP = HPCFBIO_GOP; +unsigned IOCTL_HPCFBIO_SOP = HPCFBIO_SOP; +unsigned IOCTL_IOPIOCPT = IOPIOCPT; +unsigned IOCTL_IOPIOCGLCT = IOPIOCGLCT; +unsigned IOCTL_IOPIOCGSTATUS = IOPIOCGSTATUS; +unsigned IOCTL_IOPIOCRECONFIG = IOPIOCRECONFIG; +unsigned IOCTL_IOPIOCGTIDMAP = IOPIOCGTIDMAP; +unsigned IOCTL_SIOCGATHSTATS = SIOCGATHSTATS; +unsigned IOCTL_SIOCGATHDIAG = SIOCGATHDIAG; +unsigned IOCTL_METEORCAPTUR = METEORCAPTUR; +unsigned IOCTL_METEORCAPFRM = METEORCAPFRM; +unsigned IOCTL_METEORSETGEO = METEORSETGEO; +unsigned IOCTL_METEORGETGEO = METEORGETGEO; +unsigned IOCTL_METEORSTATUS = METEORSTATUS; +unsigned IOCTL_METEORSHUE = METEORSHUE; +unsigned IOCTL_METEORGHUE = METEORGHUE; +unsigned IOCTL_METEORSFMT = METEORSFMT; +unsigned IOCTL_METEORGFMT = METEORGFMT; +unsigned IOCTL_METEORSINPUT = METEORSINPUT; +unsigned IOCTL_METEORGINPUT = METEORGINPUT; +unsigned IOCTL_METEORSCHCV = METEORSCHCV; +unsigned IOCTL_METEORGCHCV = METEORGCHCV; +unsigned IOCTL_METEORSCOUNT = METEORSCOUNT; +unsigned IOCTL_METEORGCOUNT = METEORGCOUNT; +unsigned IOCTL_METEORSFPS = METEORSFPS; +unsigned IOCTL_METEORGFPS = METEORGFPS; +unsigned IOCTL_METEORSSIGNAL = METEORSSIGNAL; +unsigned IOCTL_METEORGSIGNAL = METEORGSIGNAL; +unsigned IOCTL_METEORSVIDEO = METEORSVIDEO; +unsigned IOCTL_METEORGVIDEO = METEORGVIDEO; +unsigned IOCTL_METEORSBRIG = METEORSBRIG; +unsigned IOCTL_METEORGBRIG = METEORGBRIG; +unsigned IOCTL_METEORSCSAT = METEORSCSAT; +unsigned IOCTL_METEORGCSAT = METEORGCSAT; +unsigned IOCTL_METEORSCONT = METEORSCONT; +unsigned IOCTL_METEORGCONT = METEORGCONT; +unsigned IOCTL_METEORSHWS = METEORSHWS; +unsigned IOCTL_METEORGHWS = METEORGHWS; +unsigned IOCTL_METEORSVWS = METEORSVWS; +unsigned IOCTL_METEORGVWS = METEORGVWS; +unsigned IOCTL_METEORSTS = METEORSTS; +unsigned IOCTL_METEORGTS = METEORGTS; +unsigned IOCTL_TVTUNER_SETCHNL = TVTUNER_SETCHNL; +unsigned IOCTL_TVTUNER_GETCHNL = TVTUNER_GETCHNL; +unsigned IOCTL_TVTUNER_SETTYPE = TVTUNER_SETTYPE; +unsigned IOCTL_TVTUNER_GETTYPE = TVTUNER_GETTYPE; +unsigned IOCTL_TVTUNER_GETSTATUS = TVTUNER_GETSTATUS; +unsigned IOCTL_TVTUNER_SETFREQ = TVTUNER_SETFREQ; +unsigned IOCTL_TVTUNER_GETFREQ = TVTUNER_GETFREQ; +unsigned IOCTL_TVTUNER_SETAFC = TVTUNER_SETAFC; +unsigned IOCTL_TVTUNER_GETAFC = TVTUNER_GETAFC; +unsigned IOCTL_RADIO_SETMODE = RADIO_SETMODE; +unsigned IOCTL_RADIO_GETMODE = RADIO_GETMODE; +unsigned IOCTL_RADIO_SETFREQ = RADIO_SETFREQ; +unsigned IOCTL_RADIO_GETFREQ = RADIO_GETFREQ; +unsigned IOCTL_METEORSACTPIXFMT = METEORSACTPIXFMT; +unsigned IOCTL_METEORGACTPIXFMT = METEORGACTPIXFMT; +unsigned IOCTL_METEORGSUPPIXFMT = METEORGSUPPIXFMT; +unsigned IOCTL_TVTUNER_GETCHNLSET = TVTUNER_GETCHNLSET; +unsigned IOCTL_REMOTE_GETKEY = REMOTE_GETKEY; +unsigned IOCTL_GDT_IOCTL_GENERAL = GDT_IOCTL_GENERAL; +unsigned IOCTL_GDT_IOCTL_DRVERS = GDT_IOCTL_DRVERS; +unsigned IOCTL_GDT_IOCTL_CTRTYPE = GDT_IOCTL_CTRTYPE; +unsigned IOCTL_GDT_IOCTL_OSVERS = GDT_IOCTL_OSVERS; +unsigned IOCTL_GDT_IOCTL_CTRCNT = GDT_IOCTL_CTRCNT; +unsigned IOCTL_GDT_IOCTL_EVENT = GDT_IOCTL_EVENT; +unsigned IOCTL_GDT_IOCTL_STATIST = GDT_IOCTL_STATIST; +unsigned IOCTL_GDT_IOCTL_RESCAN = GDT_IOCTL_RESCAN; +unsigned IOCTL_ISP_SDBLEV = ISP_SDBLEV; +unsigned IOCTL_ISP_RESETHBA = ISP_RESETHBA; +unsigned IOCTL_ISP_RESCAN = ISP_RESCAN; +unsigned IOCTL_ISP_SETROLE = ISP_SETROLE; +unsigned IOCTL_ISP_GETROLE = ISP_GETROLE; +unsigned IOCTL_ISP_GET_STATS = ISP_GET_STATS; +unsigned IOCTL_ISP_CLR_STATS = ISP_CLR_STATS; +unsigned IOCTL_ISP_FC_LIP = ISP_FC_LIP; +unsigned IOCTL_ISP_FC_GETDINFO = ISP_FC_GETDINFO; +unsigned IOCTL_ISP_GET_FW_CRASH_DUMP = ISP_GET_FW_CRASH_DUMP; +unsigned IOCTL_ISP_FORCE_CRASH_DUMP = ISP_FORCE_CRASH_DUMP; +unsigned IOCTL_ISP_FC_GETHINFO = ISP_FC_GETHINFO; +unsigned IOCTL_ISP_TSK_MGMT = ISP_TSK_MGMT; +unsigned IOCTL_ISP_FC_GETDLIST = ISP_FC_GETDLIST; +unsigned IOCTL_MLXD_STATUS = MLXD_STATUS; +unsigned IOCTL_MLXD_CHECKASYNC = MLXD_CHECKASYNC; +unsigned IOCTL_MLXD_DETACH = MLXD_DETACH; +unsigned IOCTL_MLX_RESCAN_DRIVES = MLX_RESCAN_DRIVES; +unsigned IOCTL_MLX_PAUSE_CHANNEL = MLX_PAUSE_CHANNEL; +unsigned IOCTL_MLX_COMMAND = MLX_COMMAND; +unsigned IOCTL_MLX_REBUILDASYNC = MLX_REBUILDASYNC; +unsigned IOCTL_MLX_REBUILDSTAT = MLX_REBUILDSTAT; +unsigned IOCTL_MLX_GET_SYSDRIVE = MLX_GET_SYSDRIVE; +unsigned IOCTL_MLX_GET_CINFO = MLX_GET_CINFO; +unsigned IOCTL_NVME_PASSTHROUGH_CMD = NVME_PASSTHROUGH_CMD; +unsigned IOCTL_IRDA_RESET_PARAMS = IRDA_RESET_PARAMS; +unsigned IOCTL_IRDA_SET_PARAMS = IRDA_SET_PARAMS; +unsigned IOCTL_IRDA_GET_SPEEDMASK = IRDA_GET_SPEEDMASK; +unsigned IOCTL_IRDA_GET_TURNAROUNDMASK = IRDA_GET_TURNAROUNDMASK; +unsigned IOCTL_IRFRAMETTY_GET_DEVICE = IRFRAMETTY_GET_DEVICE; +unsigned IOCTL_IRFRAMETTY_GET_DONGLE = IRFRAMETTY_GET_DONGLE; +unsigned IOCTL_IRFRAMETTY_SET_DONGLE = IRFRAMETTY_SET_DONGLE; +unsigned IOCTL_SATIORESET = SATIORESET; +unsigned IOCTL_SATIOGID = SATIOGID; +unsigned IOCTL_SATIOSBUFSIZE = SATIOSBUFSIZE; +unsigned IOCTL_ISV_CMD = ISV_CMD; +unsigned IOCTL_WTQICMD = WTQICMD; +unsigned IOCTL_ISCSI_GET_VERSION = ISCSI_GET_VERSION; +unsigned IOCTL_ISCSI_LOGIN = ISCSI_LOGIN; +unsigned IOCTL_ISCSI_LOGOUT = ISCSI_LOGOUT; +unsigned IOCTL_ISCSI_ADD_CONNECTION = ISCSI_ADD_CONNECTION; +unsigned IOCTL_ISCSI_RESTORE_CONNECTION = ISCSI_RESTORE_CONNECTION; +unsigned IOCTL_ISCSI_REMOVE_CONNECTION = ISCSI_REMOVE_CONNECTION; +unsigned IOCTL_ISCSI_CONNECTION_STATUS = ISCSI_CONNECTION_STATUS; +unsigned IOCTL_ISCSI_SEND_TARGETS = ISCSI_SEND_TARGETS; +unsigned IOCTL_ISCSI_SET_NODE_NAME = ISCSI_SET_NODE_NAME; +unsigned IOCTL_ISCSI_IO_COMMAND = ISCSI_IO_COMMAND; +unsigned IOCTL_ISCSI_REGISTER_EVENT = ISCSI_REGISTER_EVENT; +unsigned IOCTL_ISCSI_DEREGISTER_EVENT = ISCSI_DEREGISTER_EVENT; +unsigned IOCTL_ISCSI_WAIT_EVENT = ISCSI_WAIT_EVENT; +unsigned IOCTL_ISCSI_POLL_EVENT = ISCSI_POLL_EVENT; +unsigned IOCTL_OFIOCGET = OFIOCGET; +unsigned IOCTL_OFIOCSET = OFIOCSET; +unsigned IOCTL_OFIOCNEXTPROP = OFIOCNEXTPROP; +unsigned IOCTL_OFIOCGETOPTNODE = OFIOCGETOPTNODE; +unsigned IOCTL_OFIOCGETNEXT = OFIOCGETNEXT; +unsigned IOCTL_OFIOCGETCHILD = OFIOCGETCHILD; +unsigned IOCTL_OFIOCFINDDEVICE = OFIOCFINDDEVICE; +unsigned IOCTL_AMR_IO_VERSION = AMR_IO_VERSION; +unsigned IOCTL_AMR_IO_COMMAND = AMR_IO_COMMAND; +unsigned IOCTL_MLYIO_COMMAND = MLYIO_COMMAND; +unsigned IOCTL_MLYIO_HEALTH = MLYIO_HEALTH; +unsigned IOCTL_PCI_IOC_CFGREAD = PCI_IOC_CFGREAD; +unsigned IOCTL_PCI_IOC_CFGWRITE = PCI_IOC_CFGWRITE; +unsigned IOCTL_PCI_IOC_BDF_CFGREAD = PCI_IOC_BDF_CFGREAD; +unsigned IOCTL_PCI_IOC_BDF_CFGWRITE = PCI_IOC_BDF_CFGWRITE; +unsigned IOCTL_PCI_IOC_BUSINFO = PCI_IOC_BUSINFO; +unsigned IOCTL_PCI_IOC_DRVNAME = PCI_IOC_DRVNAME; +unsigned IOCTL_PCI_IOC_DRVNAMEONBUS = PCI_IOC_DRVNAMEONBUS; +unsigned IOCTL_TWEIO_COMMAND = TWEIO_COMMAND; +unsigned IOCTL_TWEIO_STATS = TWEIO_STATS; +unsigned IOCTL_TWEIO_AEN_POLL = TWEIO_AEN_POLL; +unsigned IOCTL_TWEIO_AEN_WAIT = TWEIO_AEN_WAIT; +unsigned IOCTL_TWEIO_SET_PARAM = TWEIO_SET_PARAM; +unsigned IOCTL_TWEIO_GET_PARAM = TWEIO_GET_PARAM; +unsigned IOCTL_TWEIO_RESET = TWEIO_RESET; +unsigned IOCTL_TWEIO_ADD_UNIT = TWEIO_ADD_UNIT; +unsigned IOCTL_TWEIO_DEL_UNIT = TWEIO_DEL_UNIT; +unsigned IOCTL_SIOCSCNWDOMAIN = SIOCSCNWDOMAIN; +unsigned IOCTL_SIOCGCNWDOMAIN = SIOCGCNWDOMAIN; +unsigned IOCTL_SIOCSCNWKEY = SIOCSCNWKEY; +unsigned IOCTL_SIOCGCNWSTATUS = SIOCGCNWSTATUS; +unsigned IOCTL_SIOCGCNWSTATS = SIOCGCNWSTATS; +unsigned IOCTL_SIOCGCNWTRAIL = SIOCGCNWTRAIL; +unsigned IOCTL_SIOCGRAYSIGLEV = SIOCGRAYSIGLEV; +unsigned IOCTL_RAIDFRAME_SHUTDOWN = RAIDFRAME_SHUTDOWN; +unsigned IOCTL_RAIDFRAME_TUR = RAIDFRAME_TUR; +unsigned IOCTL_RAIDFRAME_FAIL_DISK = RAIDFRAME_FAIL_DISK; +unsigned IOCTL_RAIDFRAME_CHECK_RECON_STATUS = RAIDFRAME_CHECK_RECON_STATUS; +unsigned IOCTL_RAIDFRAME_REWRITEPARITY = RAIDFRAME_REWRITEPARITY; +unsigned IOCTL_RAIDFRAME_COPYBACK = RAIDFRAME_COPYBACK; +unsigned IOCTL_RAIDFRAME_SPARET_WAIT = RAIDFRAME_SPARET_WAIT; +unsigned IOCTL_RAIDFRAME_SEND_SPARET = RAIDFRAME_SEND_SPARET; +unsigned IOCTL_RAIDFRAME_ABORT_SPARET_WAIT = RAIDFRAME_ABORT_SPARET_WAIT; +unsigned IOCTL_RAIDFRAME_START_ATRACE = RAIDFRAME_START_ATRACE; +unsigned IOCTL_RAIDFRAME_STOP_ATRACE = RAIDFRAME_STOP_ATRACE; +unsigned IOCTL_RAIDFRAME_GET_SIZE = RAIDFRAME_GET_SIZE; +unsigned IOCTL_RAIDFRAME_RESET_ACCTOTALS = RAIDFRAME_RESET_ACCTOTALS; +unsigned IOCTL_RAIDFRAME_KEEP_ACCTOTALS = RAIDFRAME_KEEP_ACCTOTALS; +unsigned IOCTL_RAIDFRAME_GET_COMPONENT_LABEL = RAIDFRAME_GET_COMPONENT_LABEL; +unsigned IOCTL_RAIDFRAME_SET_COMPONENT_LABEL = RAIDFRAME_SET_COMPONENT_LABEL; +unsigned IOCTL_RAIDFRAME_INIT_LABELS = RAIDFRAME_INIT_LABELS; +unsigned IOCTL_RAIDFRAME_ADD_HOT_SPARE = RAIDFRAME_ADD_HOT_SPARE; +unsigned IOCTL_RAIDFRAME_REMOVE_HOT_SPARE = RAIDFRAME_REMOVE_HOT_SPARE; +unsigned IOCTL_RAIDFRAME_REBUILD_IN_PLACE = RAIDFRAME_REBUILD_IN_PLACE; +unsigned IOCTL_RAIDFRAME_CHECK_PARITY = RAIDFRAME_CHECK_PARITY; +unsigned IOCTL_RAIDFRAME_CHECK_PARITYREWRITE_STATUS = +    RAIDFRAME_CHECK_PARITYREWRITE_STATUS; +unsigned IOCTL_RAIDFRAME_CHECK_COPYBACK_STATUS = +    RAIDFRAME_CHECK_COPYBACK_STATUS; +unsigned IOCTL_RAIDFRAME_SET_AUTOCONFIG = RAIDFRAME_SET_AUTOCONFIG; +unsigned IOCTL_RAIDFRAME_SET_ROOT = RAIDFRAME_SET_ROOT; +unsigned IOCTL_RAIDFRAME_DELETE_COMPONENT = RAIDFRAME_DELETE_COMPONENT; +unsigned IOCTL_RAIDFRAME_INCORPORATE_HOT_SPARE = +    RAIDFRAME_INCORPORATE_HOT_SPARE; +unsigned IOCTL_RAIDFRAME_CHECK_RECON_STATUS_EXT = +    RAIDFRAME_CHECK_RECON_STATUS_EXT; +unsigned IOCTL_RAIDFRAME_CHECK_PARITYREWRITE_STATUS_EXT = +    RAIDFRAME_CHECK_PARITYREWRITE_STATUS_EXT; +unsigned IOCTL_RAIDFRAME_CHECK_COPYBACK_STATUS_EXT = +    RAIDFRAME_CHECK_COPYBACK_STATUS_EXT; +unsigned IOCTL_RAIDFRAME_CONFIGURE = RAIDFRAME_CONFIGURE; +unsigned IOCTL_RAIDFRAME_GET_INFO = RAIDFRAME_GET_INFO; +unsigned IOCTL_RAIDFRAME_PARITYMAP_STATUS = RAIDFRAME_PARITYMAP_STATUS; +unsigned IOCTL_RAIDFRAME_PARITYMAP_GET_DISABLE = +    RAIDFRAME_PARITYMAP_GET_DISABLE; +unsigned IOCTL_RAIDFRAME_PARITYMAP_SET_DISABLE = +    RAIDFRAME_PARITYMAP_SET_DISABLE; +unsigned IOCTL_RAIDFRAME_PARITYMAP_SET_PARAMS = RAIDFRAME_PARITYMAP_SET_PARAMS; +unsigned IOCTL_RAIDFRAME_SET_LAST_UNIT = RAIDFRAME_SET_LAST_UNIT; +unsigned IOCTL_MBPPIOCSPARAM = MBPPIOCSPARAM; +unsigned IOCTL_MBPPIOCGPARAM = MBPPIOCGPARAM; +unsigned IOCTL_MBPPIOCGSTAT = MBPPIOCGSTAT; +unsigned IOCTL_SESIOC_GETNOBJ = SESIOC_GETNOBJ; +unsigned IOCTL_SESIOC_GETOBJMAP = SESIOC_GETOBJMAP; +unsigned IOCTL_SESIOC_GETENCSTAT = SESIOC_GETENCSTAT; +unsigned IOCTL_SESIOC_SETENCSTAT = SESIOC_SETENCSTAT; +unsigned IOCTL_SESIOC_GETOBJSTAT = SESIOC_GETOBJSTAT; +unsigned IOCTL_SESIOC_SETOBJSTAT = SESIOC_SETOBJSTAT; +unsigned IOCTL_SESIOC_GETTEXT = SESIOC_GETTEXT; +unsigned IOCTL_SESIOC_INIT = SESIOC_INIT; +unsigned IOCTL_SUN_DKIOCGGEOM = SUN_DKIOCGGEOM; +unsigned IOCTL_SUN_DKIOCINFO = SUN_DKIOCINFO; +unsigned IOCTL_SUN_DKIOCGPART = SUN_DKIOCGPART; +unsigned IOCTL_FBIOGTYPE = FBIOGTYPE; +unsigned IOCTL_FBIOPUTCMAP = FBIOPUTCMAP; +unsigned IOCTL_FBIOGETCMAP = FBIOGETCMAP; +unsigned IOCTL_FBIOGATTR = FBIOGATTR; +unsigned IOCTL_FBIOSVIDEO = FBIOSVIDEO; +unsigned IOCTL_FBIOGVIDEO = FBIOGVIDEO; +unsigned IOCTL_FBIOSCURSOR = FBIOSCURSOR; +unsigned IOCTL_FBIOGCURSOR = FBIOGCURSOR; +unsigned IOCTL_FBIOSCURPOS = FBIOSCURPOS; +unsigned IOCTL_FBIOGCURPOS = FBIOGCURPOS; +unsigned IOCTL_FBIOGCURMAX = FBIOGCURMAX; +unsigned IOCTL_KIOCTRANS = KIOCTRANS; +unsigned IOCTL_KIOCSETKEY = KIOCSETKEY; +unsigned IOCTL_KIOCGETKEY = KIOCGETKEY; +unsigned IOCTL_KIOCGTRANS = KIOCGTRANS; +unsigned IOCTL_KIOCCMD = KIOCCMD; +unsigned IOCTL_KIOCTYPE = KIOCTYPE; +unsigned IOCTL_KIOCSDIRECT = KIOCSDIRECT; +unsigned IOCTL_KIOCSKEY = KIOCSKEY; +unsigned IOCTL_KIOCGKEY = KIOCGKEY; +unsigned IOCTL_KIOCSLED = KIOCSLED; +unsigned IOCTL_KIOCGLED = KIOCGLED; +unsigned IOCTL_KIOCLAYOUT = KIOCLAYOUT; +unsigned IOCTL_VUIDSFORMAT = VUIDSFORMAT; +unsigned IOCTL_VUIDGFORMAT = VUIDGFORMAT; +unsigned IOCTL_STICIO_GXINFO = STICIO_GXINFO; +unsigned IOCTL_STICIO_RESET = STICIO_RESET; +unsigned IOCTL_STICIO_STARTQ = STICIO_STARTQ; +unsigned IOCTL_STICIO_STOPQ = STICIO_STOPQ; +unsigned IOCTL_UKYOPON_IDENTIFY = UKYOPON_IDENTIFY; +unsigned IOCTL_URIO_SEND_COMMAND = URIO_SEND_COMMAND; +unsigned IOCTL_URIO_RECV_COMMAND = URIO_RECV_COMMAND; +unsigned IOCTL_USB_REQUEST = USB_REQUEST; +unsigned IOCTL_USB_SETDEBUG = USB_SETDEBUG; +unsigned IOCTL_USB_DISCOVER = USB_DISCOVER; +unsigned IOCTL_USB_DEVICEINFO = USB_DEVICEINFO; +unsigned IOCTL_USB_DEVICEINFO_OLD = USB_DEVICEINFO_OLD; +unsigned IOCTL_USB_DEVICESTATS = USB_DEVICESTATS; +unsigned IOCTL_USB_GET_REPORT_DESC = USB_GET_REPORT_DESC; +unsigned IOCTL_USB_SET_IMMED = USB_SET_IMMED; +unsigned IOCTL_USB_GET_REPORT = USB_GET_REPORT; +unsigned IOCTL_USB_SET_REPORT = USB_SET_REPORT; +unsigned IOCTL_USB_GET_REPORT_ID = USB_GET_REPORT_ID; +unsigned IOCTL_USB_GET_CONFIG = USB_GET_CONFIG; +unsigned IOCTL_USB_SET_CONFIG = USB_SET_CONFIG; +unsigned IOCTL_USB_GET_ALTINTERFACE = USB_GET_ALTINTERFACE; +unsigned IOCTL_USB_SET_ALTINTERFACE = USB_SET_ALTINTERFACE; +unsigned IOCTL_USB_GET_NO_ALT = USB_GET_NO_ALT; +unsigned IOCTL_USB_GET_DEVICE_DESC = USB_GET_DEVICE_DESC; +unsigned IOCTL_USB_GET_CONFIG_DESC = USB_GET_CONFIG_DESC; +unsigned IOCTL_USB_GET_INTERFACE_DESC = USB_GET_INTERFACE_DESC; +unsigned IOCTL_USB_GET_ENDPOINT_DESC = USB_GET_ENDPOINT_DESC; +unsigned IOCTL_USB_GET_FULL_DESC = USB_GET_FULL_DESC; +unsigned IOCTL_USB_GET_STRING_DESC = USB_GET_STRING_DESC; +unsigned IOCTL_USB_DO_REQUEST = USB_DO_REQUEST; +unsigned IOCTL_USB_GET_DEVICEINFO = USB_GET_DEVICEINFO; +unsigned IOCTL_USB_GET_DEVICEINFO_OLD = USB_GET_DEVICEINFO_OLD; +unsigned IOCTL_USB_SET_SHORT_XFER = USB_SET_SHORT_XFER; +unsigned IOCTL_USB_SET_TIMEOUT = USB_SET_TIMEOUT; +unsigned IOCTL_USB_SET_BULK_RA = USB_SET_BULK_RA; +unsigned IOCTL_USB_SET_BULK_WB = USB_SET_BULK_WB; +unsigned IOCTL_USB_SET_BULK_RA_OPT = USB_SET_BULK_RA_OPT; +unsigned IOCTL_USB_SET_BULK_WB_OPT = USB_SET_BULK_WB_OPT; +unsigned IOCTL_USB_GET_CM_OVER_DATA = USB_GET_CM_OVER_DATA; +unsigned IOCTL_USB_SET_CM_OVER_DATA = USB_SET_CM_OVER_DATA; +unsigned IOCTL_UTOPPYIOTURBO = UTOPPYIOTURBO; +unsigned IOCTL_UTOPPYIOCANCEL = UTOPPYIOCANCEL; +unsigned IOCTL_UTOPPYIOREBOOT = UTOPPYIOREBOOT; +unsigned IOCTL_UTOPPYIOSTATS = UTOPPYIOSTATS; +unsigned IOCTL_UTOPPYIORENAME = UTOPPYIORENAME; +unsigned IOCTL_UTOPPYIOMKDIR = UTOPPYIOMKDIR; +unsigned IOCTL_UTOPPYIODELETE = UTOPPYIODELETE; +unsigned IOCTL_UTOPPYIOREADDIR = UTOPPYIOREADDIR; +unsigned IOCTL_UTOPPYIOREADFILE = UTOPPYIOREADFILE; +unsigned IOCTL_UTOPPYIOWRITEFILE = UTOPPYIOWRITEFILE; +unsigned IOCTL_DIOSXDCMD = DIOSXDCMD; +unsigned IOCTL_VT_OPENQRY = VT_OPENQRY; +unsigned IOCTL_VT_SETMODE = VT_SETMODE; +unsigned IOCTL_VT_GETMODE = VT_GETMODE; +unsigned IOCTL_VT_RELDISP = VT_RELDISP; +unsigned IOCTL_VT_ACTIVATE = VT_ACTIVATE; +unsigned IOCTL_VT_WAITACTIVE = VT_WAITACTIVE; +unsigned IOCTL_VT_GETACTIVE = VT_GETACTIVE; +unsigned IOCTL_VT_GETSTATE = VT_GETSTATE; +unsigned IOCTL_KDGETKBENT = KDGETKBENT; +unsigned IOCTL_KDGKBMODE = KDGKBMODE; +unsigned IOCTL_KDSKBMODE = KDSKBMODE; +unsigned IOCTL_KDMKTONE = KDMKTONE; +unsigned IOCTL_KDSETMODE = KDSETMODE; +unsigned IOCTL_KDENABIO = KDENABIO; +unsigned IOCTL_KDDISABIO = KDDISABIO; +unsigned IOCTL_KDGKBTYPE = KDGKBTYPE; +unsigned IOCTL_KDGETLED = KDGETLED; +unsigned IOCTL_KDSETLED = KDSETLED; +unsigned IOCTL_KDSETRAD = KDSETRAD; +unsigned IOCTL_VGAPCVTID = VGAPCVTID; +unsigned IOCTL_CONS_GETVERS = CONS_GETVERS; +unsigned IOCTL_WSKBDIO_GTYPE = WSKBDIO_GTYPE; +unsigned IOCTL_WSKBDIO_BELL = WSKBDIO_BELL; +unsigned IOCTL_WSKBDIO_COMPLEXBELL = WSKBDIO_COMPLEXBELL; +unsigned IOCTL_WSKBDIO_SETBELL = WSKBDIO_SETBELL; +unsigned IOCTL_WSKBDIO_GETBELL = WSKBDIO_GETBELL; +unsigned IOCTL_WSKBDIO_SETDEFAULTBELL = WSKBDIO_SETDEFAULTBELL; +unsigned IOCTL_WSKBDIO_GETDEFAULTBELL = WSKBDIO_GETDEFAULTBELL; +unsigned IOCTL_WSKBDIO_SETKEYREPEAT = WSKBDIO_SETKEYREPEAT; +unsigned IOCTL_WSKBDIO_GETKEYREPEAT = WSKBDIO_GETKEYREPEAT; +unsigned IOCTL_WSKBDIO_SETDEFAULTKEYREPEAT = WSKBDIO_SETDEFAULTKEYREPEAT; +unsigned IOCTL_WSKBDIO_GETDEFAULTKEYREPEAT = WSKBDIO_GETDEFAULTKEYREPEAT; +unsigned IOCTL_WSKBDIO_SETLEDS = WSKBDIO_SETLEDS; +unsigned IOCTL_WSKBDIO_GETLEDS = WSKBDIO_GETLEDS; +unsigned IOCTL_WSKBDIO_GETMAP = WSKBDIO_GETMAP; +unsigned IOCTL_WSKBDIO_SETMAP = WSKBDIO_SETMAP; +unsigned IOCTL_WSKBDIO_GETENCODING = WSKBDIO_GETENCODING; +unsigned IOCTL_WSKBDIO_SETENCODING = WSKBDIO_SETENCODING; +unsigned IOCTL_WSKBDIO_SETMODE = WSKBDIO_SETMODE; +unsigned IOCTL_WSKBDIO_GETMODE = WSKBDIO_GETMODE; +unsigned IOCTL_WSKBDIO_SETKEYCLICK = WSKBDIO_SETKEYCLICK; +unsigned IOCTL_WSKBDIO_GETKEYCLICK = WSKBDIO_GETKEYCLICK; +unsigned IOCTL_WSKBDIO_GETSCROLL = WSKBDIO_GETSCROLL; +unsigned IOCTL_WSKBDIO_SETSCROLL = WSKBDIO_SETSCROLL; +unsigned IOCTL_WSKBDIO_SETVERSION = WSKBDIO_SETVERSION; +unsigned IOCTL_WSMOUSEIO_GTYPE = WSMOUSEIO_GTYPE; +unsigned IOCTL_WSMOUSEIO_SRES = WSMOUSEIO_SRES; +unsigned IOCTL_WSMOUSEIO_SSCALE = WSMOUSEIO_SSCALE; +unsigned IOCTL_WSMOUSEIO_SRATE = WSMOUSEIO_SRATE; +unsigned IOCTL_WSMOUSEIO_SCALIBCOORDS = WSMOUSEIO_SCALIBCOORDS; +unsigned IOCTL_WSMOUSEIO_GCALIBCOORDS = WSMOUSEIO_GCALIBCOORDS; +unsigned IOCTL_WSMOUSEIO_GETID = WSMOUSEIO_GETID; +unsigned IOCTL_WSMOUSEIO_GETREPEAT = WSMOUSEIO_GETREPEAT; +unsigned IOCTL_WSMOUSEIO_SETREPEAT = WSMOUSEIO_SETREPEAT; +unsigned IOCTL_WSMOUSEIO_SETVERSION = WSMOUSEIO_SETVERSION; +unsigned IOCTL_WSDISPLAYIO_GTYPE = WSDISPLAYIO_GTYPE; +unsigned IOCTL_WSDISPLAYIO_GINFO = WSDISPLAYIO_GINFO; +unsigned IOCTL_WSDISPLAYIO_GETCMAP = WSDISPLAYIO_GETCMAP; +unsigned IOCTL_WSDISPLAYIO_PUTCMAP = WSDISPLAYIO_PUTCMAP; +unsigned IOCTL_WSDISPLAYIO_GVIDEO = WSDISPLAYIO_GVIDEO; +unsigned IOCTL_WSDISPLAYIO_SVIDEO = WSDISPLAYIO_SVIDEO; +unsigned IOCTL_WSDISPLAYIO_GCURPOS = WSDISPLAYIO_GCURPOS; +unsigned IOCTL_WSDISPLAYIO_SCURPOS = WSDISPLAYIO_SCURPOS; +unsigned IOCTL_WSDISPLAYIO_GCURMAX = WSDISPLAYIO_GCURMAX; +unsigned IOCTL_WSDISPLAYIO_GCURSOR = WSDISPLAYIO_GCURSOR; +unsigned IOCTL_WSDISPLAYIO_SCURSOR = WSDISPLAYIO_SCURSOR; +unsigned IOCTL_WSDISPLAYIO_GMODE = WSDISPLAYIO_GMODE; +unsigned IOCTL_WSDISPLAYIO_SMODE = WSDISPLAYIO_SMODE; +unsigned IOCTL_WSDISPLAYIO_LDFONT = WSDISPLAYIO_LDFONT; +unsigned IOCTL_WSDISPLAYIO_ADDSCREEN = WSDISPLAYIO_ADDSCREEN; +unsigned IOCTL_WSDISPLAYIO_DELSCREEN = WSDISPLAYIO_DELSCREEN; +unsigned IOCTL_WSDISPLAYIO_SFONT = WSDISPLAYIO_SFONT; +unsigned IOCTL__O_WSDISPLAYIO_SETKEYBOARD = _O_WSDISPLAYIO_SETKEYBOARD; +unsigned IOCTL_WSDISPLAYIO_GETPARAM = WSDISPLAYIO_GETPARAM; +unsigned IOCTL_WSDISPLAYIO_SETPARAM = WSDISPLAYIO_SETPARAM; +unsigned IOCTL_WSDISPLAYIO_GETACTIVESCREEN = WSDISPLAYIO_GETACTIVESCREEN; +unsigned IOCTL_WSDISPLAYIO_GETWSCHAR = WSDISPLAYIO_GETWSCHAR; +unsigned IOCTL_WSDISPLAYIO_PUTWSCHAR = WSDISPLAYIO_PUTWSCHAR; +unsigned IOCTL_WSDISPLAYIO_DGSCROLL = WSDISPLAYIO_DGSCROLL; +unsigned IOCTL_WSDISPLAYIO_DSSCROLL = WSDISPLAYIO_DSSCROLL; +unsigned IOCTL_WSDISPLAYIO_GMSGATTRS = WSDISPLAYIO_GMSGATTRS; +unsigned IOCTL_WSDISPLAYIO_SMSGATTRS = WSDISPLAYIO_SMSGATTRS; +unsigned IOCTL_WSDISPLAYIO_GBORDER = WSDISPLAYIO_GBORDER; +unsigned IOCTL_WSDISPLAYIO_SBORDER = WSDISPLAYIO_SBORDER; +unsigned IOCTL_WSDISPLAYIO_SSPLASH = WSDISPLAYIO_SSPLASH; +unsigned IOCTL_WSDISPLAYIO_SPROGRESS = WSDISPLAYIO_SPROGRESS; +unsigned IOCTL_WSDISPLAYIO_LINEBYTES = WSDISPLAYIO_LINEBYTES; +unsigned IOCTL_WSDISPLAYIO_SETVERSION = WSDISPLAYIO_SETVERSION; +unsigned IOCTL_WSMUXIO_ADD_DEVICE = WSMUXIO_ADD_DEVICE; +unsigned IOCTL_WSMUXIO_REMOVE_DEVICE = WSMUXIO_REMOVE_DEVICE; +unsigned IOCTL_WSMUXIO_LIST_DEVICES = WSMUXIO_LIST_DEVICES; +unsigned IOCTL_WSMUXIO_INJECTEVENT = WSMUXIO_INJECTEVENT; +unsigned IOCTL_WSDISPLAYIO_GET_BUSID = WSDISPLAYIO_GET_BUSID; +unsigned IOCTL_WSDISPLAYIO_GET_EDID = WSDISPLAYIO_GET_EDID; +unsigned IOCTL_WSDISPLAYIO_SET_POLLING = WSDISPLAYIO_SET_POLLING; +unsigned IOCTL_WSDISPLAYIO_GET_FBINFO = WSDISPLAYIO_GET_FBINFO; +unsigned IOCTL_WSDISPLAYIO_DOBLIT = WSDISPLAYIO_DOBLIT; +unsigned IOCTL_WSDISPLAYIO_WAITBLIT = WSDISPLAYIO_WAITBLIT; +unsigned IOCTL_BIOCLOCATE = BIOCLOCATE; +unsigned IOCTL_BIOCINQ = BIOCINQ; +unsigned IOCTL_BIOCDISK_NOVOL = BIOCDISK_NOVOL; +unsigned IOCTL_BIOCDISK = BIOCDISK; +unsigned IOCTL_BIOCVOL = BIOCVOL; +unsigned IOCTL_BIOCALARM = BIOCALARM; +unsigned IOCTL_BIOCBLINK = BIOCBLINK; +unsigned IOCTL_BIOCSETSTATE = BIOCSETSTATE; +unsigned IOCTL_BIOCVOLOPS = BIOCVOLOPS; +unsigned IOCTL_MD_GETCONF = MD_GETCONF; +unsigned IOCTL_MD_SETCONF = MD_SETCONF; +unsigned IOCTL_CCDIOCSET = CCDIOCSET; +unsigned IOCTL_CCDIOCCLR = CCDIOCCLR; +unsigned IOCTL_CGDIOCSET = CGDIOCSET; +unsigned IOCTL_CGDIOCCLR = CGDIOCCLR; +unsigned IOCTL_CGDIOCGET = CGDIOCGET; +unsigned IOCTL_FSSIOCSET = FSSIOCSET; +unsigned IOCTL_FSSIOCGET = FSSIOCGET; +unsigned IOCTL_FSSIOCCLR = FSSIOCCLR; +unsigned IOCTL_FSSIOFSET = FSSIOFSET; +unsigned IOCTL_FSSIOFGET = FSSIOFGET; +unsigned IOCTL_BTDEV_ATTACH = BTDEV_ATTACH; +unsigned IOCTL_BTDEV_DETACH = BTDEV_DETACH; +unsigned IOCTL_BTSCO_GETINFO = BTSCO_GETINFO; +unsigned IOCTL_KTTCP_IO_SEND = KTTCP_IO_SEND; +unsigned IOCTL_KTTCP_IO_RECV = KTTCP_IO_RECV; +unsigned IOCTL_IOC_LOCKSTAT_GVERSION = IOC_LOCKSTAT_GVERSION; +unsigned IOCTL_IOC_LOCKSTAT_ENABLE = IOC_LOCKSTAT_ENABLE; +unsigned IOCTL_IOC_LOCKSTAT_DISABLE = IOC_LOCKSTAT_DISABLE; +unsigned IOCTL_VNDIOCSET = VNDIOCSET; +unsigned IOCTL_VNDIOCCLR = VNDIOCCLR; +unsigned IOCTL_VNDIOCGET = VNDIOCGET; +unsigned IOCTL_SPKRTONE = SPKRTONE; +unsigned IOCTL_SPKRTUNE = SPKRTUNE; +unsigned IOCTL_SPKRGETVOL = SPKRGETVOL; +unsigned IOCTL_SPKRSETVOL = SPKRSETVOL; +unsigned IOCTL_BIOCGBLEN = BIOCGBLEN; +unsigned IOCTL_BIOCSBLEN = BIOCSBLEN; +unsigned IOCTL_BIOCSETF = BIOCSETF; +unsigned IOCTL_BIOCFLUSH = BIOCFLUSH; +unsigned IOCTL_BIOCPROMISC = BIOCPROMISC; +unsigned IOCTL_BIOCGDLT = BIOCGDLT; +unsigned IOCTL_BIOCGETIF = BIOCGETIF; +unsigned IOCTL_BIOCSETIF = BIOCSETIF; +unsigned IOCTL_BIOCGSTATS = BIOCGSTATS; +unsigned IOCTL_BIOCGSTATSOLD = BIOCGSTATSOLD; +unsigned IOCTL_BIOCIMMEDIATE = BIOCIMMEDIATE; +unsigned IOCTL_BIOCVERSION = BIOCVERSION; +unsigned IOCTL_BIOCSTCPF = BIOCSTCPF; +unsigned IOCTL_BIOCSUDPF = BIOCSUDPF; +unsigned IOCTL_BIOCGHDRCMPLT = BIOCGHDRCMPLT; +unsigned IOCTL_BIOCSHDRCMPLT = BIOCSHDRCMPLT; +unsigned IOCTL_BIOCSDLT = BIOCSDLT; +unsigned IOCTL_BIOCGDLTLIST = BIOCGDLTLIST; +unsigned IOCTL_BIOCGSEESENT = BIOCGSEESENT; +unsigned IOCTL_BIOCSSEESENT = BIOCSSEESENT; +unsigned IOCTL_BIOCSRTIMEOUT = BIOCSRTIMEOUT; +unsigned IOCTL_BIOCGRTIMEOUT = BIOCGRTIMEOUT; +unsigned IOCTL_BIOCGFEEDBACK = BIOCGFEEDBACK; +unsigned IOCTL_BIOCSFEEDBACK = BIOCSFEEDBACK; +unsigned IOCTL_SIOCRAWATM = SIOCRAWATM; +unsigned IOCTL_SIOCATMENA = SIOCATMENA; +unsigned IOCTL_SIOCATMDIS = SIOCATMDIS; +unsigned IOCTL_SIOCSPVCTX = SIOCSPVCTX; +unsigned IOCTL_SIOCGPVCTX = SIOCGPVCTX; +unsigned IOCTL_SIOCSPVCSIF = SIOCSPVCSIF; +unsigned IOCTL_SIOCGPVCSIF = SIOCGPVCSIF; +unsigned IOCTL_GRESADDRS = GRESADDRS; +unsigned IOCTL_GRESADDRD = GRESADDRD; +unsigned IOCTL_GREGADDRS = GREGADDRS; +unsigned IOCTL_GREGADDRD = GREGADDRD; +unsigned IOCTL_GRESPROTO = GRESPROTO; +unsigned IOCTL_GREGPROTO = GREGPROTO; +unsigned IOCTL_GRESSOCK = GRESSOCK; +unsigned IOCTL_GREDSOCK = GREDSOCK; +unsigned IOCTL_PPPIOCGRAWIN = PPPIOCGRAWIN; +unsigned IOCTL_PPPIOCGFLAGS = PPPIOCGFLAGS; +unsigned IOCTL_PPPIOCSFLAGS = PPPIOCSFLAGS; +unsigned IOCTL_PPPIOCGASYNCMAP = PPPIOCGASYNCMAP; +unsigned IOCTL_PPPIOCSASYNCMAP = PPPIOCSASYNCMAP; +unsigned IOCTL_PPPIOCGUNIT = PPPIOCGUNIT; +unsigned IOCTL_PPPIOCGRASYNCMAP = PPPIOCGRASYNCMAP; +unsigned IOCTL_PPPIOCSRASYNCMAP = PPPIOCSRASYNCMAP; +unsigned IOCTL_PPPIOCGMRU = PPPIOCGMRU; +unsigned IOCTL_PPPIOCSMRU = PPPIOCSMRU; +unsigned IOCTL_PPPIOCSMAXCID = PPPIOCSMAXCID; +unsigned IOCTL_PPPIOCGXASYNCMAP = PPPIOCGXASYNCMAP; +unsigned IOCTL_PPPIOCSXASYNCMAP = PPPIOCSXASYNCMAP; +unsigned IOCTL_PPPIOCXFERUNIT = PPPIOCXFERUNIT; +unsigned IOCTL_PPPIOCSCOMPRESS = PPPIOCSCOMPRESS; +unsigned IOCTL_PPPIOCGNPMODE = PPPIOCGNPMODE; +unsigned IOCTL_PPPIOCSNPMODE = PPPIOCSNPMODE; +unsigned IOCTL_PPPIOCGIDLE = PPPIOCGIDLE; +unsigned IOCTL_PPPIOCGMTU = PPPIOCGMTU; +unsigned IOCTL_PPPIOCSMTU = PPPIOCSMTU; +unsigned IOCTL_SIOCGPPPSTATS = SIOCGPPPSTATS; +unsigned IOCTL_SIOCGPPPCSTATS = SIOCGPPPCSTATS; +unsigned IOCTL_IOC_NPF_VERSION = IOC_NPF_VERSION; +unsigned IOCTL_IOC_NPF_SWITCH = IOC_NPF_SWITCH; +unsigned IOCTL_IOC_NPF_LOAD = IOC_NPF_LOAD; +unsigned IOCTL_IOC_NPF_TABLE = IOC_NPF_TABLE; +unsigned IOCTL_IOC_NPF_STATS = IOC_NPF_STATS; +unsigned IOCTL_IOC_NPF_SAVE = IOC_NPF_SAVE; +unsigned IOCTL_IOC_NPF_RULE = IOC_NPF_RULE; +unsigned IOCTL_IOC_NPF_CONN_LOOKUP = IOC_NPF_CONN_LOOKUP; +unsigned IOCTL_PPPOESETPARMS = PPPOESETPARMS; +unsigned IOCTL_PPPOEGETPARMS = PPPOEGETPARMS; +unsigned IOCTL_PPPOEGETSESSION = PPPOEGETSESSION; +unsigned IOCTL_SPPPGETAUTHCFG = SPPPGETAUTHCFG; +unsigned IOCTL_SPPPSETAUTHCFG = SPPPSETAUTHCFG; +unsigned IOCTL_SPPPGETLCPCFG = SPPPGETLCPCFG; +unsigned IOCTL_SPPPSETLCPCFG = SPPPSETLCPCFG; +unsigned IOCTL_SPPPGETSTATUS = SPPPGETSTATUS; +unsigned IOCTL_SPPPGETSTATUSNCP = SPPPGETSTATUSNCP; +unsigned IOCTL_SPPPGETIDLETO = SPPPGETIDLETO; +unsigned IOCTL_SPPPSETIDLETO = SPPPSETIDLETO; +unsigned IOCTL_SPPPGETAUTHFAILURES = SPPPGETAUTHFAILURES; +unsigned IOCTL_SPPPSETAUTHFAILURE = SPPPSETAUTHFAILURE; +unsigned IOCTL_SPPPSETDNSOPTS = SPPPSETDNSOPTS; +unsigned IOCTL_SPPPGETDNSOPTS = SPPPGETDNSOPTS; +unsigned IOCTL_SPPPGETDNSADDRS = SPPPGETDNSADDRS; +unsigned IOCTL_SPPPSETKEEPALIVE = SPPPSETKEEPALIVE; +unsigned IOCTL_SPPPGETKEEPALIVE = SPPPGETKEEPALIVE; +unsigned IOCTL_SRT_GETNRT = SRT_GETNRT; +unsigned IOCTL_SRT_GETRT = SRT_GETRT; +unsigned IOCTL_SRT_SETRT = SRT_SETRT; +unsigned IOCTL_SRT_DELRT = SRT_DELRT; +unsigned IOCTL_SRT_SFLAGS = SRT_SFLAGS; +unsigned IOCTL_SRT_GFLAGS = SRT_GFLAGS; +unsigned IOCTL_SRT_SGFLAGS = SRT_SGFLAGS; +unsigned IOCTL_SRT_DEBUG = SRT_DEBUG; +unsigned IOCTL_TAPGIFNAME = TAPGIFNAME; +unsigned IOCTL_TUNSDEBUG = TUNSDEBUG; +unsigned IOCTL_TUNGDEBUG = TUNGDEBUG; +unsigned IOCTL_TUNSIFMODE = TUNSIFMODE; +unsigned IOCTL_TUNSLMODE = TUNSLMODE; +unsigned IOCTL_TUNSIFHEAD = TUNSIFHEAD; +unsigned IOCTL_TUNGIFHEAD = TUNGIFHEAD; +unsigned IOCTL_DIOCSTART = DIOCSTART; +unsigned IOCTL_DIOCSTOP = DIOCSTOP; +unsigned IOCTL_DIOCADDRULE = DIOCADDRULE; +unsigned IOCTL_DIOCGETRULES = DIOCGETRULES; +unsigned IOCTL_DIOCGETRULE = DIOCGETRULE; +unsigned IOCTL_DIOCSETLCK = DIOCSETLCK; +unsigned IOCTL_DIOCCLRSTATES = DIOCCLRSTATES; +unsigned IOCTL_DIOCGETSTATE = DIOCGETSTATE; +unsigned IOCTL_DIOCSETSTATUSIF = DIOCSETSTATUSIF; +unsigned IOCTL_DIOCGETSTATUS = DIOCGETSTATUS; +unsigned IOCTL_DIOCCLRSTATUS = DIOCCLRSTATUS; +unsigned IOCTL_DIOCNATLOOK = DIOCNATLOOK; +unsigned IOCTL_DIOCSETDEBUG = DIOCSETDEBUG; +unsigned IOCTL_DIOCGETSTATES = DIOCGETSTATES; +unsigned IOCTL_DIOCCHANGERULE = DIOCCHANGERULE; +unsigned IOCTL_DIOCSETTIMEOUT = DIOCSETTIMEOUT; +unsigned IOCTL_DIOCGETTIMEOUT = DIOCGETTIMEOUT; +unsigned IOCTL_DIOCADDSTATE = DIOCADDSTATE; +unsigned IOCTL_DIOCCLRRULECTRS = DIOCCLRRULECTRS; +unsigned IOCTL_DIOCGETLIMIT = DIOCGETLIMIT; +unsigned IOCTL_DIOCSETLIMIT = DIOCSETLIMIT; +unsigned IOCTL_DIOCKILLSTATES = DIOCKILLSTATES; +unsigned IOCTL_DIOCSTARTALTQ = DIOCSTARTALTQ; +unsigned IOCTL_DIOCSTOPALTQ = DIOCSTOPALTQ; +unsigned IOCTL_DIOCADDALTQ = DIOCADDALTQ; +unsigned IOCTL_DIOCGETALTQS = DIOCGETALTQS; +unsigned IOCTL_DIOCGETALTQ = DIOCGETALTQ; +unsigned IOCTL_DIOCCHANGEALTQ = DIOCCHANGEALTQ; +unsigned IOCTL_DIOCGETQSTATS = DIOCGETQSTATS; +unsigned IOCTL_DIOCBEGINADDRS = DIOCBEGINADDRS; +unsigned IOCTL_DIOCADDADDR = DIOCADDADDR; +unsigned IOCTL_DIOCGETADDRS = DIOCGETADDRS; +unsigned IOCTL_DIOCGETADDR = DIOCGETADDR; +unsigned IOCTL_DIOCCHANGEADDR = DIOCCHANGEADDR; +unsigned IOCTL_DIOCADDSTATES = DIOCADDSTATES; +unsigned IOCTL_DIOCGETRULESETS = DIOCGETRULESETS; +unsigned IOCTL_DIOCGETRULESET = DIOCGETRULESET; +unsigned IOCTL_DIOCRCLRTABLES = DIOCRCLRTABLES; +unsigned IOCTL_DIOCRADDTABLES = DIOCRADDTABLES; +unsigned IOCTL_DIOCRDELTABLES = DIOCRDELTABLES; +unsigned IOCTL_DIOCRGETTABLES = DIOCRGETTABLES; +unsigned IOCTL_DIOCRGETTSTATS = DIOCRGETTSTATS; +unsigned IOCTL_DIOCRCLRTSTATS = DIOCRCLRTSTATS; +unsigned IOCTL_DIOCRCLRADDRS = DIOCRCLRADDRS; +unsigned IOCTL_DIOCRADDADDRS = DIOCRADDADDRS; +unsigned IOCTL_DIOCRDELADDRS = DIOCRDELADDRS; +unsigned IOCTL_DIOCRSETADDRS = DIOCRSETADDRS; +unsigned IOCTL_DIOCRGETADDRS = DIOCRGETADDRS; +unsigned IOCTL_DIOCRGETASTATS = DIOCRGETASTATS; +unsigned IOCTL_DIOCRCLRASTATS = DIOCRCLRASTATS; +unsigned IOCTL_DIOCRTSTADDRS = DIOCRTSTADDRS; +unsigned IOCTL_DIOCRSETTFLAGS = DIOCRSETTFLAGS; +unsigned IOCTL_DIOCRINADEFINE = DIOCRINADEFINE; +unsigned IOCTL_DIOCOSFPFLUSH = DIOCOSFPFLUSH; +unsigned IOCTL_DIOCOSFPADD = DIOCOSFPADD; +unsigned IOCTL_DIOCOSFPGET = DIOCOSFPGET; +unsigned IOCTL_DIOCXBEGIN = DIOCXBEGIN; +unsigned IOCTL_DIOCXCOMMIT = DIOCXCOMMIT; +unsigned IOCTL_DIOCXROLLBACK = DIOCXROLLBACK; +unsigned IOCTL_DIOCGETSRCNODES = DIOCGETSRCNODES; +unsigned IOCTL_DIOCCLRSRCNODES = DIOCCLRSRCNODES; +unsigned IOCTL_DIOCSETHOSTID = DIOCSETHOSTID; +unsigned IOCTL_DIOCIGETIFACES = DIOCIGETIFACES; +unsigned IOCTL_DIOCSETIFFLAG = DIOCSETIFFLAG; +unsigned IOCTL_DIOCCLRIFFLAG = DIOCCLRIFFLAG; +unsigned IOCTL_DIOCKILLSRCNODES = DIOCKILLSRCNODES; +unsigned IOCTL_SLIOCGUNIT = SLIOCGUNIT; +unsigned IOCTL_SIOCGBTINFO = SIOCGBTINFO; +unsigned IOCTL_SIOCGBTINFOA = SIOCGBTINFOA; +unsigned IOCTL_SIOCNBTINFO = SIOCNBTINFO; +unsigned IOCTL_SIOCSBTFLAGS = SIOCSBTFLAGS; +unsigned IOCTL_SIOCSBTPOLICY = SIOCSBTPOLICY; +unsigned IOCTL_SIOCSBTPTYPE = SIOCSBTPTYPE; +unsigned IOCTL_SIOCGBTSTATS = SIOCGBTSTATS; +unsigned IOCTL_SIOCZBTSTATS = SIOCZBTSTATS; +unsigned IOCTL_SIOCBTDUMP = SIOCBTDUMP; +unsigned IOCTL_SIOCSBTSCOMTU = SIOCSBTSCOMTU; +unsigned IOCTL_SIOCGBTFEAT = SIOCGBTFEAT; +unsigned IOCTL_SIOCADNAT = SIOCADNAT; +unsigned IOCTL_SIOCRMNAT = SIOCRMNAT; +unsigned IOCTL_SIOCGNATS = SIOCGNATS; +unsigned IOCTL_SIOCGNATL = SIOCGNATL; +unsigned IOCTL_SIOCPURGENAT = SIOCPURGENAT; +unsigned IOCTL_SIOCSIFINFO_FLAGS = SIOCSIFINFO_FLAGS; +unsigned IOCTL_SIOCAADDRCTL_POLICY = SIOCAADDRCTL_POLICY; +unsigned IOCTL_SIOCDADDRCTL_POLICY = SIOCDADDRCTL_POLICY; +unsigned IOCTL_SMBIOC_OPENSESSION = SMBIOC_OPENSESSION; +unsigned IOCTL_SMBIOC_OPENSHARE = SMBIOC_OPENSHARE; +unsigned IOCTL_SMBIOC_REQUEST = SMBIOC_REQUEST; +unsigned IOCTL_SMBIOC_SETFLAGS = SMBIOC_SETFLAGS; +unsigned IOCTL_SMBIOC_LOOKUP = SMBIOC_LOOKUP; +unsigned IOCTL_SMBIOC_READ = SMBIOC_READ; +unsigned IOCTL_SMBIOC_WRITE = SMBIOC_WRITE; +unsigned IOCTL_AGPIOC_INFO = AGPIOC_INFO; +unsigned IOCTL_AGPIOC_ACQUIRE = AGPIOC_ACQUIRE; +unsigned IOCTL_AGPIOC_RELEASE = AGPIOC_RELEASE; +unsigned IOCTL_AGPIOC_SETUP = AGPIOC_SETUP; +unsigned IOCTL_AGPIOC_ALLOCATE = AGPIOC_ALLOCATE; +unsigned IOCTL_AGPIOC_DEALLOCATE = AGPIOC_DEALLOCATE; +unsigned IOCTL_AGPIOC_BIND = AGPIOC_BIND; +unsigned IOCTL_AGPIOC_UNBIND = AGPIOC_UNBIND; +unsigned IOCTL_AUDIO_GETINFO = AUDIO_GETINFO; +unsigned IOCTL_AUDIO_SETINFO = AUDIO_SETINFO; +unsigned IOCTL_AUDIO_DRAIN = AUDIO_DRAIN; +unsigned IOCTL_AUDIO_FLUSH = AUDIO_FLUSH; +unsigned IOCTL_AUDIO_WSEEK = AUDIO_WSEEK; +unsigned IOCTL_AUDIO_RERROR = AUDIO_RERROR; +unsigned IOCTL_AUDIO_GETDEV = AUDIO_GETDEV; +unsigned IOCTL_AUDIO_GETENC = AUDIO_GETENC; +unsigned IOCTL_AUDIO_GETFD = AUDIO_GETFD; +unsigned IOCTL_AUDIO_SETFD = AUDIO_SETFD; +unsigned IOCTL_AUDIO_PERROR = AUDIO_PERROR; +unsigned IOCTL_AUDIO_GETIOFFS = AUDIO_GETIOFFS; +unsigned IOCTL_AUDIO_GETOOFFS = AUDIO_GETOOFFS; +unsigned IOCTL_AUDIO_GETPROPS = AUDIO_GETPROPS; +unsigned IOCTL_AUDIO_GETBUFINFO = AUDIO_GETBUFINFO; +unsigned IOCTL_AUDIO_SETCHAN = AUDIO_SETCHAN; +unsigned IOCTL_AUDIO_GETCHAN = AUDIO_GETCHAN; +unsigned IOCTL_AUDIO_MIXER_READ = AUDIO_MIXER_READ; +unsigned IOCTL_AUDIO_MIXER_WRITE = AUDIO_MIXER_WRITE; +unsigned IOCTL_AUDIO_MIXER_DEVINFO = AUDIO_MIXER_DEVINFO; +unsigned IOCTL_ATAIOCCOMMAND = ATAIOCCOMMAND; +unsigned IOCTL_ATABUSIOSCAN = ATABUSIOSCAN; +unsigned IOCTL_ATABUSIORESET = ATABUSIORESET; +unsigned IOCTL_ATABUSIODETACH = ATABUSIODETACH; +unsigned IOCTL_CDIOCPLAYTRACKS = CDIOCPLAYTRACKS; +unsigned IOCTL_CDIOCPLAYBLOCKS = CDIOCPLAYBLOCKS; +unsigned IOCTL_CDIOCREADSUBCHANNEL = CDIOCREADSUBCHANNEL; +unsigned IOCTL_CDIOREADTOCHEADER = CDIOREADTOCHEADER; +unsigned IOCTL_CDIOREADTOCENTRIES = CDIOREADTOCENTRIES; +unsigned IOCTL_CDIOREADMSADDR = CDIOREADMSADDR; +unsigned IOCTL_CDIOCSETPATCH = CDIOCSETPATCH; +unsigned IOCTL_CDIOCGETVOL = CDIOCGETVOL; +unsigned IOCTL_CDIOCSETVOL = CDIOCSETVOL; +unsigned IOCTL_CDIOCSETMONO = CDIOCSETMONO; +unsigned IOCTL_CDIOCSETSTEREO = CDIOCSETSTEREO; +unsigned IOCTL_CDIOCSETMUTE = CDIOCSETMUTE; +unsigned IOCTL_CDIOCSETLEFT = CDIOCSETLEFT; +unsigned IOCTL_CDIOCSETRIGHT = CDIOCSETRIGHT; +unsigned IOCTL_CDIOCSETDEBUG = CDIOCSETDEBUG; +unsigned IOCTL_CDIOCCLRDEBUG = CDIOCCLRDEBUG; +unsigned IOCTL_CDIOCPAUSE = CDIOCPAUSE; +unsigned IOCTL_CDIOCRESUME = CDIOCRESUME; +unsigned IOCTL_CDIOCRESET = CDIOCRESET; +unsigned IOCTL_CDIOCSTART = CDIOCSTART; +unsigned IOCTL_CDIOCSTOP = CDIOCSTOP; +unsigned IOCTL_CDIOCEJECT = CDIOCEJECT; +unsigned IOCTL_CDIOCALLOW = CDIOCALLOW; +unsigned IOCTL_CDIOCPREVENT = CDIOCPREVENT; +unsigned IOCTL_CDIOCCLOSE = CDIOCCLOSE; +unsigned IOCTL_CDIOCPLAYMSF = CDIOCPLAYMSF; +unsigned IOCTL_CDIOCLOADUNLOAD = CDIOCLOADUNLOAD; +unsigned IOCTL_CHIOMOVE = CHIOMOVE; +unsigned IOCTL_CHIOEXCHANGE = CHIOEXCHANGE; +unsigned IOCTL_CHIOPOSITION = CHIOPOSITION; +unsigned IOCTL_CHIOGPICKER = CHIOGPICKER; +unsigned IOCTL_CHIOSPICKER = CHIOSPICKER; +unsigned IOCTL_CHIOGPARAMS = CHIOGPARAMS; +unsigned IOCTL_CHIOIELEM = CHIOIELEM; +unsigned IOCTL_OCHIOGSTATUS = OCHIOGSTATUS; +unsigned IOCTL_CHIOGSTATUS = CHIOGSTATUS; +unsigned IOCTL_CHIOSVOLTAG = CHIOSVOLTAG; +unsigned IOCTL_CLOCKCTL_SETTIMEOFDAY = CLOCKCTL_SETTIMEOFDAY; +unsigned IOCTL_CLOCKCTL_ADJTIME = CLOCKCTL_ADJTIME; +unsigned IOCTL_CLOCKCTL_CLOCK_SETTIME = CLOCKCTL_CLOCK_SETTIME; +unsigned IOCTL_CLOCKCTL_NTP_ADJTIME = CLOCKCTL_NTP_ADJTIME; +unsigned IOCTL_IOC_CPU_SETSTATE = IOC_CPU_SETSTATE; +unsigned IOCTL_IOC_CPU_GETSTATE = IOC_CPU_GETSTATE; +unsigned IOCTL_IOC_CPU_GETCOUNT = IOC_CPU_GETCOUNT; +unsigned IOCTL_IOC_CPU_MAPID = IOC_CPU_MAPID; +unsigned IOCTL_IOC_CPU_UCODE_GET_VERSION = IOC_CPU_UCODE_GET_VERSION; +unsigned IOCTL_IOC_CPU_UCODE_APPLY = IOC_CPU_UCODE_APPLY; +unsigned IOCTL_DIOCGDINFO = DIOCGDINFO; +unsigned IOCTL_DIOCSDINFO = DIOCSDINFO; +unsigned IOCTL_DIOCWDINFO = DIOCWDINFO; +unsigned IOCTL_DIOCRFORMAT = DIOCRFORMAT; +unsigned IOCTL_DIOCWFORMAT = DIOCWFORMAT; +unsigned IOCTL_DIOCSSTEP = DIOCSSTEP; +unsigned IOCTL_DIOCSRETRIES = DIOCSRETRIES; +unsigned IOCTL_DIOCKLABEL = DIOCKLABEL; +unsigned IOCTL_DIOCWLABEL = DIOCWLABEL; +unsigned IOCTL_DIOCSBAD = DIOCSBAD; +unsigned IOCTL_DIOCEJECT = DIOCEJECT; +unsigned IOCTL_ODIOCEJECT = ODIOCEJECT; +unsigned IOCTL_DIOCLOCK = DIOCLOCK; +unsigned IOCTL_DIOCGDEFLABEL = DIOCGDEFLABEL; +unsigned IOCTL_DIOCCLRLABEL = DIOCCLRLABEL; +unsigned IOCTL_DIOCGCACHE = DIOCGCACHE; +unsigned IOCTL_DIOCSCACHE = DIOCSCACHE; +unsigned IOCTL_DIOCCACHESYNC = DIOCCACHESYNC; +unsigned IOCTL_DIOCBSLIST = DIOCBSLIST; +unsigned IOCTL_DIOCBSFLUSH = DIOCBSFLUSH; +unsigned IOCTL_DIOCAWEDGE = DIOCAWEDGE; +unsigned IOCTL_DIOCGWEDGEINFO = DIOCGWEDGEINFO; +unsigned IOCTL_DIOCDWEDGE = DIOCDWEDGE; +unsigned IOCTL_DIOCLWEDGES = DIOCLWEDGES; +unsigned IOCTL_DIOCGSTRATEGY = DIOCGSTRATEGY; +unsigned IOCTL_DIOCSSTRATEGY = DIOCSSTRATEGY; +unsigned IOCTL_DIOCGDISKINFO = DIOCGDISKINFO; +unsigned IOCTL_DIOCTUR = DIOCTUR; +unsigned IOCTL_DIOCMWEDGES = DIOCMWEDGES; +unsigned IOCTL_DIOCGSECTORSIZE = DIOCGSECTORSIZE; +unsigned IOCTL_DIOCGMEDIASIZE = DIOCGMEDIASIZE; +unsigned IOCTL_DRVDETACHDEV = DRVDETACHDEV; +unsigned IOCTL_DRVRESCANBUS = DRVRESCANBUS; +unsigned IOCTL_DRVCTLCOMMAND = DRVCTLCOMMAND; +unsigned IOCTL_DRVRESUMEDEV = DRVRESUMEDEV; +unsigned IOCTL_DRVLISTDEV = DRVLISTDEV; +unsigned IOCTL_DRVGETEVENT = DRVGETEVENT; +unsigned IOCTL_DRVSUSPENDDEV = DRVSUSPENDDEV; +unsigned IOCTL_DVD_READ_STRUCT = DVD_READ_STRUCT; +unsigned IOCTL_DVD_WRITE_STRUCT = DVD_WRITE_STRUCT; +unsigned IOCTL_DVD_AUTH = DVD_AUTH; +unsigned IOCTL_ENVSYS_GETDICTIONARY = ENVSYS_GETDICTIONARY; +unsigned IOCTL_ENVSYS_SETDICTIONARY = ENVSYS_SETDICTIONARY; +unsigned IOCTL_ENVSYS_REMOVEPROPS = ENVSYS_REMOVEPROPS; +unsigned IOCTL_ENVSYS_GTREDATA = ENVSYS_GTREDATA; +unsigned IOCTL_ENVSYS_GTREINFO = ENVSYS_GTREINFO; +unsigned IOCTL_KFILTER_BYFILTER = KFILTER_BYFILTER; +unsigned IOCTL_KFILTER_BYNAME = KFILTER_BYNAME; +unsigned IOCTL_FDIOCGETOPTS = FDIOCGETOPTS; +unsigned IOCTL_FDIOCSETOPTS = FDIOCSETOPTS; +unsigned IOCTL_FDIOCSETFORMAT = FDIOCSETFORMAT; +unsigned IOCTL_FDIOCGETFORMAT = FDIOCGETFORMAT; +unsigned IOCTL_FDIOCFORMAT_TRACK = FDIOCFORMAT_TRACK;  unsigned IOCTL_FIOCLEX = FIOCLEX; -unsigned IOCTL_FIOGETOWN = FIOGETOWN; -unsigned IOCTL_FIONBIO = FIONBIO;  unsigned IOCTL_FIONCLEX = FIONCLEX; +unsigned IOCTL_FIONREAD = FIONREAD; +unsigned IOCTL_FIONBIO = FIONBIO; +unsigned IOCTL_FIOASYNC = FIOASYNC;  unsigned IOCTL_FIOSETOWN = FIOSETOWN; -unsigned IOCTL_SIOCADDMULTI = SIOCADDMULTI; +unsigned IOCTL_FIOGETOWN = FIOGETOWN; +unsigned IOCTL_OFIOGETBMAP = OFIOGETBMAP; +unsigned IOCTL_FIOGETBMAP = FIOGETBMAP; +unsigned IOCTL_FIONWRITE = FIONWRITE; +unsigned IOCTL_FIONSPACE = FIONSPACE; +unsigned IOCTL_GPIOINFO = GPIOINFO; +unsigned IOCTL_GPIOSET = GPIOSET; +unsigned IOCTL_GPIOUNSET = GPIOUNSET; +unsigned IOCTL_GPIOREAD = GPIOREAD; +unsigned IOCTL_GPIOWRITE = GPIOWRITE; +unsigned IOCTL_GPIOTOGGLE = GPIOTOGGLE; +unsigned IOCTL_GPIOATTACH = GPIOATTACH; +unsigned IOCTL_PTIOCNETBSD = PTIOCNETBSD; +unsigned IOCTL_PTIOCSUNOS = PTIOCSUNOS; +unsigned IOCTL_PTIOCLINUX = PTIOCLINUX; +unsigned IOCTL_PTIOCFREEBSD = PTIOCFREEBSD; +unsigned IOCTL_PTIOCULTRIX = PTIOCULTRIX; +unsigned IOCTL_TIOCHPCL = TIOCHPCL; +unsigned IOCTL_TIOCGETP = TIOCGETP; +unsigned IOCTL_TIOCSETP = TIOCSETP; +unsigned IOCTL_TIOCSETN = TIOCSETN; +unsigned IOCTL_TIOCSETC = TIOCSETC; +unsigned IOCTL_TIOCGETC = TIOCGETC; +unsigned IOCTL_TIOCLBIS = TIOCLBIS; +unsigned IOCTL_TIOCLBIC = TIOCLBIC; +unsigned IOCTL_TIOCLSET = TIOCLSET; +unsigned IOCTL_TIOCLGET = TIOCLGET; +unsigned IOCTL_TIOCSLTC = TIOCSLTC; +unsigned IOCTL_TIOCGLTC = TIOCGLTC; +unsigned IOCTL_OTIOCCONS = OTIOCCONS; +unsigned IOCTL_JOY_SETTIMEOUT = JOY_SETTIMEOUT; +unsigned IOCTL_JOY_GETTIMEOUT = JOY_GETTIMEOUT; +unsigned IOCTL_JOY_SET_X_OFFSET = JOY_SET_X_OFFSET; +unsigned IOCTL_JOY_SET_Y_OFFSET = JOY_SET_Y_OFFSET; +unsigned IOCTL_JOY_GET_X_OFFSET = JOY_GET_X_OFFSET; +unsigned IOCTL_JOY_GET_Y_OFFSET = JOY_GET_Y_OFFSET; +unsigned IOCTL_OKIOCGSYMBOL = OKIOCGSYMBOL; +unsigned IOCTL_OKIOCGVALUE = OKIOCGVALUE; +unsigned IOCTL_KIOCGSIZE = KIOCGSIZE; +unsigned IOCTL_KIOCGVALUE = KIOCGVALUE; +unsigned IOCTL_KIOCGSYMBOL = KIOCGSYMBOL; +unsigned IOCTL_LUAINFO = LUAINFO; +unsigned IOCTL_LUACREATE = LUACREATE; +unsigned IOCTL_LUADESTROY = LUADESTROY; +unsigned IOCTL_LUAREQUIRE = LUAREQUIRE; +unsigned IOCTL_LUALOAD = LUALOAD; +unsigned IOCTL_MIDI_PRETIME = MIDI_PRETIME; +unsigned IOCTL_MIDI_MPUMODE = MIDI_MPUMODE; +unsigned IOCTL_MIDI_MPUCMD = MIDI_MPUCMD; +unsigned IOCTL_SEQUENCER_RESET = SEQUENCER_RESET; +unsigned IOCTL_SEQUENCER_SYNC = SEQUENCER_SYNC; +unsigned IOCTL_SEQUENCER_INFO = SEQUENCER_INFO; +unsigned IOCTL_SEQUENCER_CTRLRATE = SEQUENCER_CTRLRATE; +unsigned IOCTL_SEQUENCER_GETOUTCOUNT = SEQUENCER_GETOUTCOUNT; +unsigned IOCTL_SEQUENCER_GETINCOUNT = SEQUENCER_GETINCOUNT; +unsigned IOCTL_SEQUENCER_RESETSAMPLES = SEQUENCER_RESETSAMPLES; +unsigned IOCTL_SEQUENCER_NRSYNTHS = SEQUENCER_NRSYNTHS; +unsigned IOCTL_SEQUENCER_NRMIDIS = SEQUENCER_NRMIDIS; +unsigned IOCTL_SEQUENCER_THRESHOLD = SEQUENCER_THRESHOLD; +unsigned IOCTL_SEQUENCER_MEMAVL = SEQUENCER_MEMAVL; +unsigned IOCTL_SEQUENCER_PANIC = SEQUENCER_PANIC; +unsigned IOCTL_SEQUENCER_OUTOFBAND = SEQUENCER_OUTOFBAND; +unsigned IOCTL_SEQUENCER_GETTIME = SEQUENCER_GETTIME; +unsigned IOCTL_SEQUENCER_TMR_TIMEBASE = SEQUENCER_TMR_TIMEBASE; +unsigned IOCTL_SEQUENCER_TMR_START = SEQUENCER_TMR_START; +unsigned IOCTL_SEQUENCER_TMR_STOP = SEQUENCER_TMR_STOP; +unsigned IOCTL_SEQUENCER_TMR_CONTINUE = SEQUENCER_TMR_CONTINUE; +unsigned IOCTL_SEQUENCER_TMR_TEMPO = SEQUENCER_TMR_TEMPO; +unsigned IOCTL_SEQUENCER_TMR_SOURCE = SEQUENCER_TMR_SOURCE; +unsigned IOCTL_SEQUENCER_TMR_METRONOME = SEQUENCER_TMR_METRONOME; +unsigned IOCTL_SEQUENCER_TMR_SELECT = SEQUENCER_TMR_SELECT; +unsigned IOCTL_MTIOCTOP = MTIOCTOP; +unsigned IOCTL_MTIOCGET = MTIOCGET; +unsigned IOCTL_MTIOCIEOT = MTIOCIEOT; +unsigned IOCTL_MTIOCEEOT = MTIOCEEOT; +unsigned IOCTL_MTIOCRDSPOS = MTIOCRDSPOS; +unsigned IOCTL_MTIOCRDHPOS = MTIOCRDHPOS; +unsigned IOCTL_MTIOCSLOCATE = MTIOCSLOCATE; +unsigned IOCTL_MTIOCHLOCATE = MTIOCHLOCATE; +unsigned IOCTL_POWER_EVENT_RECVDICT = POWER_EVENT_RECVDICT; +unsigned IOCTL_POWER_IOC_GET_TYPE = POWER_IOC_GET_TYPE; +unsigned IOCTL_POWER_IOC_GET_TYPE_WITH_LOSSAGE = +    POWER_IOC_GET_TYPE_WITH_LOSSAGE; +unsigned IOCTL_RIOCGINFO = RIOCGINFO; +unsigned IOCTL_RIOCSINFO = RIOCSINFO; +unsigned IOCTL_RIOCSSRCH = RIOCSSRCH; +unsigned IOCTL_RNDGETENTCNT = RNDGETENTCNT; +unsigned IOCTL_RNDGETSRCNUM = RNDGETSRCNUM; +unsigned IOCTL_RNDGETSRCNAME = RNDGETSRCNAME; +unsigned IOCTL_RNDCTL = RNDCTL; +unsigned IOCTL_RNDADDDATA = RNDADDDATA; +unsigned IOCTL_RNDGETPOOLSTAT = RNDGETPOOLSTAT; +unsigned IOCTL_RNDGETESTNUM = RNDGETESTNUM; +unsigned IOCTL_RNDGETESTNAME = RNDGETESTNAME; +unsigned IOCTL_SCIOCGET = SCIOCGET; +unsigned IOCTL_SCIOCSET = SCIOCSET; +unsigned IOCTL_SCIOCRESTART = SCIOCRESTART; +unsigned IOCTL_SCIOC_USE_ADF = SCIOC_USE_ADF; +unsigned IOCTL_SCIOCCOMMAND = SCIOCCOMMAND; +unsigned IOCTL_SCIOCDEBUG = SCIOCDEBUG; +unsigned IOCTL_SCIOCIDENTIFY = SCIOCIDENTIFY; +unsigned IOCTL_OSCIOCIDENTIFY = OSCIOCIDENTIFY; +unsigned IOCTL_SCIOCDECONFIG = SCIOCDECONFIG; +unsigned IOCTL_SCIOCRECONFIG = SCIOCRECONFIG; +unsigned IOCTL_SCIOCRESET = SCIOCRESET; +unsigned IOCTL_SCBUSIOSCAN = SCBUSIOSCAN; +unsigned IOCTL_SCBUSIORESET = SCBUSIORESET; +unsigned IOCTL_SCBUSIODETACH = SCBUSIODETACH; +unsigned IOCTL_SCBUSACCEL = SCBUSACCEL; +unsigned IOCTL_SCBUSIOLLSCAN = SCBUSIOLLSCAN; +unsigned IOCTL_SIOCSHIWAT = SIOCSHIWAT; +unsigned IOCTL_SIOCGHIWAT = SIOCGHIWAT; +unsigned IOCTL_SIOCSLOWAT = SIOCSLOWAT; +unsigned IOCTL_SIOCGLOWAT = SIOCGLOWAT;  unsigned IOCTL_SIOCATMARK = SIOCATMARK; -unsigned IOCTL_SIOCDELMULTI = SIOCDELMULTI; -unsigned IOCTL_SIOCGIFADDR = SIOCGIFADDR; -unsigned IOCTL_SIOCGIFBRDADDR = SIOCGIFBRDADDR; -unsigned IOCTL_SIOCGIFCONF = SIOCGIFCONF; -unsigned IOCTL_SIOCGIFDSTADDR = SIOCGIFDSTADDR; -unsigned IOCTL_SIOCGIFFLAGS = SIOCGIFFLAGS; -unsigned IOCTL_SIOCGIFMETRIC = SIOCGIFMETRIC; -unsigned IOCTL_SIOCGIFMTU = SIOCGIFMTU; -unsigned IOCTL_SIOCGIFNETMASK = SIOCGIFNETMASK; +unsigned IOCTL_SIOCSPGRP = SIOCSPGRP;  unsigned IOCTL_SIOCGPGRP = SIOCGPGRP; +unsigned IOCTL_SIOCADDRT = SIOCADDRT; +unsigned IOCTL_SIOCDELRT = SIOCDELRT;  unsigned IOCTL_SIOCSIFADDR = SIOCSIFADDR; -unsigned IOCTL_SIOCSIFBRDADDR = SIOCSIFBRDADDR; +unsigned IOCTL_SIOCGIFADDR = SIOCGIFADDR;  unsigned IOCTL_SIOCSIFDSTADDR = SIOCSIFDSTADDR; +unsigned IOCTL_SIOCGIFDSTADDR = SIOCGIFDSTADDR;  unsigned IOCTL_SIOCSIFFLAGS = SIOCSIFFLAGS; +unsigned IOCTL_SIOCGIFFLAGS = SIOCGIFFLAGS; +unsigned IOCTL_SIOCGIFBRDADDR = SIOCGIFBRDADDR; +unsigned IOCTL_SIOCSIFBRDADDR = SIOCSIFBRDADDR; +unsigned IOCTL_SIOCGIFCONF = SIOCGIFCONF; +unsigned IOCTL_SIOCGIFNETMASK = SIOCGIFNETMASK; +unsigned IOCTL_SIOCSIFNETMASK = SIOCSIFNETMASK; +unsigned IOCTL_SIOCGIFMETRIC = SIOCGIFMETRIC;  unsigned IOCTL_SIOCSIFMETRIC = SIOCSIFMETRIC; +unsigned IOCTL_SIOCDIFADDR = SIOCDIFADDR; +unsigned IOCTL_SIOCAIFADDR = SIOCAIFADDR; +unsigned IOCTL_SIOCGIFALIAS = SIOCGIFALIAS; +unsigned IOCTL_SIOCGIFAFLAG_IN = SIOCGIFAFLAG_IN; +unsigned IOCTL_SIOCALIFADDR = SIOCALIFADDR; +unsigned IOCTL_SIOCGLIFADDR = SIOCGLIFADDR; +unsigned IOCTL_SIOCDLIFADDR = SIOCDLIFADDR; +unsigned IOCTL_SIOCSIFADDRPREF = SIOCSIFADDRPREF; +unsigned IOCTL_SIOCGIFADDRPREF = SIOCGIFADDRPREF; +unsigned IOCTL_SIOCADDMULTI = SIOCADDMULTI; +unsigned IOCTL_SIOCDELMULTI = SIOCDELMULTI; +unsigned IOCTL_SIOCGETVIFCNT = SIOCGETVIFCNT; +unsigned IOCTL_SIOCGETSGCNT = SIOCGETSGCNT; +unsigned IOCTL_SIOCSIFMEDIA = SIOCSIFMEDIA; +unsigned IOCTL_SIOCGIFMEDIA = SIOCGIFMEDIA; +unsigned IOCTL_SIOCSIFGENERIC = SIOCSIFGENERIC; +unsigned IOCTL_SIOCGIFGENERIC = SIOCGIFGENERIC; +unsigned IOCTL_SIOCSIFPHYADDR = SIOCSIFPHYADDR; +unsigned IOCTL_SIOCGIFPSRCADDR = SIOCGIFPSRCADDR; +unsigned IOCTL_SIOCGIFPDSTADDR = SIOCGIFPDSTADDR; +unsigned IOCTL_SIOCDIFPHYADDR = SIOCDIFPHYADDR; +unsigned IOCTL_SIOCSLIFPHYADDR = SIOCSLIFPHYADDR; +unsigned IOCTL_SIOCGLIFPHYADDR = SIOCGLIFPHYADDR;  unsigned IOCTL_SIOCSIFMTU = SIOCSIFMTU; -unsigned IOCTL_SIOCSIFNETMASK = SIOCSIFNETMASK; -unsigned IOCTL_SIOCSPGRP = SIOCSPGRP; -unsigned IOCTL_TIOCCONS = TIOCCONS; +unsigned IOCTL_SIOCGIFMTU = SIOCGIFMTU; +unsigned IOCTL_SIOCSDRVSPEC = SIOCSDRVSPEC; +unsigned IOCTL_SIOCGDRVSPEC = SIOCGDRVSPEC; +unsigned IOCTL_SIOCIFCREATE = SIOCIFCREATE; +unsigned IOCTL_SIOCIFDESTROY = SIOCIFDESTROY; +unsigned IOCTL_SIOCIFGCLONERS = SIOCIFGCLONERS; +unsigned IOCTL_SIOCGIFDLT = SIOCGIFDLT; +unsigned IOCTL_SIOCGIFCAP = SIOCGIFCAP; +unsigned IOCTL_SIOCSIFCAP = SIOCSIFCAP; +unsigned IOCTL_SIOCSVH = SIOCSVH; +unsigned IOCTL_SIOCGVH = SIOCGVH; +unsigned IOCTL_SIOCINITIFADDR = SIOCINITIFADDR; +unsigned IOCTL_SIOCGIFDATA = SIOCGIFDATA; +unsigned IOCTL_SIOCZIFDATA = SIOCZIFDATA; +unsigned IOCTL_SIOCGLINKSTR = SIOCGLINKSTR; +unsigned IOCTL_SIOCSLINKSTR = SIOCSLINKSTR; +unsigned IOCTL_SIOCGETHERCAP = SIOCGETHERCAP; +unsigned IOCTL_SIOCGIFINDEX = SIOCGIFINDEX; +unsigned IOCTL_SIOCSETPFSYNC = SIOCSETPFSYNC; +unsigned IOCTL_SIOCGETPFSYNC = SIOCGETPFSYNC; +unsigned IOCTL_PPS_IOC_CREATE = PPS_IOC_CREATE; +unsigned IOCTL_PPS_IOC_DESTROY = PPS_IOC_DESTROY; +unsigned IOCTL_PPS_IOC_SETPARAMS = PPS_IOC_SETPARAMS; +unsigned IOCTL_PPS_IOC_GETPARAMS = PPS_IOC_GETPARAMS; +unsigned IOCTL_PPS_IOC_GETCAP = PPS_IOC_GETCAP; +unsigned IOCTL_PPS_IOC_FETCH = PPS_IOC_FETCH; +unsigned IOCTL_PPS_IOC_KCBIND = PPS_IOC_KCBIND;  unsigned IOCTL_TIOCEXCL = TIOCEXCL; -unsigned IOCTL_TIOCGETD = TIOCGETD; -unsigned IOCTL_TIOCGPGRP = TIOCGPGRP; -unsigned IOCTL_TIOCGWINSZ = TIOCGWINSZ; -unsigned IOCTL_TIOCMBIC = TIOCMBIC; -unsigned IOCTL_TIOCMBIS = TIOCMBIS; -unsigned IOCTL_TIOCMGET = TIOCMGET; -unsigned IOCTL_TIOCMSET = TIOCMSET; -unsigned IOCTL_TIOCNOTTY = TIOCNOTTY;  unsigned IOCTL_TIOCNXCL = TIOCNXCL; -unsigned IOCTL_TIOCOUTQ = TIOCOUTQ; -unsigned IOCTL_TIOCPKT = TIOCPKT; -unsigned IOCTL_TIOCSCTTY = TIOCSCTTY; +unsigned IOCTL_TIOCFLUSH = TIOCFLUSH; +unsigned IOCTL_TIOCGETA = TIOCGETA; +unsigned IOCTL_TIOCSETA = TIOCSETA; +unsigned IOCTL_TIOCSETAW = TIOCSETAW; +unsigned IOCTL_TIOCSETAF = TIOCSETAF; +unsigned IOCTL_TIOCGETD = TIOCGETD;  unsigned IOCTL_TIOCSETD = TIOCSETD; +unsigned IOCTL_TIOCGLINED = TIOCGLINED; +unsigned IOCTL_TIOCSLINED = TIOCSLINED; +unsigned IOCTL_TIOCSBRK = TIOCSBRK; +unsigned IOCTL_TIOCCBRK = TIOCCBRK; +unsigned IOCTL_TIOCSDTR = TIOCSDTR; +unsigned IOCTL_TIOCCDTR = TIOCCDTR; +unsigned IOCTL_TIOCGPGRP = TIOCGPGRP;  unsigned IOCTL_TIOCSPGRP = TIOCSPGRP; +unsigned IOCTL_TIOCOUTQ = TIOCOUTQ;  unsigned IOCTL_TIOCSTI = TIOCSTI; +unsigned IOCTL_TIOCNOTTY = TIOCNOTTY; +unsigned IOCTL_TIOCPKT = TIOCPKT; +unsigned IOCTL_TIOCSTOP = TIOCSTOP; +unsigned IOCTL_TIOCSTART = TIOCSTART; +unsigned IOCTL_TIOCMSET = TIOCMSET; +unsigned IOCTL_TIOCMBIS = TIOCMBIS; +unsigned IOCTL_TIOCMBIC = TIOCMBIC; +unsigned IOCTL_TIOCMGET = TIOCMGET; +unsigned IOCTL_TIOCREMOTE = TIOCREMOTE; +unsigned IOCTL_TIOCGWINSZ = TIOCGWINSZ;  unsigned IOCTL_TIOCSWINSZ = TIOCSWINSZ; -unsigned IOCTL_SIOCGETSGCNT = SIOCGETSGCNT; -unsigned IOCTL_SIOCGETVIFCNT = SIOCGETVIFCNT; +unsigned IOCTL_TIOCUCNTL = TIOCUCNTL; +unsigned IOCTL_TIOCSTAT = TIOCSTAT; +unsigned IOCTL_TIOCGSID = TIOCGSID; +unsigned IOCTL_TIOCCONS = TIOCCONS; +unsigned IOCTL_TIOCSCTTY = TIOCSCTTY; +unsigned IOCTL_TIOCEXT = TIOCEXT; +unsigned IOCTL_TIOCSIG = TIOCSIG; +unsigned IOCTL_TIOCDRAIN = TIOCDRAIN; +unsigned IOCTL_TIOCGFLAGS = TIOCGFLAGS; +unsigned IOCTL_TIOCSFLAGS = TIOCSFLAGS; +unsigned IOCTL_TIOCDCDTIMESTAMP = TIOCDCDTIMESTAMP; +unsigned IOCTL_TIOCRCVFRAME = TIOCRCVFRAME; +unsigned IOCTL_TIOCXMTFRAME = TIOCXMTFRAME; +unsigned IOCTL_TIOCPTMGET = TIOCPTMGET; +unsigned IOCTL_TIOCGRANTPT = TIOCGRANTPT; +unsigned IOCTL_TIOCPTSNAME = TIOCPTSNAME; +unsigned IOCTL_TIOCSQSIZE = TIOCSQSIZE; +unsigned IOCTL_TIOCGQSIZE = TIOCGQSIZE; +unsigned IOCTL_VERIEXEC_LOAD = VERIEXEC_LOAD; +unsigned IOCTL_VERIEXEC_TABLESIZE = VERIEXEC_TABLESIZE; +unsigned IOCTL_VERIEXEC_DELETE = VERIEXEC_DELETE; +unsigned IOCTL_VERIEXEC_QUERY = VERIEXEC_QUERY; +unsigned IOCTL_VERIEXEC_DUMP = VERIEXEC_DUMP; +unsigned IOCTL_VERIEXEC_FLUSH = VERIEXEC_FLUSH; +unsigned IOCTL_VIDIOC_QUERYCAP = VIDIOC_QUERYCAP; +unsigned IOCTL_VIDIOC_RESERVED = VIDIOC_RESERVED; +unsigned IOCTL_VIDIOC_ENUM_FMT = VIDIOC_ENUM_FMT; +unsigned IOCTL_VIDIOC_G_FMT = VIDIOC_G_FMT; +unsigned IOCTL_VIDIOC_S_FMT = VIDIOC_S_FMT; +unsigned IOCTL_VIDIOC_REQBUFS = VIDIOC_REQBUFS; +unsigned IOCTL_VIDIOC_QUERYBUF = VIDIOC_QUERYBUF; +unsigned IOCTL_VIDIOC_G_FBUF = VIDIOC_G_FBUF; +unsigned IOCTL_VIDIOC_S_FBUF = VIDIOC_S_FBUF; +unsigned IOCTL_VIDIOC_OVERLAY = VIDIOC_OVERLAY; +unsigned IOCTL_VIDIOC_QBUF = VIDIOC_QBUF; +unsigned IOCTL_VIDIOC_DQBUF = VIDIOC_DQBUF; +unsigned IOCTL_VIDIOC_STREAMON = VIDIOC_STREAMON; +unsigned IOCTL_VIDIOC_STREAMOFF = VIDIOC_STREAMOFF; +unsigned IOCTL_VIDIOC_G_PARM = VIDIOC_G_PARM; +unsigned IOCTL_VIDIOC_S_PARM = VIDIOC_S_PARM; +unsigned IOCTL_VIDIOC_G_STD = VIDIOC_G_STD; +unsigned IOCTL_VIDIOC_S_STD = VIDIOC_S_STD; +unsigned IOCTL_VIDIOC_ENUMSTD = VIDIOC_ENUMSTD; +unsigned IOCTL_VIDIOC_ENUMINPUT = VIDIOC_ENUMINPUT; +unsigned IOCTL_VIDIOC_G_CTRL = VIDIOC_G_CTRL; +unsigned IOCTL_VIDIOC_S_CTRL = VIDIOC_S_CTRL; +unsigned IOCTL_VIDIOC_G_TUNER = VIDIOC_G_TUNER; +unsigned IOCTL_VIDIOC_S_TUNER = VIDIOC_S_TUNER; +unsigned IOCTL_VIDIOC_G_AUDIO = VIDIOC_G_AUDIO; +unsigned IOCTL_VIDIOC_S_AUDIO = VIDIOC_S_AUDIO; +unsigned IOCTL_VIDIOC_QUERYCTRL = VIDIOC_QUERYCTRL; +unsigned IOCTL_VIDIOC_QUERYMENU = VIDIOC_QUERYMENU; +unsigned IOCTL_VIDIOC_G_INPUT = VIDIOC_G_INPUT; +unsigned IOCTL_VIDIOC_S_INPUT = VIDIOC_S_INPUT; +unsigned IOCTL_VIDIOC_G_OUTPUT = VIDIOC_G_OUTPUT; +unsigned IOCTL_VIDIOC_S_OUTPUT = VIDIOC_S_OUTPUT; +unsigned IOCTL_VIDIOC_ENUMOUTPUT = VIDIOC_ENUMOUTPUT; +unsigned IOCTL_VIDIOC_G_AUDOUT = VIDIOC_G_AUDOUT; +unsigned IOCTL_VIDIOC_S_AUDOUT = VIDIOC_S_AUDOUT; +unsigned IOCTL_VIDIOC_G_MODULATOR = VIDIOC_G_MODULATOR; +unsigned IOCTL_VIDIOC_S_MODULATOR = VIDIOC_S_MODULATOR; +unsigned IOCTL_VIDIOC_G_FREQUENCY = VIDIOC_G_FREQUENCY; +unsigned IOCTL_VIDIOC_S_FREQUENCY = VIDIOC_S_FREQUENCY; +unsigned IOCTL_VIDIOC_CROPCAP = VIDIOC_CROPCAP; +unsigned IOCTL_VIDIOC_G_CROP = VIDIOC_G_CROP; +unsigned IOCTL_VIDIOC_S_CROP = VIDIOC_S_CROP; +unsigned IOCTL_VIDIOC_G_JPEGCOMP = VIDIOC_G_JPEGCOMP; +unsigned IOCTL_VIDIOC_S_JPEGCOMP = VIDIOC_S_JPEGCOMP; +unsigned IOCTL_VIDIOC_QUERYSTD = VIDIOC_QUERYSTD; +unsigned IOCTL_VIDIOC_TRY_FMT = VIDIOC_TRY_FMT; +unsigned IOCTL_VIDIOC_ENUMAUDIO = VIDIOC_ENUMAUDIO; +unsigned IOCTL_VIDIOC_ENUMAUDOUT = VIDIOC_ENUMAUDOUT; +unsigned IOCTL_VIDIOC_G_PRIORITY = VIDIOC_G_PRIORITY; +unsigned IOCTL_VIDIOC_S_PRIORITY = VIDIOC_S_PRIORITY; +unsigned IOCTL_VIDIOC_ENUM_FRAMESIZES = VIDIOC_ENUM_FRAMESIZES; +unsigned IOCTL_VIDIOC_ENUM_FRAMEINTERVALS = VIDIOC_ENUM_FRAMEINTERVALS; +unsigned IOCTL_WDOGIOC_GMODE = WDOGIOC_GMODE; +unsigned IOCTL_WDOGIOC_SMODE = WDOGIOC_SMODE; +unsigned IOCTL_WDOGIOC_WHICH = WDOGIOC_WHICH; +unsigned IOCTL_WDOGIOC_TICKLE = WDOGIOC_TICKLE; +unsigned IOCTL_WDOGIOC_GTICKLER = WDOGIOC_GTICKLER; +unsigned IOCTL_WDOGIOC_GWDOGS = WDOGIOC_GWDOGS; +unsigned IOCTL_SNDCTL_DSP_RESET = SNDCTL_DSP_RESET; +unsigned IOCTL_SNDCTL_DSP_SYNC = SNDCTL_DSP_SYNC; +unsigned IOCTL_SNDCTL_DSP_SPEED = SNDCTL_DSP_SPEED; +unsigned IOCTL_SOUND_PCM_READ_RATE = SOUND_PCM_READ_RATE; +unsigned IOCTL_SNDCTL_DSP_STEREO = SNDCTL_DSP_STEREO; +unsigned IOCTL_SNDCTL_DSP_GETBLKSIZE = SNDCTL_DSP_GETBLKSIZE; +unsigned IOCTL_SNDCTL_DSP_SETFMT = SNDCTL_DSP_SETFMT; +unsigned IOCTL_SOUND_PCM_READ_BITS = SOUND_PCM_READ_BITS; +unsigned IOCTL_SNDCTL_DSP_CHANNELS = SNDCTL_DSP_CHANNELS; +unsigned IOCTL_SOUND_PCM_READ_CHANNELS = SOUND_PCM_READ_CHANNELS; +unsigned IOCTL_SOUND_PCM_WRITE_FILTER = SOUND_PCM_WRITE_FILTER; +unsigned IOCTL_SOUND_PCM_READ_FILTER = SOUND_PCM_READ_FILTER; +unsigned IOCTL_SNDCTL_DSP_POST = SNDCTL_DSP_POST; +unsigned IOCTL_SNDCTL_DSP_SUBDIVIDE = SNDCTL_DSP_SUBDIVIDE; +unsigned IOCTL_SNDCTL_DSP_SETFRAGMENT = SNDCTL_DSP_SETFRAGMENT; +unsigned IOCTL_SNDCTL_DSP_GETFMTS = SNDCTL_DSP_GETFMTS; +unsigned IOCTL_SNDCTL_DSP_GETOSPACE = SNDCTL_DSP_GETOSPACE; +unsigned IOCTL_SNDCTL_DSP_GETISPACE = SNDCTL_DSP_GETISPACE; +unsigned IOCTL_SNDCTL_DSP_NONBLOCK = SNDCTL_DSP_NONBLOCK; +unsigned IOCTL_SNDCTL_DSP_GETCAPS = SNDCTL_DSP_GETCAPS; +unsigned IOCTL_SNDCTL_DSP_GETTRIGGER = SNDCTL_DSP_GETTRIGGER; +unsigned IOCTL_SNDCTL_DSP_SETTRIGGER = SNDCTL_DSP_SETTRIGGER; +unsigned IOCTL_SNDCTL_DSP_GETIPTR = SNDCTL_DSP_GETIPTR; +unsigned IOCTL_SNDCTL_DSP_GETOPTR = SNDCTL_DSP_GETOPTR; +unsigned IOCTL_SNDCTL_DSP_MAPINBUF = SNDCTL_DSP_MAPINBUF; +unsigned IOCTL_SNDCTL_DSP_MAPOUTBUF = SNDCTL_DSP_MAPOUTBUF; +unsigned IOCTL_SNDCTL_DSP_SETSYNCRO = SNDCTL_DSP_SETSYNCRO; +unsigned IOCTL_SNDCTL_DSP_SETDUPLEX = SNDCTL_DSP_SETDUPLEX; +unsigned IOCTL_SNDCTL_DSP_PROFILE = SNDCTL_DSP_PROFILE; +unsigned IOCTL_SNDCTL_DSP_GETODELAY = SNDCTL_DSP_GETODELAY; +unsigned IOCTL_SOUND_MIXER_INFO = SOUND_MIXER_INFO; +unsigned IOCTL_SOUND_OLD_MIXER_INFO = SOUND_OLD_MIXER_INFO; +unsigned IOCTL_OSS_GETVERSION = OSS_GETVERSION; +unsigned IOCTL_SNDCTL_SYSINFO = SNDCTL_SYSINFO; +unsigned IOCTL_SNDCTL_AUDIOINFO = SNDCTL_AUDIOINFO; +unsigned IOCTL_SNDCTL_ENGINEINFO = SNDCTL_ENGINEINFO; +unsigned IOCTL_SNDCTL_DSP_GETPLAYVOL = SNDCTL_DSP_GETPLAYVOL; +unsigned IOCTL_SNDCTL_DSP_SETPLAYVOL = SNDCTL_DSP_SETPLAYVOL; +unsigned IOCTL_SNDCTL_DSP_GETRECVOL = SNDCTL_DSP_GETRECVOL; +unsigned IOCTL_SNDCTL_DSP_SETRECVOL = SNDCTL_DSP_SETRECVOL; +unsigned IOCTL_SNDCTL_DSP_SKIP = SNDCTL_DSP_SKIP; +unsigned IOCTL_SNDCTL_DSP_SILENCE = SNDCTL_DSP_SILENCE;  const int si_SEGV_MAPERR = SEGV_MAPERR;  const int si_SEGV_ACCERR = SEGV_ACCERR; diff --git a/lib/sanitizer_common/sanitizer_platform_limits_netbsd.h b/lib/sanitizer_common/sanitizer_platform_limits_netbsd.h index 6823004d7b417..1718e3b1e8eaa 100644 --- a/lib/sanitizer_common/sanitizer_platform_limits_netbsd.h +++ b/lib/sanitizer_common/sanitizer_platform_limits_netbsd.h @@ -57,33 +57,36 @@ extern unsigned ucontext_t_sz;  extern unsigned struct_rlimit_sz;  extern unsigned struct_utimbuf_sz;  extern unsigned struct_timespec_sz; +extern unsigned struct_sembuf_sz; -struct __sanitizer_iocb { +extern unsigned struct_kevent_sz; + +union __sanitizer_sigval { +  int sival_int; +  uptr sival_ptr; +}; + +struct __sanitizer_sigevent { +  int sigev_notify; +  int sigev_signo; +  union __sanitizer_sigval sigev_value; +  uptr sigev_notify_function; +  uptr sigev_notify_attributes; +}; + +struct __sanitizer_aiocb {    u64 aio_offset;    uptr aio_buf; -  long aio_nbytes; -  u32 aio_fildes; -  u32 aio_lio_opcode; -  long aio_reqprio; -#if SANITIZER_WORDSIZE == 64 -  u8 aio_sigevent[32]; -#else -  u8 aio_sigevent[20]; -#endif -  u32 _state; -  u32 _errno; +  uptr aio_nbytes; +  int aio_fildes; +  int aio_lio_opcode; +  int aio_reqprio; +  struct __sanitizer_sigevent aio_sigevent; +  int _state; +  int _errno;    long _retval;  }; -struct __sanitizer___sysctl_args { -  int *name; -  int nlen; -  void *oldval; -  uptr *oldlenp; -  void *newval; -  uptr newlen; -}; -  struct __sanitizer_sem_t {    uptr data[5];  }; @@ -110,6 +113,19 @@ struct __sanitizer_shmid_ds {    void *_shm_internal;  }; +struct __sanitizer_protoent { +  char *p_name; +  char **p_aliases; +  int p_proto; +}; + +struct __sanitizer_netent { +  char *n_name; +  char **n_aliases; +  int n_addrtype; +  u32 n_net; +}; +  extern unsigned struct_msqid_ds_sz;  extern unsigned struct_mq_attr_sz;  extern unsigned struct_timex_sz; @@ -131,9 +147,27 @@ struct __sanitizer_ifaddrs {    unsigned int ifa_addrflags;  }; +typedef unsigned int __sanitizer_socklen_t; +  typedef unsigned __sanitizer_pthread_key_t;  typedef long long __sanitizer_time_t; +typedef int __sanitizer_suseconds_t; + +struct __sanitizer_timeval { +  __sanitizer_time_t tv_sec; +  __sanitizer_suseconds_t tv_usec; +}; + +struct __sanitizer_itimerval { +  struct __sanitizer_timeval it_interval; +  struct __sanitizer_timeval it_value; +}; + +struct __sanitizer_timespec { +  __sanitizer_time_t tv_sec; +  long tv_nsec; +};  struct __sanitizer_passwd {    char *pw_name; @@ -189,6 +223,12 @@ struct __sanitizer_msghdr {    unsigned msg_controllen;    int msg_flags;  }; + +struct __sanitizer_mmsghdr { +  struct __sanitizer_msghdr msg_hdr; +  unsigned int msg_len; +}; +  struct __sanitizer_cmsghdr {    unsigned cmsg_len;    int cmsg_level; @@ -241,6 +281,22 @@ struct __sanitizer_sigaction {    int sa_flags;  }; +extern unsigned struct_sigaltstack_sz; + +typedef unsigned int __sanitizer_sigset13_t; + +struct __sanitizer_sigaction13 { +  __sanitizer_sighandler_ptr osa_handler; +  __sanitizer_sigset13_t osa_mask; +  int osa_flags; +}; + +struct __sanitizer_sigaltstack { +  void *ss_sp; +  uptr ss_size; +  int ss_flags; +}; +  typedef __sanitizer_sigset_t __sanitizer_kernel_sigset_t;  struct __sanitizer_kernel_sigaction_t { @@ -298,6 +354,8 @@ struct __sanitizer_pollfd {  typedef unsigned __sanitizer_nfds_t; +typedef int __sanitizer_lwpid_t; +  struct __sanitizer_glob_t {    uptr gl_pathc;    uptr gl_matchc; @@ -317,6 +375,48 @@ extern int glob_altdirfunc;  extern unsigned path_max; +extern int struct_ttyent_sz; + +extern int ptrace_pt_io; +extern int ptrace_pt_lwpinfo; +extern int ptrace_pt_set_event_mask; +extern int ptrace_pt_get_event_mask; +extern int ptrace_pt_get_process_state; +extern int ptrace_pt_set_siginfo; +extern int ptrace_pt_get_siginfo; +extern int ptrace_piod_read_d; +extern int ptrace_piod_write_d; +extern int ptrace_piod_read_i; +extern int ptrace_piod_write_i; +extern int ptrace_piod_read_auxv; +extern int ptrace_pt_setregs; +extern int ptrace_pt_getregs; +extern int ptrace_pt_setfpregs; +extern int ptrace_pt_getfpregs; +extern int ptrace_pt_setdbregs; +extern int ptrace_pt_getdbregs; + +struct __sanitizer_ptrace_io_desc { +  int piod_op; +  void *piod_offs; +  void *piod_addr; +  uptr piod_len; +}; + +struct __sanitizer_ptrace_lwpinfo { +  __sanitizer_lwpid_t pl_lwpid; +  int pl_event; +}; + +extern unsigned struct_ptrace_ptrace_io_desc_struct_sz; +extern unsigned struct_ptrace_ptrace_lwpinfo_struct_sz; +extern unsigned struct_ptrace_ptrace_event_struct_sz; +extern unsigned struct_ptrace_ptrace_siginfo_struct_sz; + +extern unsigned struct_ptrace_reg_struct_sz; +extern unsigned struct_ptrace_fpreg_struct_sz; +extern unsigned struct_ptrace_dbreg_struct_sz; +  struct __sanitizer_wordexp_t {    uptr we_wordc;    char **we_wordv; @@ -350,6 +450,16 @@ struct __sanitizer_ifconf {    } ifc_ifcu;  }; +struct __sanitizer_ttyent { +  char *ty_name; +  char *ty_getty; +  char *ty_type; +  int ty_status; +  char *ty_window; +  char *ty_comment; +  char *ty_class; +}; +  #define IOC_NRBITS 8  #define IOC_TYPEBITS 8  #define IOC_SIZEBITS 14 @@ -374,185 +484,1713 @@ struct __sanitizer_ifconf {  #define IOC_NR(nr) (((nr) >> IOC_NRSHIFT) & IOC_NRMASK)  #define IOC_SIZE(nr) (((nr) >> IOC_SIZESHIFT) & IOC_SIZEMASK) -extern unsigned struct_ifreq_sz; -extern unsigned struct_termios_sz; -extern unsigned struct_winsize_sz; - -extern unsigned struct_arpreq_sz; +// ioctl request identifiers +extern unsigned struct_altqreq_sz; +extern unsigned struct_amr_user_ioctl_sz; +extern unsigned struct_ap_control_sz; +extern unsigned struct_apm_ctl_sz; +extern unsigned struct_apm_event_info_sz; +extern unsigned struct_apm_power_info_sz; +extern unsigned struct_atabusiodetach_args_sz; +extern unsigned struct_atabusioscan_args_sz; +extern unsigned struct_ath_diag_sz; +extern unsigned struct_atm_flowmap_sz; +extern unsigned struct_atm_pseudoioctl_sz; +extern unsigned struct_audio_buf_info_sz; +extern unsigned struct_audio_device_sz; +extern unsigned struct_audio_encoding_sz; +extern unsigned struct_audio_info_sz; +extern unsigned struct_audio_offset_sz; +extern unsigned struct_bio_locate_sz; +extern unsigned struct_bioc_alarm_sz; +extern unsigned struct_bioc_blink_sz; +extern unsigned struct_bioc_disk_sz; +extern unsigned struct_bioc_inq_sz; +extern unsigned struct_bioc_setstate_sz; +extern unsigned struct_bioc_vol_sz; +extern unsigned struct_bioc_volops_sz; +extern unsigned struct_bktr_chnlset_sz; +extern unsigned struct_bktr_remote_sz; +extern unsigned struct_blue_conf_sz; +extern unsigned struct_blue_interface_sz; +extern unsigned struct_blue_stats_sz; +extern unsigned struct_bpf_dltlist_sz; +extern unsigned struct_bpf_program_sz; +extern unsigned struct_bpf_stat_old_sz; +extern unsigned struct_bpf_stat_sz; +extern unsigned struct_bpf_version_sz; +extern unsigned struct_btreq_sz; +extern unsigned struct_btsco_info_sz; +extern unsigned struct_buffmem_desc_sz; +extern unsigned struct_cbq_add_class_sz; +extern unsigned struct_cbq_add_filter_sz; +extern unsigned struct_cbq_delete_class_sz; +extern unsigned struct_cbq_delete_filter_sz; +extern unsigned struct_cbq_getstats_sz; +extern unsigned struct_cbq_interface_sz; +extern unsigned struct_cbq_modify_class_sz; +extern unsigned struct_ccd_ioctl_sz; +extern unsigned struct_cdnr_add_element_sz; +extern unsigned struct_cdnr_add_filter_sz; +extern unsigned struct_cdnr_add_tbmeter_sz; +extern unsigned struct_cdnr_add_trtcm_sz; +extern unsigned struct_cdnr_add_tswtcm_sz; +extern unsigned struct_cdnr_delete_element_sz; +extern unsigned struct_cdnr_delete_filter_sz; +extern unsigned struct_cdnr_get_stats_sz; +extern unsigned struct_cdnr_interface_sz; +extern unsigned struct_cdnr_modify_tbmeter_sz; +extern unsigned struct_cdnr_modify_trtcm_sz; +extern unsigned struct_cdnr_modify_tswtcm_sz; +extern unsigned struct_cdnr_tbmeter_stats_sz; +extern unsigned struct_cdnr_tcm_stats_sz; +extern unsigned struct_cgd_ioctl_sz; +extern unsigned struct_cgd_user_sz; +extern unsigned struct_changer_element_status_request_sz; +extern unsigned struct_changer_exchange_request_sz; +extern unsigned struct_changer_move_request_sz; +extern unsigned struct_changer_params_sz; +extern unsigned struct_changer_position_request_sz; +extern unsigned struct_changer_set_voltag_request_sz; +extern unsigned struct_clockctl_adjtime_sz; +extern unsigned struct_clockctl_clock_settime_sz; +extern unsigned struct_clockctl_ntp_adjtime_sz; +extern unsigned struct_clockctl_settimeofday_sz; +extern unsigned struct_cnwistats_sz; +extern unsigned struct_cnwitrail_sz; +extern unsigned struct_cnwstatus_sz; +extern unsigned struct_count_info_sz; +extern unsigned struct_cpu_ucode_sz; +extern unsigned struct_cpu_ucode_version_sz; +extern unsigned struct_crypt_kop_sz; +extern unsigned struct_crypt_mkop_sz; +extern unsigned struct_crypt_mop_sz; +extern unsigned struct_crypt_op_sz; +extern unsigned struct_crypt_result_sz; +extern unsigned struct_crypt_sfop_sz; +extern unsigned struct_crypt_sgop_sz; +extern unsigned struct_cryptret_sz; +extern unsigned struct_devdetachargs_sz; +extern unsigned struct_devlistargs_sz; +extern unsigned struct_devpmargs_sz; +extern unsigned struct_devrescanargs_sz; +extern unsigned struct_disk_badsecinfo_sz; +extern unsigned struct_disk_strategy_sz; +extern unsigned struct_disklabel_sz; +extern unsigned struct_dkbad_sz; +extern unsigned struct_dkwedge_info_sz; +extern unsigned struct_dkwedge_list_sz; +extern unsigned struct_dmio_setfunc_sz; +extern unsigned struct_dmx_pes_filter_params_sz; +extern unsigned struct_dmx_sct_filter_params_sz; +extern unsigned struct_dmx_stc_sz; +extern unsigned struct_dvb_diseqc_master_cmd_sz; +extern unsigned struct_dvb_diseqc_slave_reply_sz; +extern unsigned struct_dvb_frontend_event_sz; +extern unsigned struct_dvb_frontend_info_sz; +extern unsigned struct_dvb_frontend_parameters_sz; +extern unsigned struct_eccapreq_sz; +extern unsigned struct_fbcmap_sz; +extern unsigned struct_fbcurpos_sz; +extern unsigned struct_fbcursor_sz; +extern unsigned struct_fbgattr_sz; +extern unsigned struct_fbsattr_sz; +extern unsigned struct_fbtype_sz; +extern unsigned struct_fdformat_cmd_sz; +extern unsigned struct_fdformat_parms_sz; +extern unsigned struct_fifoq_conf_sz; +extern unsigned struct_fifoq_getstats_sz; +extern unsigned struct_fifoq_interface_sz; +extern unsigned struct_format_op_sz; +extern unsigned struct_fss_get_sz; +extern unsigned struct_fss_set_sz; +extern unsigned struct_gpio_attach_sz; +extern unsigned struct_gpio_info_sz; +extern unsigned struct_gpio_req_sz; +extern unsigned struct_gpio_set_sz; +extern unsigned struct_hfsc_add_class_sz; +extern unsigned struct_hfsc_add_filter_sz; +extern unsigned struct_hfsc_attach_sz; +extern unsigned struct_hfsc_class_stats_sz; +extern unsigned struct_hfsc_delete_class_sz; +extern unsigned struct_hfsc_delete_filter_sz; +extern unsigned struct_hfsc_interface_sz; +extern unsigned struct_hfsc_modify_class_sz; +extern unsigned struct_hpcfb_dsp_op_sz; +extern unsigned struct_hpcfb_dspconf_sz; +extern unsigned struct_hpcfb_fbconf_sz; +extern unsigned struct_if_addrprefreq_sz; +extern unsigned struct_if_clonereq_sz; +extern unsigned struct_if_laddrreq_sz; +extern unsigned struct_ifaddr_sz; +extern unsigned struct_ifaliasreq_sz; +extern unsigned struct_ifcapreq_sz; +extern unsigned struct_ifconf_sz; +extern unsigned struct_ifdatareq_sz; +extern unsigned struct_ifdrv_sz; +extern unsigned struct_ifmediareq_sz; +extern unsigned struct_ifpppcstatsreq_sz; +extern unsigned struct_ifpppstatsreq_sz; +extern unsigned struct_ifreq_sz; +extern unsigned struct_in6_addrpolicy_sz; +extern unsigned struct_in6_ndireq_sz; +extern unsigned struct_ioc_load_unload_sz; +extern unsigned struct_ioc_patch_sz; +extern unsigned struct_ioc_play_blocks_sz; +extern unsigned struct_ioc_play_msf_sz; +extern unsigned struct_ioc_play_track_sz; +extern unsigned struct_ioc_read_subchannel_sz; +extern unsigned struct_ioc_read_toc_entry_sz; +extern unsigned struct_ioc_toc_header_sz; +extern unsigned struct_ioc_vol_sz; +extern unsigned struct_ioctl_pt_sz; +extern unsigned struct_ioppt_sz; +extern unsigned struct_iovec_sz; +extern unsigned struct_ipfobj_sz; +extern unsigned struct_irda_params_sz; +extern unsigned struct_isp_fc_device_sz; +extern unsigned struct_isp_fc_tsk_mgmt_sz; +extern unsigned struct_isp_hba_device_sz; +extern unsigned struct_isv_cmd_sz; +extern unsigned struct_jobs_add_class_sz; +extern unsigned struct_jobs_add_filter_sz; +extern unsigned struct_jobs_attach_sz; +extern unsigned struct_jobs_class_stats_sz; +extern unsigned struct_jobs_delete_class_sz; +extern unsigned struct_jobs_delete_filter_sz; +extern unsigned struct_jobs_interface_sz; +extern unsigned struct_jobs_modify_class_sz; +extern unsigned struct_kbentry_sz; +extern unsigned struct_kfilter_mapping_sz; +extern unsigned struct_kiockeymap_sz; +extern unsigned struct_ksyms_gsymbol_sz; +extern unsigned struct_ksyms_gvalue_sz; +extern unsigned struct_ksyms_ogsymbol_sz; +extern unsigned struct_kttcp_io_args_sz; +extern unsigned struct_ltchars_sz; +extern unsigned struct_lua_create_sz; +extern unsigned struct_lua_info_sz; +extern unsigned struct_lua_load_sz; +extern unsigned struct_lua_require_sz; +extern unsigned struct_mbpp_param_sz; +extern unsigned struct_md_conf_sz; +extern unsigned struct_meteor_capframe_sz; +extern unsigned struct_meteor_counts_sz; +extern unsigned struct_meteor_geomet_sz; +extern unsigned struct_meteor_pixfmt_sz; +extern unsigned struct_meteor_video_sz; +extern unsigned struct_mlx_cinfo_sz; +extern unsigned struct_mlx_pause_sz; +extern unsigned struct_mlx_rebuild_request_sz; +extern unsigned struct_mlx_rebuild_status_sz; +extern unsigned struct_mlx_usercommand_sz; +extern unsigned struct_mly_user_command_sz; +extern unsigned struct_mly_user_health_sz;  extern unsigned struct_mtget_sz;  extern unsigned struct_mtop_sz; -extern unsigned struct_rtentry_sz; -extern unsigned struct_sbi_instrument_sz; +extern unsigned struct_npf_ioctl_table_sz; +extern unsigned struct_npioctl_sz; +extern unsigned struct_nvme_pt_command_sz; +extern unsigned struct_ochanger_element_status_request_sz; +extern unsigned struct_ofiocdesc_sz; +extern unsigned struct_okiockey_sz; +extern unsigned struct_ortentry_sz; +extern unsigned struct_oscsi_addr_sz; +extern unsigned struct_oss_audioinfo_sz; +extern unsigned struct_oss_sysinfo_sz; +extern unsigned struct_pciio_bdf_cfgreg_sz; +extern unsigned struct_pciio_businfo_sz; +extern unsigned struct_pciio_cfgreg_sz; +extern unsigned struct_pciio_drvname_sz; +extern unsigned struct_pciio_drvnameonbus_sz; +extern unsigned struct_pcvtid_sz; +extern unsigned struct_pf_osfp_ioctl_sz; +extern unsigned struct_pf_status_sz; +extern unsigned struct_pfioc_altq_sz; +extern unsigned struct_pfioc_if_sz; +extern unsigned struct_pfioc_iface_sz; +extern unsigned struct_pfioc_limit_sz; +extern unsigned struct_pfioc_natlook_sz; +extern unsigned struct_pfioc_pooladdr_sz; +extern unsigned struct_pfioc_qstats_sz; +extern unsigned struct_pfioc_rule_sz; +extern unsigned struct_pfioc_ruleset_sz; +extern unsigned struct_pfioc_src_node_kill_sz; +extern unsigned struct_pfioc_src_nodes_sz; +extern unsigned struct_pfioc_state_kill_sz; +extern unsigned struct_pfioc_state_sz; +extern unsigned struct_pfioc_states_sz; +extern unsigned struct_pfioc_table_sz; +extern unsigned struct_pfioc_tm_sz; +extern unsigned struct_pfioc_trans_sz; +extern unsigned struct_plistref_sz; +extern unsigned struct_power_type_sz; +extern unsigned struct_ppp_idle_sz; +extern unsigned struct_ppp_option_data_sz; +extern unsigned struct_ppp_rawin_sz; +extern unsigned struct_pppoeconnectionstate_sz; +extern unsigned struct_pppoediscparms_sz; +extern unsigned struct_priq_add_class_sz; +extern unsigned struct_priq_add_filter_sz; +extern unsigned struct_priq_class_stats_sz; +extern unsigned struct_priq_delete_class_sz; +extern unsigned struct_priq_delete_filter_sz; +extern unsigned struct_priq_interface_sz; +extern unsigned struct_priq_modify_class_sz; +extern unsigned struct_ptmget_sz; +extern unsigned struct_pvctxreq_sz; +extern unsigned struct_radio_info_sz; +extern unsigned struct_red_conf_sz; +extern unsigned struct_red_interface_sz; +extern unsigned struct_red_stats_sz; +extern unsigned struct_redparams_sz; +extern unsigned struct_rf_pmparams_sz; +extern unsigned struct_rf_pmstat_sz; +extern unsigned struct_rf_recon_req_sz; +extern unsigned struct_rio_conf_sz; +extern unsigned struct_rio_interface_sz; +extern unsigned struct_rio_stats_sz; +extern unsigned struct_satlink_id_sz; +extern unsigned struct_scan_io_sz; +extern unsigned struct_scbusaccel_args_sz; +extern unsigned struct_scbusiodetach_args_sz; +extern unsigned struct_scbusioscan_args_sz; +extern unsigned struct_scsi_addr_sz;  extern unsigned struct_seq_event_rec_sz; -extern unsigned struct_synth_info_sz; -extern unsigned struct_vt_mode_sz; -extern unsigned struct_audio_buf_info_sz; -extern unsigned struct_ppp_stats_sz; +extern unsigned struct_session_op_sz; +extern unsigned struct_sgttyb_sz;  extern unsigned struct_sioc_sg_req_sz;  extern unsigned struct_sioc_vif_req_sz; +extern unsigned struct_smbioc_flags_sz; +extern unsigned struct_smbioc_lookup_sz; +extern unsigned struct_smbioc_oshare_sz; +extern unsigned struct_smbioc_ossn_sz; +extern unsigned struct_smbioc_rq_sz; +extern unsigned struct_smbioc_rw_sz; +extern unsigned struct_spppauthcfg_sz; +extern unsigned struct_spppauthfailuresettings_sz; +extern unsigned struct_spppauthfailurestats_sz; +extern unsigned struct_spppdnsaddrs_sz; +extern unsigned struct_spppdnssettings_sz; +extern unsigned struct_spppidletimeout_sz; +extern unsigned struct_spppkeepalivesettings_sz; +extern unsigned struct_sppplcpcfg_sz; +extern unsigned struct_spppstatus_sz; +extern unsigned struct_spppstatusncp_sz; +extern unsigned struct_srt_rt_sz; +extern unsigned struct_stic_xinfo_sz; +extern unsigned struct_sun_dkctlr_sz; +extern unsigned struct_sun_dkgeom_sz; +extern unsigned struct_sun_dkpart_sz; +extern unsigned struct_synth_info_sz; +extern unsigned struct_tbrreq_sz; +extern unsigned struct_tchars_sz; +extern unsigned struct_termios_sz; +extern unsigned struct_timeval_sz; +extern unsigned struct_twe_drivecommand_sz; +extern unsigned struct_twe_paramcommand_sz; +extern unsigned struct_twe_usercommand_sz; +extern unsigned struct_ukyopon_identify_sz; +extern unsigned struct_urio_command_sz; +extern unsigned struct_usb_alt_interface_sz; +extern unsigned struct_usb_bulk_ra_wb_opt_sz; +extern unsigned struct_usb_config_desc_sz; +extern unsigned struct_usb_ctl_report_desc_sz; +extern unsigned struct_usb_ctl_report_sz; +extern unsigned struct_usb_ctl_request_sz; +extern unsigned struct_usb_device_info_old_sz; +extern unsigned struct_usb_device_info_sz; +extern unsigned struct_usb_device_stats_sz; +extern unsigned struct_usb_endpoint_desc_sz; +extern unsigned struct_usb_full_desc_sz; +extern unsigned struct_usb_interface_desc_sz; +extern unsigned struct_usb_string_desc_sz; +extern unsigned struct_utoppy_readfile_sz; +extern unsigned struct_utoppy_rename_sz; +extern unsigned struct_utoppy_stats_sz; +extern unsigned struct_utoppy_writefile_sz; +extern unsigned struct_v4l2_audio_sz; +extern unsigned struct_v4l2_audioout_sz; +extern unsigned struct_v4l2_buffer_sz; +extern unsigned struct_v4l2_capability_sz; +extern unsigned struct_v4l2_control_sz; +extern unsigned struct_v4l2_crop_sz; +extern unsigned struct_v4l2_cropcap_sz; +extern unsigned struct_v4l2_fmtdesc_sz; +extern unsigned struct_v4l2_format_sz; +extern unsigned struct_v4l2_framebuffer_sz; +extern unsigned struct_v4l2_frequency_sz; +extern unsigned struct_v4l2_frmivalenum_sz; +extern unsigned struct_v4l2_frmsizeenum_sz; +extern unsigned struct_v4l2_input_sz; +extern unsigned struct_v4l2_jpegcompression_sz; +extern unsigned struct_v4l2_modulator_sz; +extern unsigned struct_v4l2_output_sz; +extern unsigned struct_v4l2_queryctrl_sz; +extern unsigned struct_v4l2_querymenu_sz; +extern unsigned struct_v4l2_requestbuffers_sz; +extern unsigned struct_v4l2_standard_sz; +extern unsigned struct_v4l2_streamparm_sz; +extern unsigned struct_v4l2_tuner_sz; +extern unsigned struct_vnd_ioctl_sz; +extern unsigned struct_vnd_user_sz; +extern unsigned struct_vt_stat_sz; +extern unsigned struct_wdog_conf_sz; +extern unsigned struct_wdog_mode_sz; +extern unsigned struct_wfq_conf_sz; +extern unsigned struct_wfq_getqid_sz; +extern unsigned struct_wfq_getstats_sz; +extern unsigned struct_wfq_interface_sz; +extern unsigned struct_wfq_setweight_sz; +extern unsigned struct_winsize_sz; +extern unsigned struct_wscons_event_sz; +extern unsigned struct_wsdisplay_addscreendata_sz; +extern unsigned struct_wsdisplay_char_sz; +extern unsigned struct_wsdisplay_cmap_sz; +extern unsigned struct_wsdisplay_curpos_sz; +extern unsigned struct_wsdisplay_cursor_sz; +extern unsigned struct_wsdisplay_delscreendata_sz; +extern unsigned struct_wsdisplay_fbinfo_sz; +extern unsigned struct_wsdisplay_font_sz; +extern unsigned struct_wsdisplay_kbddata_sz; +extern unsigned struct_wsdisplay_msgattrs_sz; +extern unsigned struct_wsdisplay_param_sz; +extern unsigned struct_wsdisplay_scroll_data_sz; +extern unsigned struct_wsdisplay_usefontdata_sz; +extern unsigned struct_wsdisplayio_blit_sz; +extern unsigned struct_wsdisplayio_bus_id_sz; +extern unsigned struct_wsdisplayio_edid_info_sz; +extern unsigned struct_wsdisplayio_fbinfo_sz; +extern unsigned struct_wskbd_bell_data_sz; +extern unsigned struct_wskbd_keyrepeat_data_sz; +extern unsigned struct_wskbd_map_data_sz; +extern unsigned struct_wskbd_scroll_data_sz; +extern unsigned struct_wsmouse_calibcoords_sz; +extern unsigned struct_wsmouse_id_sz; +extern unsigned struct_wsmouse_repeat_sz; +extern unsigned struct_wsmux_device_list_sz; +extern unsigned struct_wsmux_device_sz; +extern unsigned struct_xd_iocmd_sz; + +extern unsigned struct_scsireq_sz; +extern unsigned struct_tone_sz; +extern unsigned union_twe_statrequest_sz; +extern unsigned struct_usb_device_descriptor_sz; +extern unsigned struct_vt_mode_sz; +extern unsigned struct__old_mixer_info_sz; +extern unsigned struct__agp_allocate_sz; +extern unsigned struct__agp_bind_sz; +extern unsigned struct__agp_info_sz; +extern unsigned struct__agp_setup_sz; +extern unsigned struct__agp_unbind_sz; +extern unsigned struct_atareq_sz; +extern unsigned struct_cpustate_sz; +extern unsigned struct_dmx_caps_sz; +extern unsigned enum_dmx_source_sz; +extern unsigned union_dvd_authinfo_sz; +extern unsigned union_dvd_struct_sz; +extern unsigned enum_v4l2_priority_sz; +extern unsigned struct_envsys_basic_info_sz; +extern unsigned struct_envsys_tre_data_sz; +extern unsigned enum_fe_sec_mini_cmd_sz; +extern unsigned enum_fe_sec_tone_mode_sz; +extern unsigned enum_fe_sec_voltage_sz; +extern unsigned enum_fe_status_sz; +extern unsigned struct_gdt_ctrt_sz; +extern unsigned struct_gdt_event_sz; +extern unsigned struct_gdt_osv_sz; +extern unsigned struct_gdt_rescan_sz; +extern unsigned struct_gdt_statist_sz; +extern unsigned struct_gdt_ucmd_sz; +extern unsigned struct_iscsi_conn_status_parameters_sz; +extern unsigned struct_iscsi_get_version_parameters_sz; +extern unsigned struct_iscsi_iocommand_parameters_sz; +extern unsigned struct_iscsi_login_parameters_sz; +extern unsigned struct_iscsi_logout_parameters_sz; +extern unsigned struct_iscsi_register_event_parameters_sz; +extern unsigned struct_iscsi_remove_parameters_sz; +extern unsigned struct_iscsi_send_targets_parameters_sz; +extern unsigned struct_iscsi_set_node_name_parameters_sz; +extern unsigned struct_iscsi_wait_event_parameters_sz; +extern unsigned struct_isp_stats_sz; +extern unsigned struct_lsenable_sz; +extern unsigned struct_lsdisable_sz; +extern unsigned struct_mixer_ctrl_sz; +extern unsigned struct_mixer_devinfo_sz; +extern unsigned struct_mpu_command_rec_sz; +extern unsigned struct_rndstat_sz; +extern unsigned struct_rndstat_name_sz; +extern unsigned struct_rndctl_sz; +extern unsigned struct_rnddata_sz; +extern unsigned struct_rndpoolstat_sz; +extern unsigned struct_rndstat_est_sz; +extern unsigned struct_rndstat_est_name_sz; +extern unsigned struct_pps_params_sz; +extern unsigned struct_pps_info_sz; +extern unsigned struct_mixer_info_sz; +extern unsigned struct_RF_SparetWait_sz; +extern unsigned struct_RF_ComponentLabel_sz; +extern unsigned struct_RF_SingleComponent_sz; +extern unsigned struct_RF_ProgressInfo_sz; -// ioctl request identifiers  // A special value to mark ioctls that are not present on the target platform,  // when it can not be determined without including any system headers.  extern const unsigned IOCTL_NOT_PRESENT; -extern unsigned IOCTL_FIOASYNC; + +extern unsigned IOCTL_AFM_ADDFMAP; +extern unsigned IOCTL_AFM_DELFMAP; +extern unsigned IOCTL_AFM_CLEANFMAP; +extern unsigned IOCTL_AFM_GETFMAP; +extern unsigned IOCTL_ALTQGTYPE; +extern unsigned IOCTL_ALTQTBRSET; +extern unsigned IOCTL_ALTQTBRGET; +extern unsigned IOCTL_BLUE_IF_ATTACH; +extern unsigned IOCTL_BLUE_IF_DETACH; +extern unsigned IOCTL_BLUE_ENABLE; +extern unsigned IOCTL_BLUE_DISABLE; +extern unsigned IOCTL_BLUE_CONFIG; +extern unsigned IOCTL_BLUE_GETSTATS; +extern unsigned IOCTL_CBQ_IF_ATTACH; +extern unsigned IOCTL_CBQ_IF_DETACH; +extern unsigned IOCTL_CBQ_ENABLE; +extern unsigned IOCTL_CBQ_DISABLE; +extern unsigned IOCTL_CBQ_CLEAR_HIERARCHY; +extern unsigned IOCTL_CBQ_ADD_CLASS; +extern unsigned IOCTL_CBQ_DEL_CLASS; +extern unsigned IOCTL_CBQ_MODIFY_CLASS; +extern unsigned IOCTL_CBQ_ADD_FILTER; +extern unsigned IOCTL_CBQ_DEL_FILTER; +extern unsigned IOCTL_CBQ_GETSTATS; +extern unsigned IOCTL_CDNR_IF_ATTACH; +extern unsigned IOCTL_CDNR_IF_DETACH; +extern unsigned IOCTL_CDNR_ENABLE; +extern unsigned IOCTL_CDNR_DISABLE; +extern unsigned IOCTL_CDNR_ADD_FILTER; +extern unsigned IOCTL_CDNR_DEL_FILTER; +extern unsigned IOCTL_CDNR_GETSTATS; +extern unsigned IOCTL_CDNR_ADD_ELEM; +extern unsigned IOCTL_CDNR_DEL_ELEM; +extern unsigned IOCTL_CDNR_ADD_TBM; +extern unsigned IOCTL_CDNR_MOD_TBM; +extern unsigned IOCTL_CDNR_TBM_STATS; +extern unsigned IOCTL_CDNR_ADD_TCM; +extern unsigned IOCTL_CDNR_MOD_TCM; +extern unsigned IOCTL_CDNR_TCM_STATS; +extern unsigned IOCTL_CDNR_ADD_TSW; +extern unsigned IOCTL_CDNR_MOD_TSW; +extern unsigned IOCTL_FIFOQ_IF_ATTACH; +extern unsigned IOCTL_FIFOQ_IF_DETACH; +extern unsigned IOCTL_FIFOQ_ENABLE; +extern unsigned IOCTL_FIFOQ_DISABLE; +extern unsigned IOCTL_FIFOQ_CONFIG; +extern unsigned IOCTL_FIFOQ_GETSTATS; +extern unsigned IOCTL_HFSC_IF_ATTACH; +extern unsigned IOCTL_HFSC_IF_DETACH; +extern unsigned IOCTL_HFSC_ENABLE; +extern unsigned IOCTL_HFSC_DISABLE; +extern unsigned IOCTL_HFSC_CLEAR_HIERARCHY; +extern unsigned IOCTL_HFSC_ADD_CLASS; +extern unsigned IOCTL_HFSC_DEL_CLASS; +extern unsigned IOCTL_HFSC_MOD_CLASS; +extern unsigned IOCTL_HFSC_ADD_FILTER; +extern unsigned IOCTL_HFSC_DEL_FILTER; +extern unsigned IOCTL_HFSC_GETSTATS; +extern unsigned IOCTL_JOBS_IF_ATTACH; +extern unsigned IOCTL_JOBS_IF_DETACH; +extern unsigned IOCTL_JOBS_ENABLE; +extern unsigned IOCTL_JOBS_DISABLE; +extern unsigned IOCTL_JOBS_CLEAR; +extern unsigned IOCTL_JOBS_ADD_CLASS; +extern unsigned IOCTL_JOBS_DEL_CLASS; +extern unsigned IOCTL_JOBS_MOD_CLASS; +extern unsigned IOCTL_JOBS_ADD_FILTER; +extern unsigned IOCTL_JOBS_DEL_FILTER; +extern unsigned IOCTL_JOBS_GETSTATS; +extern unsigned IOCTL_PRIQ_IF_ATTACH; +extern unsigned IOCTL_PRIQ_IF_DETACH; +extern unsigned IOCTL_PRIQ_ENABLE; +extern unsigned IOCTL_PRIQ_DISABLE; +extern unsigned IOCTL_PRIQ_CLEAR; +extern unsigned IOCTL_PRIQ_ADD_CLASS; +extern unsigned IOCTL_PRIQ_DEL_CLASS; +extern unsigned IOCTL_PRIQ_MOD_CLASS; +extern unsigned IOCTL_PRIQ_ADD_FILTER; +extern unsigned IOCTL_PRIQ_DEL_FILTER; +extern unsigned IOCTL_PRIQ_GETSTATS; +extern unsigned IOCTL_RED_IF_ATTACH; +extern unsigned IOCTL_RED_IF_DETACH; +extern unsigned IOCTL_RED_ENABLE; +extern unsigned IOCTL_RED_DISABLE; +extern unsigned IOCTL_RED_CONFIG; +extern unsigned IOCTL_RED_GETSTATS; +extern unsigned IOCTL_RED_SETDEFAULTS; +extern unsigned IOCTL_RIO_IF_ATTACH; +extern unsigned IOCTL_RIO_IF_DETACH; +extern unsigned IOCTL_RIO_ENABLE; +extern unsigned IOCTL_RIO_DISABLE; +extern unsigned IOCTL_RIO_CONFIG; +extern unsigned IOCTL_RIO_GETSTATS; +extern unsigned IOCTL_RIO_SETDEFAULTS; +extern unsigned IOCTL_WFQ_IF_ATTACH; +extern unsigned IOCTL_WFQ_IF_DETACH; +extern unsigned IOCTL_WFQ_ENABLE; +extern unsigned IOCTL_WFQ_DISABLE; +extern unsigned IOCTL_WFQ_CONFIG; +extern unsigned IOCTL_WFQ_GET_STATS; +extern unsigned IOCTL_WFQ_GET_QID; +extern unsigned IOCTL_WFQ_SET_WEIGHT; +extern unsigned IOCTL_CRIOGET; +extern unsigned IOCTL_CIOCFSESSION; +extern unsigned IOCTL_CIOCKEY; +extern unsigned IOCTL_CIOCNFKEYM; +extern unsigned IOCTL_CIOCNFSESSION; +extern unsigned IOCTL_CIOCNCRYPTRETM; +extern unsigned IOCTL_CIOCNCRYPTRET; +extern unsigned IOCTL_CIOCGSESSION; +extern unsigned IOCTL_CIOCNGSESSION; +extern unsigned IOCTL_CIOCCRYPT; +extern unsigned IOCTL_CIOCNCRYPTM; +extern unsigned IOCTL_CIOCASYMFEAT; +extern unsigned IOCTL_APM_IOC_REJECT; +extern unsigned IOCTL_APM_IOC_STANDBY; +extern unsigned IOCTL_APM_IOC_SUSPEND; +extern unsigned IOCTL_OAPM_IOC_GETPOWER; +extern unsigned IOCTL_APM_IOC_GETPOWER; +extern unsigned IOCTL_APM_IOC_NEXTEVENT; +extern unsigned IOCTL_APM_IOC_DEV_CTL; +extern unsigned IOCTL_NETBSD_DM_IOCTL; +extern unsigned IOCTL_DMIO_SETFUNC; +extern unsigned IOCTL_DMX_START; +extern unsigned IOCTL_DMX_STOP; +extern unsigned IOCTL_DMX_SET_FILTER; +extern unsigned IOCTL_DMX_SET_PES_FILTER; +extern unsigned IOCTL_DMX_SET_BUFFER_SIZE; +extern unsigned IOCTL_DMX_GET_STC; +extern unsigned IOCTL_DMX_ADD_PID; +extern unsigned IOCTL_DMX_REMOVE_PID; +extern unsigned IOCTL_DMX_GET_CAPS; +extern unsigned IOCTL_DMX_SET_SOURCE; +extern unsigned IOCTL_FE_READ_STATUS; +extern unsigned IOCTL_FE_READ_BER; +extern unsigned IOCTL_FE_READ_SNR; +extern unsigned IOCTL_FE_READ_SIGNAL_STRENGTH; +extern unsigned IOCTL_FE_READ_UNCORRECTED_BLOCKS; +extern unsigned IOCTL_FE_SET_FRONTEND; +extern unsigned IOCTL_FE_GET_FRONTEND; +extern unsigned IOCTL_FE_GET_EVENT; +extern unsigned IOCTL_FE_GET_INFO; +extern unsigned IOCTL_FE_DISEQC_RESET_OVERLOAD; +extern unsigned IOCTL_FE_DISEQC_SEND_MASTER_CMD; +extern unsigned IOCTL_FE_DISEQC_RECV_SLAVE_REPLY; +extern unsigned IOCTL_FE_DISEQC_SEND_BURST; +extern unsigned IOCTL_FE_SET_TONE; +extern unsigned IOCTL_FE_SET_VOLTAGE; +extern unsigned IOCTL_FE_ENABLE_HIGH_LNB_VOLTAGE; +extern unsigned IOCTL_FE_SET_FRONTEND_TUNE_MODE; +extern unsigned IOCTL_FE_DISHNETWORK_SEND_LEGACY_CMD; +extern unsigned IOCTL_FILEMON_SET_FD; +extern unsigned IOCTL_FILEMON_SET_PID; +extern unsigned IOCTL_HDAUDIO_FGRP_INFO; +extern unsigned IOCTL_HDAUDIO_FGRP_GETCONFIG; +extern unsigned IOCTL_HDAUDIO_FGRP_SETCONFIG; +extern unsigned IOCTL_HDAUDIO_FGRP_WIDGET_INFO; +extern unsigned IOCTL_HDAUDIO_FGRP_CODEC_INFO; +extern unsigned IOCTL_HDAUDIO_AFG_WIDGET_INFO; +extern unsigned IOCTL_HDAUDIO_AFG_CODEC_INFO; +extern unsigned IOCTL_CEC_GET_PHYS_ADDR; +extern unsigned IOCTL_CEC_GET_LOG_ADDRS; +extern unsigned IOCTL_CEC_SET_LOG_ADDRS; +extern unsigned IOCTL_CEC_GET_VENDOR_ID; +extern unsigned IOCTL_HPCFBIO_GCONF; +extern unsigned IOCTL_HPCFBIO_SCONF; +extern unsigned IOCTL_HPCFBIO_GDSPCONF; +extern unsigned IOCTL_HPCFBIO_SDSPCONF; +extern unsigned IOCTL_HPCFBIO_GOP; +extern unsigned IOCTL_HPCFBIO_SOP; +extern unsigned IOCTL_IOPIOCPT; +extern unsigned IOCTL_IOPIOCGLCT; +extern unsigned IOCTL_IOPIOCGSTATUS; +extern unsigned IOCTL_IOPIOCRECONFIG; +extern unsigned IOCTL_IOPIOCGTIDMAP; +extern unsigned IOCTL_SIOCGATHSTATS; +extern unsigned IOCTL_SIOCGATHDIAG; +extern unsigned IOCTL_METEORCAPTUR; +extern unsigned IOCTL_METEORCAPFRM; +extern unsigned IOCTL_METEORSETGEO; +extern unsigned IOCTL_METEORGETGEO; +extern unsigned IOCTL_METEORSTATUS; +extern unsigned IOCTL_METEORSHUE; +extern unsigned IOCTL_METEORGHUE; +extern unsigned IOCTL_METEORSFMT; +extern unsigned IOCTL_METEORGFMT; +extern unsigned IOCTL_METEORSINPUT; +extern unsigned IOCTL_METEORGINPUT; +extern unsigned IOCTL_METEORSCHCV; +extern unsigned IOCTL_METEORGCHCV; +extern unsigned IOCTL_METEORSCOUNT; +extern unsigned IOCTL_METEORGCOUNT; +extern unsigned IOCTL_METEORSFPS; +extern unsigned IOCTL_METEORGFPS; +extern unsigned IOCTL_METEORSSIGNAL; +extern unsigned IOCTL_METEORGSIGNAL; +extern unsigned IOCTL_METEORSVIDEO; +extern unsigned IOCTL_METEORGVIDEO; +extern unsigned IOCTL_METEORSBRIG; +extern unsigned IOCTL_METEORGBRIG; +extern unsigned IOCTL_METEORSCSAT; +extern unsigned IOCTL_METEORGCSAT; +extern unsigned IOCTL_METEORSCONT; +extern unsigned IOCTL_METEORGCONT; +extern unsigned IOCTL_METEORSHWS; +extern unsigned IOCTL_METEORGHWS; +extern unsigned IOCTL_METEORSVWS; +extern unsigned IOCTL_METEORGVWS; +extern unsigned IOCTL_METEORSTS; +extern unsigned IOCTL_METEORGTS; +extern unsigned IOCTL_TVTUNER_SETCHNL; +extern unsigned IOCTL_TVTUNER_GETCHNL; +extern unsigned IOCTL_TVTUNER_SETTYPE; +extern unsigned IOCTL_TVTUNER_GETTYPE; +extern unsigned IOCTL_TVTUNER_GETSTATUS; +extern unsigned IOCTL_TVTUNER_SETFREQ; +extern unsigned IOCTL_TVTUNER_GETFREQ; +extern unsigned IOCTL_TVTUNER_SETAFC; +extern unsigned IOCTL_TVTUNER_GETAFC; +extern unsigned IOCTL_RADIO_SETMODE; +extern unsigned IOCTL_RADIO_GETMODE; +extern unsigned IOCTL_RADIO_SETFREQ; +extern unsigned IOCTL_RADIO_GETFREQ; +extern unsigned IOCTL_METEORSACTPIXFMT; +extern unsigned IOCTL_METEORGACTPIXFMT; +extern unsigned IOCTL_METEORGSUPPIXFMT; +extern unsigned IOCTL_TVTUNER_GETCHNLSET; +extern unsigned IOCTL_REMOTE_GETKEY; +extern unsigned IOCTL_GDT_IOCTL_GENERAL; +extern unsigned IOCTL_GDT_IOCTL_DRVERS; +extern unsigned IOCTL_GDT_IOCTL_CTRTYPE; +extern unsigned IOCTL_GDT_IOCTL_OSVERS; +extern unsigned IOCTL_GDT_IOCTL_CTRCNT; +extern unsigned IOCTL_GDT_IOCTL_EVENT; +extern unsigned IOCTL_GDT_IOCTL_STATIST; +extern unsigned IOCTL_GDT_IOCTL_RESCAN; +extern unsigned IOCTL_ISP_SDBLEV; +extern unsigned IOCTL_ISP_RESETHBA; +extern unsigned IOCTL_ISP_RESCAN; +extern unsigned IOCTL_ISP_SETROLE; +extern unsigned IOCTL_ISP_GETROLE; +extern unsigned IOCTL_ISP_GET_STATS; +extern unsigned IOCTL_ISP_CLR_STATS; +extern unsigned IOCTL_ISP_FC_LIP; +extern unsigned IOCTL_ISP_FC_GETDINFO; +extern unsigned IOCTL_ISP_GET_FW_CRASH_DUMP; +extern unsigned IOCTL_ISP_FORCE_CRASH_DUMP; +extern unsigned IOCTL_ISP_FC_GETHINFO; +extern unsigned IOCTL_ISP_TSK_MGMT; +extern unsigned IOCTL_ISP_FC_GETDLIST; +extern unsigned IOCTL_MLXD_STATUS; +extern unsigned IOCTL_MLXD_CHECKASYNC; +extern unsigned IOCTL_MLXD_DETACH; +extern unsigned IOCTL_MLX_RESCAN_DRIVES; +extern unsigned IOCTL_MLX_PAUSE_CHANNEL; +extern unsigned IOCTL_MLX_COMMAND; +extern unsigned IOCTL_MLX_REBUILDASYNC; +extern unsigned IOCTL_MLX_REBUILDSTAT; +extern unsigned IOCTL_MLX_GET_SYSDRIVE; +extern unsigned IOCTL_MLX_GET_CINFO; +extern unsigned IOCTL_NVME_PASSTHROUGH_CMD; +extern unsigned IOCTL_IRDA_RESET_PARAMS; +extern unsigned IOCTL_IRDA_SET_PARAMS; +extern unsigned IOCTL_IRDA_GET_SPEEDMASK; +extern unsigned IOCTL_IRDA_GET_TURNAROUNDMASK; +extern unsigned IOCTL_IRFRAMETTY_GET_DEVICE; +extern unsigned IOCTL_IRFRAMETTY_GET_DONGLE; +extern unsigned IOCTL_IRFRAMETTY_SET_DONGLE; +extern unsigned IOCTL_SATIORESET; +extern unsigned IOCTL_SATIOGID; +extern unsigned IOCTL_SATIOSBUFSIZE; +extern unsigned IOCTL_ISV_CMD; +extern unsigned IOCTL_WTQICMD; +extern unsigned IOCTL_ISCSI_GET_VERSION; +extern unsigned IOCTL_ISCSI_LOGIN; +extern unsigned IOCTL_ISCSI_LOGOUT; +extern unsigned IOCTL_ISCSI_ADD_CONNECTION; +extern unsigned IOCTL_ISCSI_RESTORE_CONNECTION; +extern unsigned IOCTL_ISCSI_REMOVE_CONNECTION; +extern unsigned IOCTL_ISCSI_CONNECTION_STATUS; +extern unsigned IOCTL_ISCSI_SEND_TARGETS; +extern unsigned IOCTL_ISCSI_SET_NODE_NAME; +extern unsigned IOCTL_ISCSI_IO_COMMAND; +extern unsigned IOCTL_ISCSI_REGISTER_EVENT; +extern unsigned IOCTL_ISCSI_DEREGISTER_EVENT; +extern unsigned IOCTL_ISCSI_WAIT_EVENT; +extern unsigned IOCTL_ISCSI_POLL_EVENT; +extern unsigned IOCTL_OFIOCGET; +extern unsigned IOCTL_OFIOCSET; +extern unsigned IOCTL_OFIOCNEXTPROP; +extern unsigned IOCTL_OFIOCGETOPTNODE; +extern unsigned IOCTL_OFIOCGETNEXT; +extern unsigned IOCTL_OFIOCGETCHILD; +extern unsigned IOCTL_OFIOCFINDDEVICE; +extern unsigned IOCTL_AMR_IO_VERSION; +extern unsigned IOCTL_AMR_IO_COMMAND; +extern unsigned IOCTL_MLYIO_COMMAND; +extern unsigned IOCTL_MLYIO_HEALTH; +extern unsigned IOCTL_PCI_IOC_CFGREAD; +extern unsigned IOCTL_PCI_IOC_CFGWRITE; +extern unsigned IOCTL_PCI_IOC_BDF_CFGREAD; +extern unsigned IOCTL_PCI_IOC_BDF_CFGWRITE; +extern unsigned IOCTL_PCI_IOC_BUSINFO; +extern unsigned IOCTL_PCI_IOC_DRVNAME; +extern unsigned IOCTL_PCI_IOC_DRVNAMEONBUS; +extern unsigned IOCTL_TWEIO_COMMAND; +extern unsigned IOCTL_TWEIO_STATS; +extern unsigned IOCTL_TWEIO_AEN_POLL; +extern unsigned IOCTL_TWEIO_AEN_WAIT; +extern unsigned IOCTL_TWEIO_SET_PARAM; +extern unsigned IOCTL_TWEIO_GET_PARAM; +extern unsigned IOCTL_TWEIO_RESET; +extern unsigned IOCTL_TWEIO_ADD_UNIT; +extern unsigned IOCTL_TWEIO_DEL_UNIT; +extern unsigned IOCTL_SIOCSCNWDOMAIN; +extern unsigned IOCTL_SIOCGCNWDOMAIN; +extern unsigned IOCTL_SIOCSCNWKEY; +extern unsigned IOCTL_SIOCGCNWSTATUS; +extern unsigned IOCTL_SIOCGCNWSTATS; +extern unsigned IOCTL_SIOCGCNWTRAIL; +extern unsigned IOCTL_SIOCGRAYSIGLEV; +extern unsigned IOCTL_RAIDFRAME_SHUTDOWN; +extern unsigned IOCTL_RAIDFRAME_TUR; +extern unsigned IOCTL_RAIDFRAME_FAIL_DISK; +extern unsigned IOCTL_RAIDFRAME_CHECK_RECON_STATUS; +extern unsigned IOCTL_RAIDFRAME_REWRITEPARITY; +extern unsigned IOCTL_RAIDFRAME_COPYBACK; +extern unsigned IOCTL_RAIDFRAME_SPARET_WAIT; +extern unsigned IOCTL_RAIDFRAME_SEND_SPARET; +extern unsigned IOCTL_RAIDFRAME_ABORT_SPARET_WAIT; +extern unsigned IOCTL_RAIDFRAME_START_ATRACE; +extern unsigned IOCTL_RAIDFRAME_STOP_ATRACE; +extern unsigned IOCTL_RAIDFRAME_GET_SIZE; +extern unsigned IOCTL_RAIDFRAME_RESET_ACCTOTALS; +extern unsigned IOCTL_RAIDFRAME_KEEP_ACCTOTALS; +extern unsigned IOCTL_RAIDFRAME_GET_COMPONENT_LABEL; +extern unsigned IOCTL_RAIDFRAME_SET_COMPONENT_LABEL; +extern unsigned IOCTL_RAIDFRAME_INIT_LABELS; +extern unsigned IOCTL_RAIDFRAME_ADD_HOT_SPARE; +extern unsigned IOCTL_RAIDFRAME_REMOVE_HOT_SPARE; +extern unsigned IOCTL_RAIDFRAME_REBUILD_IN_PLACE; +extern unsigned IOCTL_RAIDFRAME_CHECK_PARITY; +extern unsigned IOCTL_RAIDFRAME_CHECK_PARITYREWRITE_STATUS; +extern unsigned IOCTL_RAIDFRAME_CHECK_COPYBACK_STATUS; +extern unsigned IOCTL_RAIDFRAME_SET_AUTOCONFIG; +extern unsigned IOCTL_RAIDFRAME_SET_ROOT; +extern unsigned IOCTL_RAIDFRAME_DELETE_COMPONENT; +extern unsigned IOCTL_RAIDFRAME_INCORPORATE_HOT_SPARE; +extern unsigned IOCTL_RAIDFRAME_CHECK_RECON_STATUS_EXT; +extern unsigned IOCTL_RAIDFRAME_CHECK_PARITYREWRITE_STATUS_EXT; +extern unsigned IOCTL_RAIDFRAME_CHECK_COPYBACK_STATUS_EXT; +extern unsigned IOCTL_RAIDFRAME_CONFIGURE; +extern unsigned IOCTL_RAIDFRAME_GET_INFO; +extern unsigned IOCTL_RAIDFRAME_PARITYMAP_STATUS; +extern unsigned IOCTL_RAIDFRAME_PARITYMAP_GET_DISABLE; +extern unsigned IOCTL_RAIDFRAME_PARITYMAP_SET_DISABLE; +extern unsigned IOCTL_RAIDFRAME_PARITYMAP_SET_PARAMS; +extern unsigned IOCTL_RAIDFRAME_SET_LAST_UNIT; +extern unsigned IOCTL_MBPPIOCSPARAM; +extern unsigned IOCTL_MBPPIOCGPARAM; +extern unsigned IOCTL_MBPPIOCGSTAT; +extern unsigned IOCTL_SESIOC_GETNOBJ; +extern unsigned IOCTL_SESIOC_GETOBJMAP; +extern unsigned IOCTL_SESIOC_GETENCSTAT; +extern unsigned IOCTL_SESIOC_SETENCSTAT; +extern unsigned IOCTL_SESIOC_GETOBJSTAT; +extern unsigned IOCTL_SESIOC_SETOBJSTAT; +extern unsigned IOCTL_SESIOC_GETTEXT; +extern unsigned IOCTL_SESIOC_INIT; +extern unsigned IOCTL_SUN_DKIOCGGEOM; +extern unsigned IOCTL_SUN_DKIOCINFO; +extern unsigned IOCTL_SUN_DKIOCGPART; +extern unsigned IOCTL_FBIOGTYPE; +extern unsigned IOCTL_FBIOPUTCMAP; +extern unsigned IOCTL_FBIOGETCMAP; +extern unsigned IOCTL_FBIOGATTR; +extern unsigned IOCTL_FBIOSVIDEO; +extern unsigned IOCTL_FBIOGVIDEO; +extern unsigned IOCTL_FBIOSCURSOR; +extern unsigned IOCTL_FBIOGCURSOR; +extern unsigned IOCTL_FBIOSCURPOS; +extern unsigned IOCTL_FBIOGCURPOS; +extern unsigned IOCTL_FBIOGCURMAX; +extern unsigned IOCTL_KIOCTRANS; +extern unsigned IOCTL_KIOCSETKEY; +extern unsigned IOCTL_KIOCGETKEY; +extern unsigned IOCTL_KIOCGTRANS; +extern unsigned IOCTL_KIOCCMD; +extern unsigned IOCTL_KIOCTYPE; +extern unsigned IOCTL_KIOCSDIRECT; +extern unsigned IOCTL_KIOCSKEY; +extern unsigned IOCTL_KIOCGKEY; +extern unsigned IOCTL_KIOCSLED; +extern unsigned IOCTL_KIOCGLED; +extern unsigned IOCTL_KIOCLAYOUT; +extern unsigned IOCTL_VUIDSFORMAT; +extern unsigned IOCTL_VUIDGFORMAT; +extern unsigned IOCTL_STICIO_GXINFO; +extern unsigned IOCTL_STICIO_RESET; +extern unsigned IOCTL_STICIO_STARTQ; +extern unsigned IOCTL_STICIO_STOPQ; +extern unsigned IOCTL_UKYOPON_IDENTIFY; +extern unsigned IOCTL_URIO_SEND_COMMAND; +extern unsigned IOCTL_URIO_RECV_COMMAND; +extern unsigned IOCTL_USB_REQUEST; +extern unsigned IOCTL_USB_SETDEBUG; +extern unsigned IOCTL_USB_DISCOVER; +extern unsigned IOCTL_USB_DEVICEINFO; +extern unsigned IOCTL_USB_DEVICEINFO_OLD; +extern unsigned IOCTL_USB_DEVICESTATS; +extern unsigned IOCTL_USB_GET_REPORT_DESC; +extern unsigned IOCTL_USB_SET_IMMED; +extern unsigned IOCTL_USB_GET_REPORT; +extern unsigned IOCTL_USB_SET_REPORT; +extern unsigned IOCTL_USB_GET_REPORT_ID; +extern unsigned IOCTL_USB_GET_CONFIG; +extern unsigned IOCTL_USB_SET_CONFIG; +extern unsigned IOCTL_USB_GET_ALTINTERFACE; +extern unsigned IOCTL_USB_SET_ALTINTERFACE; +extern unsigned IOCTL_USB_GET_NO_ALT; +extern unsigned IOCTL_USB_GET_DEVICE_DESC; +extern unsigned IOCTL_USB_GET_CONFIG_DESC; +extern unsigned IOCTL_USB_GET_INTERFACE_DESC; +extern unsigned IOCTL_USB_GET_ENDPOINT_DESC; +extern unsigned IOCTL_USB_GET_FULL_DESC; +extern unsigned IOCTL_USB_GET_STRING_DESC; +extern unsigned IOCTL_USB_DO_REQUEST; +extern unsigned IOCTL_USB_GET_DEVICEINFO; +extern unsigned IOCTL_USB_GET_DEVICEINFO_OLD; +extern unsigned IOCTL_USB_SET_SHORT_XFER; +extern unsigned IOCTL_USB_SET_TIMEOUT; +extern unsigned IOCTL_USB_SET_BULK_RA; +extern unsigned IOCTL_USB_SET_BULK_WB; +extern unsigned IOCTL_USB_SET_BULK_RA_OPT; +extern unsigned IOCTL_USB_SET_BULK_WB_OPT; +extern unsigned IOCTL_USB_GET_CM_OVER_DATA; +extern unsigned IOCTL_USB_SET_CM_OVER_DATA; +extern unsigned IOCTL_UTOPPYIOTURBO; +extern unsigned IOCTL_UTOPPYIOCANCEL; +extern unsigned IOCTL_UTOPPYIOREBOOT; +extern unsigned IOCTL_UTOPPYIOSTATS; +extern unsigned IOCTL_UTOPPYIORENAME; +extern unsigned IOCTL_UTOPPYIOMKDIR; +extern unsigned IOCTL_UTOPPYIODELETE; +extern unsigned IOCTL_UTOPPYIOREADDIR; +extern unsigned IOCTL_UTOPPYIOREADFILE; +extern unsigned IOCTL_UTOPPYIOWRITEFILE; +extern unsigned IOCTL_DIOSXDCMD; +extern unsigned IOCTL_VT_OPENQRY; +extern unsigned IOCTL_VT_SETMODE; +extern unsigned IOCTL_VT_GETMODE; +extern unsigned IOCTL_VT_RELDISP; +extern unsigned IOCTL_VT_ACTIVATE; +extern unsigned IOCTL_VT_WAITACTIVE; +extern unsigned IOCTL_VT_GETACTIVE; +extern unsigned IOCTL_VT_GETSTATE; +extern unsigned IOCTL_KDGETKBENT; +extern unsigned IOCTL_KDGKBMODE; +extern unsigned IOCTL_KDSKBMODE; +extern unsigned IOCTL_KDMKTONE; +extern unsigned IOCTL_KDSETMODE; +extern unsigned IOCTL_KDENABIO; +extern unsigned IOCTL_KDDISABIO; +extern unsigned IOCTL_KDGKBTYPE; +extern unsigned IOCTL_KDGETLED; +extern unsigned IOCTL_KDSETLED; +extern unsigned IOCTL_KDSETRAD; +extern unsigned IOCTL_VGAPCVTID; +extern unsigned IOCTL_CONS_GETVERS; +extern unsigned IOCTL_WSKBDIO_GTYPE; +extern unsigned IOCTL_WSKBDIO_BELL; +extern unsigned IOCTL_WSKBDIO_COMPLEXBELL; +extern unsigned IOCTL_WSKBDIO_SETBELL; +extern unsigned IOCTL_WSKBDIO_GETBELL; +extern unsigned IOCTL_WSKBDIO_SETDEFAULTBELL; +extern unsigned IOCTL_WSKBDIO_GETDEFAULTBELL; +extern unsigned IOCTL_WSKBDIO_SETKEYREPEAT; +extern unsigned IOCTL_WSKBDIO_GETKEYREPEAT; +extern unsigned IOCTL_WSKBDIO_SETDEFAULTKEYREPEAT; +extern unsigned IOCTL_WSKBDIO_GETDEFAULTKEYREPEAT; +extern unsigned IOCTL_WSKBDIO_SETLEDS; +extern unsigned IOCTL_WSKBDIO_GETLEDS; +extern unsigned IOCTL_WSKBDIO_GETMAP; +extern unsigned IOCTL_WSKBDIO_SETMAP; +extern unsigned IOCTL_WSKBDIO_GETENCODING; +extern unsigned IOCTL_WSKBDIO_SETENCODING; +extern unsigned IOCTL_WSKBDIO_SETMODE; +extern unsigned IOCTL_WSKBDIO_GETMODE; +extern unsigned IOCTL_WSKBDIO_SETKEYCLICK; +extern unsigned IOCTL_WSKBDIO_GETKEYCLICK; +extern unsigned IOCTL_WSKBDIO_GETSCROLL; +extern unsigned IOCTL_WSKBDIO_SETSCROLL; +extern unsigned IOCTL_WSKBDIO_SETVERSION; +extern unsigned IOCTL_WSMOUSEIO_GTYPE; +extern unsigned IOCTL_WSMOUSEIO_SRES; +extern unsigned IOCTL_WSMOUSEIO_SSCALE; +extern unsigned IOCTL_WSMOUSEIO_SRATE; +extern unsigned IOCTL_WSMOUSEIO_SCALIBCOORDS; +extern unsigned IOCTL_WSMOUSEIO_GCALIBCOORDS; +extern unsigned IOCTL_WSMOUSEIO_GETID; +extern unsigned IOCTL_WSMOUSEIO_GETREPEAT; +extern unsigned IOCTL_WSMOUSEIO_SETREPEAT; +extern unsigned IOCTL_WSMOUSEIO_SETVERSION; +extern unsigned IOCTL_WSDISPLAYIO_GTYPE; +extern unsigned IOCTL_WSDISPLAYIO_GINFO; +extern unsigned IOCTL_WSDISPLAYIO_GETCMAP; +extern unsigned IOCTL_WSDISPLAYIO_PUTCMAP; +extern unsigned IOCTL_WSDISPLAYIO_GVIDEO; +extern unsigned IOCTL_WSDISPLAYIO_SVIDEO; +extern unsigned IOCTL_WSDISPLAYIO_GCURPOS; +extern unsigned IOCTL_WSDISPLAYIO_SCURPOS; +extern unsigned IOCTL_WSDISPLAYIO_GCURMAX; +extern unsigned IOCTL_WSDISPLAYIO_GCURSOR; +extern unsigned IOCTL_WSDISPLAYIO_SCURSOR; +extern unsigned IOCTL_WSDISPLAYIO_GMODE; +extern unsigned IOCTL_WSDISPLAYIO_SMODE; +extern unsigned IOCTL_WSDISPLAYIO_LDFONT; +extern unsigned IOCTL_WSDISPLAYIO_ADDSCREEN; +extern unsigned IOCTL_WSDISPLAYIO_DELSCREEN; +extern unsigned IOCTL_WSDISPLAYIO_SFONT; +extern unsigned IOCTL__O_WSDISPLAYIO_SETKEYBOARD; +extern unsigned IOCTL_WSDISPLAYIO_GETPARAM; +extern unsigned IOCTL_WSDISPLAYIO_SETPARAM; +extern unsigned IOCTL_WSDISPLAYIO_GETACTIVESCREEN; +extern unsigned IOCTL_WSDISPLAYIO_GETWSCHAR; +extern unsigned IOCTL_WSDISPLAYIO_PUTWSCHAR; +extern unsigned IOCTL_WSDISPLAYIO_DGSCROLL; +extern unsigned IOCTL_WSDISPLAYIO_DSSCROLL; +extern unsigned IOCTL_WSDISPLAYIO_GMSGATTRS; +extern unsigned IOCTL_WSDISPLAYIO_SMSGATTRS; +extern unsigned IOCTL_WSDISPLAYIO_GBORDER; +extern unsigned IOCTL_WSDISPLAYIO_SBORDER; +extern unsigned IOCTL_WSDISPLAYIO_SSPLASH; +extern unsigned IOCTL_WSDISPLAYIO_SPROGRESS; +extern unsigned IOCTL_WSDISPLAYIO_LINEBYTES; +extern unsigned IOCTL_WSDISPLAYIO_SETVERSION; +extern unsigned IOCTL_WSMUXIO_ADD_DEVICE; +extern unsigned IOCTL_WSMUXIO_REMOVE_DEVICE; +extern unsigned IOCTL_WSMUXIO_LIST_DEVICES; +extern unsigned IOCTL_WSMUXIO_INJECTEVENT; +extern unsigned IOCTL_WSDISPLAYIO_GET_BUSID; +extern unsigned IOCTL_WSDISPLAYIO_GET_EDID; +extern unsigned IOCTL_WSDISPLAYIO_SET_POLLING; +extern unsigned IOCTL_WSDISPLAYIO_GET_FBINFO; +extern unsigned IOCTL_WSDISPLAYIO_DOBLIT; +extern unsigned IOCTL_WSDISPLAYIO_WAITBLIT; +extern unsigned IOCTL_BIOCLOCATE; +extern unsigned IOCTL_BIOCINQ; +extern unsigned IOCTL_BIOCDISK_NOVOL; +extern unsigned IOCTL_BIOCDISK; +extern unsigned IOCTL_BIOCVOL; +extern unsigned IOCTL_BIOCALARM; +extern unsigned IOCTL_BIOCBLINK; +extern unsigned IOCTL_BIOCSETSTATE; +extern unsigned IOCTL_BIOCVOLOPS; +extern unsigned IOCTL_MD_GETCONF; +extern unsigned IOCTL_MD_SETCONF; +extern unsigned IOCTL_CCDIOCSET; +extern unsigned IOCTL_CCDIOCCLR; +extern unsigned IOCTL_CGDIOCSET; +extern unsigned IOCTL_CGDIOCCLR; +extern unsigned IOCTL_CGDIOCGET; +extern unsigned IOCTL_FSSIOCSET; +extern unsigned IOCTL_FSSIOCGET; +extern unsigned IOCTL_FSSIOCCLR; +extern unsigned IOCTL_FSSIOFSET; +extern unsigned IOCTL_FSSIOFGET; +extern unsigned IOCTL_BTDEV_ATTACH; +extern unsigned IOCTL_BTDEV_DETACH; +extern unsigned IOCTL_BTSCO_GETINFO; +extern unsigned IOCTL_KTTCP_IO_SEND; +extern unsigned IOCTL_KTTCP_IO_RECV; +extern unsigned IOCTL_IOC_LOCKSTAT_GVERSION; +extern unsigned IOCTL_IOC_LOCKSTAT_ENABLE; +extern unsigned IOCTL_IOC_LOCKSTAT_DISABLE; +extern unsigned IOCTL_VNDIOCSET; +extern unsigned IOCTL_VNDIOCCLR; +extern unsigned IOCTL_VNDIOCGET; +extern unsigned IOCTL_SPKRTONE; +extern unsigned IOCTL_SPKRTUNE; +extern unsigned IOCTL_SPKRGETVOL; +extern unsigned IOCTL_SPKRSETVOL; +extern unsigned IOCTL_BIOCGBLEN; +extern unsigned IOCTL_BIOCSBLEN; +extern unsigned IOCTL_BIOCSETF; +extern unsigned IOCTL_BIOCFLUSH; +extern unsigned IOCTL_BIOCPROMISC; +extern unsigned IOCTL_BIOCGDLT; +extern unsigned IOCTL_BIOCGETIF; +extern unsigned IOCTL_BIOCSETIF; +extern unsigned IOCTL_BIOCGSTATS; +extern unsigned IOCTL_BIOCGSTATSOLD; +extern unsigned IOCTL_BIOCIMMEDIATE; +extern unsigned IOCTL_BIOCVERSION; +extern unsigned IOCTL_BIOCSTCPF; +extern unsigned IOCTL_BIOCSUDPF; +extern unsigned IOCTL_BIOCGHDRCMPLT; +extern unsigned IOCTL_BIOCSHDRCMPLT; +extern unsigned IOCTL_BIOCSDLT; +extern unsigned IOCTL_BIOCGDLTLIST; +extern unsigned IOCTL_BIOCGSEESENT; +extern unsigned IOCTL_BIOCSSEESENT; +extern unsigned IOCTL_BIOCSRTIMEOUT; +extern unsigned IOCTL_BIOCGRTIMEOUT; +extern unsigned IOCTL_BIOCGFEEDBACK; +extern unsigned IOCTL_BIOCSFEEDBACK; +extern unsigned IOCTL_SIOCRAWATM; +extern unsigned IOCTL_SIOCATMENA; +extern unsigned IOCTL_SIOCATMDIS; +extern unsigned IOCTL_SIOCSPVCTX; +extern unsigned IOCTL_SIOCGPVCTX; +extern unsigned IOCTL_SIOCSPVCSIF; +extern unsigned IOCTL_SIOCGPVCSIF; +extern unsigned IOCTL_GRESADDRS; +extern unsigned IOCTL_GRESADDRD; +extern unsigned IOCTL_GREGADDRS; +extern unsigned IOCTL_GREGADDRD; +extern unsigned IOCTL_GRESPROTO; +extern unsigned IOCTL_GREGPROTO; +extern unsigned IOCTL_GRESSOCK; +extern unsigned IOCTL_GREDSOCK; +extern unsigned IOCTL_PPPIOCGRAWIN; +extern unsigned IOCTL_PPPIOCGFLAGS; +extern unsigned IOCTL_PPPIOCSFLAGS; +extern unsigned IOCTL_PPPIOCGASYNCMAP; +extern unsigned IOCTL_PPPIOCSASYNCMAP; +extern unsigned IOCTL_PPPIOCGUNIT; +extern unsigned IOCTL_PPPIOCGRASYNCMAP; +extern unsigned IOCTL_PPPIOCSRASYNCMAP; +extern unsigned IOCTL_PPPIOCGMRU; +extern unsigned IOCTL_PPPIOCSMRU; +extern unsigned IOCTL_PPPIOCSMAXCID; +extern unsigned IOCTL_PPPIOCGXASYNCMAP; +extern unsigned IOCTL_PPPIOCSXASYNCMAP; +extern unsigned IOCTL_PPPIOCXFERUNIT; +extern unsigned IOCTL_PPPIOCSCOMPRESS; +extern unsigned IOCTL_PPPIOCGNPMODE; +extern unsigned IOCTL_PPPIOCSNPMODE; +extern unsigned IOCTL_PPPIOCGIDLE; +extern unsigned IOCTL_PPPIOCGMTU; +extern unsigned IOCTL_PPPIOCSMTU; +extern unsigned IOCTL_SIOCGPPPSTATS; +extern unsigned IOCTL_SIOCGPPPCSTATS; +extern unsigned IOCTL_IOC_NPF_VERSION; +extern unsigned IOCTL_IOC_NPF_SWITCH; +extern unsigned IOCTL_IOC_NPF_LOAD; +extern unsigned IOCTL_IOC_NPF_TABLE; +extern unsigned IOCTL_IOC_NPF_STATS; +extern unsigned IOCTL_IOC_NPF_SAVE; +extern unsigned IOCTL_IOC_NPF_RULE; +extern unsigned IOCTL_IOC_NPF_CONN_LOOKUP; +extern unsigned IOCTL_PPPOESETPARMS; +extern unsigned IOCTL_PPPOEGETPARMS; +extern unsigned IOCTL_PPPOEGETSESSION; +extern unsigned IOCTL_SPPPGETAUTHCFG; +extern unsigned IOCTL_SPPPSETAUTHCFG; +extern unsigned IOCTL_SPPPGETLCPCFG; +extern unsigned IOCTL_SPPPSETLCPCFG; +extern unsigned IOCTL_SPPPGETSTATUS; +extern unsigned IOCTL_SPPPGETSTATUSNCP; +extern unsigned IOCTL_SPPPGETIDLETO; +extern unsigned IOCTL_SPPPSETIDLETO; +extern unsigned IOCTL_SPPPGETAUTHFAILURES; +extern unsigned IOCTL_SPPPSETAUTHFAILURE; +extern unsigned IOCTL_SPPPSETDNSOPTS; +extern unsigned IOCTL_SPPPGETDNSOPTS; +extern unsigned IOCTL_SPPPGETDNSADDRS; +extern unsigned IOCTL_SPPPSETKEEPALIVE; +extern unsigned IOCTL_SPPPGETKEEPALIVE; +extern unsigned IOCTL_SRT_GETNRT; +extern unsigned IOCTL_SRT_GETRT; +extern unsigned IOCTL_SRT_SETRT; +extern unsigned IOCTL_SRT_DELRT; +extern unsigned IOCTL_SRT_SFLAGS; +extern unsigned IOCTL_SRT_GFLAGS; +extern unsigned IOCTL_SRT_SGFLAGS; +extern unsigned IOCTL_SRT_DEBUG; +extern unsigned IOCTL_TAPGIFNAME; +extern unsigned IOCTL_TUNSDEBUG; +extern unsigned IOCTL_TUNGDEBUG; +extern unsigned IOCTL_TUNSIFMODE; +extern unsigned IOCTL_TUNSLMODE; +extern unsigned IOCTL_TUNSIFHEAD; +extern unsigned IOCTL_TUNGIFHEAD; +extern unsigned IOCTL_DIOCSTART; +extern unsigned IOCTL_DIOCSTOP; +extern unsigned IOCTL_DIOCADDRULE; +extern unsigned IOCTL_DIOCGETRULES; +extern unsigned IOCTL_DIOCGETRULE; +extern unsigned IOCTL_DIOCSETLCK; +extern unsigned IOCTL_DIOCCLRSTATES; +extern unsigned IOCTL_DIOCGETSTATE; +extern unsigned IOCTL_DIOCSETSTATUSIF; +extern unsigned IOCTL_DIOCGETSTATUS; +extern unsigned IOCTL_DIOCCLRSTATUS; +extern unsigned IOCTL_DIOCNATLOOK; +extern unsigned IOCTL_DIOCSETDEBUG; +extern unsigned IOCTL_DIOCGETSTATES; +extern unsigned IOCTL_DIOCCHANGERULE; +extern unsigned IOCTL_DIOCSETTIMEOUT; +extern unsigned IOCTL_DIOCGETTIMEOUT; +extern unsigned IOCTL_DIOCADDSTATE; +extern unsigned IOCTL_DIOCCLRRULECTRS; +extern unsigned IOCTL_DIOCGETLIMIT; +extern unsigned IOCTL_DIOCSETLIMIT; +extern unsigned IOCTL_DIOCKILLSTATES; +extern unsigned IOCTL_DIOCSTARTALTQ; +extern unsigned IOCTL_DIOCSTOPALTQ; +extern unsigned IOCTL_DIOCADDALTQ; +extern unsigned IOCTL_DIOCGETALTQS; +extern unsigned IOCTL_DIOCGETALTQ; +extern unsigned IOCTL_DIOCCHANGEALTQ; +extern unsigned IOCTL_DIOCGETQSTATS; +extern unsigned IOCTL_DIOCBEGINADDRS; +extern unsigned IOCTL_DIOCADDADDR; +extern unsigned IOCTL_DIOCGETADDRS; +extern unsigned IOCTL_DIOCGETADDR; +extern unsigned IOCTL_DIOCCHANGEADDR; +extern unsigned IOCTL_DIOCADDSTATES; +extern unsigned IOCTL_DIOCGETRULESETS; +extern unsigned IOCTL_DIOCGETRULESET; +extern unsigned IOCTL_DIOCRCLRTABLES; +extern unsigned IOCTL_DIOCRADDTABLES; +extern unsigned IOCTL_DIOCRDELTABLES; +extern unsigned IOCTL_DIOCRGETTABLES; +extern unsigned IOCTL_DIOCRGETTSTATS; +extern unsigned IOCTL_DIOCRCLRTSTATS; +extern unsigned IOCTL_DIOCRCLRADDRS; +extern unsigned IOCTL_DIOCRADDADDRS; +extern unsigned IOCTL_DIOCRDELADDRS; +extern unsigned IOCTL_DIOCRSETADDRS; +extern unsigned IOCTL_DIOCRGETADDRS; +extern unsigned IOCTL_DIOCRGETASTATS; +extern unsigned IOCTL_DIOCRCLRASTATS; +extern unsigned IOCTL_DIOCRTSTADDRS; +extern unsigned IOCTL_DIOCRSETTFLAGS; +extern unsigned IOCTL_DIOCRINADEFINE; +extern unsigned IOCTL_DIOCOSFPFLUSH; +extern unsigned IOCTL_DIOCOSFPADD; +extern unsigned IOCTL_DIOCOSFPGET; +extern unsigned IOCTL_DIOCXBEGIN; +extern unsigned IOCTL_DIOCXCOMMIT; +extern unsigned IOCTL_DIOCXROLLBACK; +extern unsigned IOCTL_DIOCGETSRCNODES; +extern unsigned IOCTL_DIOCCLRSRCNODES; +extern unsigned IOCTL_DIOCSETHOSTID; +extern unsigned IOCTL_DIOCIGETIFACES; +extern unsigned IOCTL_DIOCSETIFFLAG; +extern unsigned IOCTL_DIOCCLRIFFLAG; +extern unsigned IOCTL_DIOCKILLSRCNODES; +extern unsigned IOCTL_SLIOCGUNIT; +extern unsigned IOCTL_SIOCGBTINFO; +extern unsigned IOCTL_SIOCGBTINFOA; +extern unsigned IOCTL_SIOCNBTINFO; +extern unsigned IOCTL_SIOCSBTFLAGS; +extern unsigned IOCTL_SIOCSBTPOLICY; +extern unsigned IOCTL_SIOCSBTPTYPE; +extern unsigned IOCTL_SIOCGBTSTATS; +extern unsigned IOCTL_SIOCZBTSTATS; +extern unsigned IOCTL_SIOCBTDUMP; +extern unsigned IOCTL_SIOCSBTSCOMTU; +extern unsigned IOCTL_SIOCGBTFEAT; +extern unsigned IOCTL_SIOCADNAT; +extern unsigned IOCTL_SIOCRMNAT; +extern unsigned IOCTL_SIOCGNATS; +extern unsigned IOCTL_SIOCGNATL; +extern unsigned IOCTL_SIOCPURGENAT; +extern unsigned IOCTL_SIOCSIFINFO_FLAGS; +extern unsigned IOCTL_SIOCAADDRCTL_POLICY; +extern unsigned IOCTL_SIOCDADDRCTL_POLICY; +extern unsigned IOCTL_SMBIOC_OPENSESSION; +extern unsigned IOCTL_SMBIOC_OPENSHARE; +extern unsigned IOCTL_SMBIOC_REQUEST; +extern unsigned IOCTL_SMBIOC_SETFLAGS; +extern unsigned IOCTL_SMBIOC_LOOKUP; +extern unsigned IOCTL_SMBIOC_READ; +extern unsigned IOCTL_SMBIOC_WRITE; +extern unsigned IOCTL_AGPIOC_INFO; +extern unsigned IOCTL_AGPIOC_ACQUIRE; +extern unsigned IOCTL_AGPIOC_RELEASE; +extern unsigned IOCTL_AGPIOC_SETUP; +extern unsigned IOCTL_AGPIOC_ALLOCATE; +extern unsigned IOCTL_AGPIOC_DEALLOCATE; +extern unsigned IOCTL_AGPIOC_BIND; +extern unsigned IOCTL_AGPIOC_UNBIND; +extern unsigned IOCTL_AUDIO_GETINFO; +extern unsigned IOCTL_AUDIO_SETINFO; +extern unsigned IOCTL_AUDIO_DRAIN; +extern unsigned IOCTL_AUDIO_FLUSH; +extern unsigned IOCTL_AUDIO_WSEEK; +extern unsigned IOCTL_AUDIO_RERROR; +extern unsigned IOCTL_AUDIO_GETDEV; +extern unsigned IOCTL_AUDIO_GETENC; +extern unsigned IOCTL_AUDIO_GETFD; +extern unsigned IOCTL_AUDIO_SETFD; +extern unsigned IOCTL_AUDIO_PERROR; +extern unsigned IOCTL_AUDIO_GETIOFFS; +extern unsigned IOCTL_AUDIO_GETOOFFS; +extern unsigned IOCTL_AUDIO_GETPROPS; +extern unsigned IOCTL_AUDIO_GETBUFINFO; +extern unsigned IOCTL_AUDIO_SETCHAN; +extern unsigned IOCTL_AUDIO_GETCHAN; +extern unsigned IOCTL_AUDIO_MIXER_READ; +extern unsigned IOCTL_AUDIO_MIXER_WRITE; +extern unsigned IOCTL_AUDIO_MIXER_DEVINFO; +extern unsigned IOCTL_ATAIOCCOMMAND; +extern unsigned IOCTL_ATABUSIOSCAN; +extern unsigned IOCTL_ATABUSIORESET; +extern unsigned IOCTL_ATABUSIODETACH; +extern unsigned IOCTL_CDIOCPLAYTRACKS; +extern unsigned IOCTL_CDIOCPLAYBLOCKS; +extern unsigned IOCTL_CDIOCREADSUBCHANNEL; +extern unsigned IOCTL_CDIOREADTOCHEADER; +extern unsigned IOCTL_CDIOREADTOCENTRIES; +extern unsigned IOCTL_CDIOREADMSADDR; +extern unsigned IOCTL_CDIOCSETPATCH; +extern unsigned IOCTL_CDIOCGETVOL; +extern unsigned IOCTL_CDIOCSETVOL; +extern unsigned IOCTL_CDIOCSETMONO; +extern unsigned IOCTL_CDIOCSETSTEREO; +extern unsigned IOCTL_CDIOCSETMUTE; +extern unsigned IOCTL_CDIOCSETLEFT; +extern unsigned IOCTL_CDIOCSETRIGHT; +extern unsigned IOCTL_CDIOCSETDEBUG; +extern unsigned IOCTL_CDIOCCLRDEBUG; +extern unsigned IOCTL_CDIOCPAUSE; +extern unsigned IOCTL_CDIOCRESUME; +extern unsigned IOCTL_CDIOCRESET; +extern unsigned IOCTL_CDIOCSTART; +extern unsigned IOCTL_CDIOCSTOP; +extern unsigned IOCTL_CDIOCEJECT; +extern unsigned IOCTL_CDIOCALLOW; +extern unsigned IOCTL_CDIOCPREVENT; +extern unsigned IOCTL_CDIOCCLOSE; +extern unsigned IOCTL_CDIOCPLAYMSF; +extern unsigned IOCTL_CDIOCLOADUNLOAD; +extern unsigned IOCTL_CHIOMOVE; +extern unsigned IOCTL_CHIOEXCHANGE; +extern unsigned IOCTL_CHIOPOSITION; +extern unsigned IOCTL_CHIOGPICKER; +extern unsigned IOCTL_CHIOSPICKER; +extern unsigned IOCTL_CHIOGPARAMS; +extern unsigned IOCTL_CHIOIELEM; +extern unsigned IOCTL_OCHIOGSTATUS; +extern unsigned IOCTL_CHIOGSTATUS; +extern unsigned IOCTL_CHIOSVOLTAG; +extern unsigned IOCTL_CLOCKCTL_SETTIMEOFDAY; +extern unsigned IOCTL_CLOCKCTL_ADJTIME; +extern unsigned IOCTL_CLOCKCTL_CLOCK_SETTIME; +extern unsigned IOCTL_CLOCKCTL_NTP_ADJTIME; +extern unsigned IOCTL_IOC_CPU_SETSTATE; +extern unsigned IOCTL_IOC_CPU_GETSTATE; +extern unsigned IOCTL_IOC_CPU_GETCOUNT; +extern unsigned IOCTL_IOC_CPU_MAPID; +extern unsigned IOCTL_IOC_CPU_UCODE_GET_VERSION; +extern unsigned IOCTL_IOC_CPU_UCODE_APPLY; +extern unsigned IOCTL_DIOCGDINFO; +extern unsigned IOCTL_DIOCSDINFO; +extern unsigned IOCTL_DIOCWDINFO; +extern unsigned IOCTL_DIOCRFORMAT; +extern unsigned IOCTL_DIOCWFORMAT; +extern unsigned IOCTL_DIOCSSTEP; +extern unsigned IOCTL_DIOCSRETRIES; +extern unsigned IOCTL_DIOCKLABEL; +extern unsigned IOCTL_DIOCWLABEL; +extern unsigned IOCTL_DIOCSBAD; +extern unsigned IOCTL_DIOCEJECT; +extern unsigned IOCTL_ODIOCEJECT; +extern unsigned IOCTL_DIOCLOCK; +extern unsigned IOCTL_DIOCGDEFLABEL; +extern unsigned IOCTL_DIOCCLRLABEL; +extern unsigned IOCTL_DIOCGCACHE; +extern unsigned IOCTL_DIOCSCACHE; +extern unsigned IOCTL_DIOCCACHESYNC; +extern unsigned IOCTL_DIOCBSLIST; +extern unsigned IOCTL_DIOCBSFLUSH; +extern unsigned IOCTL_DIOCAWEDGE; +extern unsigned IOCTL_DIOCGWEDGEINFO; +extern unsigned IOCTL_DIOCDWEDGE; +extern unsigned IOCTL_DIOCLWEDGES; +extern unsigned IOCTL_DIOCGSTRATEGY; +extern unsigned IOCTL_DIOCSSTRATEGY; +extern unsigned IOCTL_DIOCGDISKINFO; +extern unsigned IOCTL_DIOCTUR; +extern unsigned IOCTL_DIOCMWEDGES; +extern unsigned IOCTL_DIOCGSECTORSIZE; +extern unsigned IOCTL_DIOCGMEDIASIZE; +extern unsigned IOCTL_DRVDETACHDEV; +extern unsigned IOCTL_DRVRESCANBUS; +extern unsigned IOCTL_DRVCTLCOMMAND; +extern unsigned IOCTL_DRVRESUMEDEV; +extern unsigned IOCTL_DRVLISTDEV; +extern unsigned IOCTL_DRVGETEVENT; +extern unsigned IOCTL_DRVSUSPENDDEV; +extern unsigned IOCTL_DVD_READ_STRUCT; +extern unsigned IOCTL_DVD_WRITE_STRUCT; +extern unsigned IOCTL_DVD_AUTH; +extern unsigned IOCTL_ENVSYS_GETDICTIONARY; +extern unsigned IOCTL_ENVSYS_SETDICTIONARY; +extern unsigned IOCTL_ENVSYS_REMOVEPROPS; +extern unsigned IOCTL_ENVSYS_GTREDATA; +extern unsigned IOCTL_ENVSYS_GTREINFO; +extern unsigned IOCTL_KFILTER_BYFILTER; +extern unsigned IOCTL_KFILTER_BYNAME; +extern unsigned IOCTL_FDIOCGETOPTS; +extern unsigned IOCTL_FDIOCSETOPTS; +extern unsigned IOCTL_FDIOCSETFORMAT; +extern unsigned IOCTL_FDIOCGETFORMAT; +extern unsigned IOCTL_FDIOCFORMAT_TRACK;  extern unsigned IOCTL_FIOCLEX; -extern unsigned IOCTL_FIOGETOWN; -extern unsigned IOCTL_FIONBIO;  extern unsigned IOCTL_FIONCLEX; +extern unsigned IOCTL_FIONREAD; +extern unsigned IOCTL_FIONBIO; +extern unsigned IOCTL_FIOASYNC;  extern unsigned IOCTL_FIOSETOWN; -extern unsigned IOCTL_SIOCADDMULTI; +extern unsigned IOCTL_FIOGETOWN; +extern unsigned IOCTL_OFIOGETBMAP; +extern unsigned IOCTL_FIOGETBMAP; +extern unsigned IOCTL_FIONWRITE; +extern unsigned IOCTL_FIONSPACE; +extern unsigned IOCTL_GPIOINFO; +extern unsigned IOCTL_GPIOSET; +extern unsigned IOCTL_GPIOUNSET; +extern unsigned IOCTL_GPIOREAD; +extern unsigned IOCTL_GPIOWRITE; +extern unsigned IOCTL_GPIOTOGGLE; +extern unsigned IOCTL_GPIOATTACH; +extern unsigned IOCTL_PTIOCNETBSD; +extern unsigned IOCTL_PTIOCSUNOS; +extern unsigned IOCTL_PTIOCLINUX; +extern unsigned IOCTL_PTIOCFREEBSD; +extern unsigned IOCTL_PTIOCULTRIX; +extern unsigned IOCTL_TIOCHPCL; +extern unsigned IOCTL_TIOCGETP; +extern unsigned IOCTL_TIOCSETP; +extern unsigned IOCTL_TIOCSETN; +extern unsigned IOCTL_TIOCSETC; +extern unsigned IOCTL_TIOCGETC; +extern unsigned IOCTL_TIOCLBIS; +extern unsigned IOCTL_TIOCLBIC; +extern unsigned IOCTL_TIOCLSET; +extern unsigned IOCTL_TIOCLGET; +extern unsigned IOCTL_TIOCSLTC; +extern unsigned IOCTL_TIOCGLTC; +extern unsigned IOCTL_OTIOCCONS; +extern unsigned IOCTL_JOY_SETTIMEOUT; +extern unsigned IOCTL_JOY_GETTIMEOUT; +extern unsigned IOCTL_JOY_SET_X_OFFSET; +extern unsigned IOCTL_JOY_SET_Y_OFFSET; +extern unsigned IOCTL_JOY_GET_X_OFFSET; +extern unsigned IOCTL_JOY_GET_Y_OFFSET; +extern unsigned IOCTL_OKIOCGSYMBOL; +extern unsigned IOCTL_OKIOCGVALUE; +extern unsigned IOCTL_KIOCGSIZE; +extern unsigned IOCTL_KIOCGVALUE; +extern unsigned IOCTL_KIOCGSYMBOL; +extern unsigned IOCTL_LUAINFO; +extern unsigned IOCTL_LUACREATE; +extern unsigned IOCTL_LUADESTROY; +extern unsigned IOCTL_LUAREQUIRE; +extern unsigned IOCTL_LUALOAD; +extern unsigned IOCTL_MIDI_PRETIME; +extern unsigned IOCTL_MIDI_MPUMODE; +extern unsigned IOCTL_MIDI_MPUCMD; +extern unsigned IOCTL_SEQUENCER_RESET; +extern unsigned IOCTL_SEQUENCER_SYNC; +extern unsigned IOCTL_SEQUENCER_INFO; +extern unsigned IOCTL_SEQUENCER_CTRLRATE; +extern unsigned IOCTL_SEQUENCER_GETOUTCOUNT; +extern unsigned IOCTL_SEQUENCER_GETINCOUNT; +extern unsigned IOCTL_SEQUENCER_RESETSAMPLES; +extern unsigned IOCTL_SEQUENCER_NRSYNTHS; +extern unsigned IOCTL_SEQUENCER_NRMIDIS; +extern unsigned IOCTL_SEQUENCER_THRESHOLD; +extern unsigned IOCTL_SEQUENCER_MEMAVL; +extern unsigned IOCTL_SEQUENCER_PANIC; +extern unsigned IOCTL_SEQUENCER_OUTOFBAND; +extern unsigned IOCTL_SEQUENCER_GETTIME; +extern unsigned IOCTL_SEQUENCER_TMR_TIMEBASE; +extern unsigned IOCTL_SEQUENCER_TMR_START; +extern unsigned IOCTL_SEQUENCER_TMR_STOP; +extern unsigned IOCTL_SEQUENCER_TMR_CONTINUE; +extern unsigned IOCTL_SEQUENCER_TMR_TEMPO; +extern unsigned IOCTL_SEQUENCER_TMR_SOURCE; +extern unsigned IOCTL_SEQUENCER_TMR_METRONOME; +extern unsigned IOCTL_SEQUENCER_TMR_SELECT; +extern unsigned IOCTL_MTIOCTOP; +extern unsigned IOCTL_MTIOCGET; +extern unsigned IOCTL_MTIOCIEOT; +extern unsigned IOCTL_MTIOCEEOT; +extern unsigned IOCTL_MTIOCRDSPOS; +extern unsigned IOCTL_MTIOCRDHPOS; +extern unsigned IOCTL_MTIOCSLOCATE; +extern unsigned IOCTL_MTIOCHLOCATE; +extern unsigned IOCTL_POWER_EVENT_RECVDICT; +extern unsigned IOCTL_POWER_IOC_GET_TYPE; +extern unsigned IOCTL_POWER_IOC_GET_TYPE_WITH_LOSSAGE; +extern unsigned IOCTL_RIOCGINFO; +extern unsigned IOCTL_RIOCSINFO; +extern unsigned IOCTL_RIOCSSRCH; +extern unsigned IOCTL_RNDGETENTCNT; +extern unsigned IOCTL_RNDGETSRCNUM; +extern unsigned IOCTL_RNDGETSRCNAME; +extern unsigned IOCTL_RNDCTL; +extern unsigned IOCTL_RNDADDDATA; +extern unsigned IOCTL_RNDGETPOOLSTAT; +extern unsigned IOCTL_RNDGETESTNUM; +extern unsigned IOCTL_RNDGETESTNAME; +extern unsigned IOCTL_SCIOCGET; +extern unsigned IOCTL_SCIOCSET; +extern unsigned IOCTL_SCIOCRESTART; +extern unsigned IOCTL_SCIOC_USE_ADF; +extern unsigned IOCTL_SCIOCCOMMAND; +extern unsigned IOCTL_SCIOCDEBUG; +extern unsigned IOCTL_SCIOCIDENTIFY; +extern unsigned IOCTL_OSCIOCIDENTIFY; +extern unsigned IOCTL_SCIOCDECONFIG; +extern unsigned IOCTL_SCIOCRECONFIG; +extern unsigned IOCTL_SCIOCRESET; +extern unsigned IOCTL_SCBUSIOSCAN; +extern unsigned IOCTL_SCBUSIORESET; +extern unsigned IOCTL_SCBUSIODETACH; +extern unsigned IOCTL_SCBUSACCEL; +extern unsigned IOCTL_SCBUSIOLLSCAN; +extern unsigned IOCTL_SIOCSHIWAT; +extern unsigned IOCTL_SIOCGHIWAT; +extern unsigned IOCTL_SIOCSLOWAT; +extern unsigned IOCTL_SIOCGLOWAT;  extern unsigned IOCTL_SIOCATMARK; -extern unsigned IOCTL_SIOCDELMULTI; -extern unsigned IOCTL_SIOCGIFADDR; -extern unsigned IOCTL_SIOCGIFBRDADDR; -extern unsigned IOCTL_SIOCGIFCONF; -extern unsigned IOCTL_SIOCGIFDSTADDR; -extern unsigned IOCTL_SIOCGIFFLAGS; -extern unsigned IOCTL_SIOCGIFMETRIC; -extern unsigned IOCTL_SIOCGIFMTU; -extern unsigned IOCTL_SIOCGIFNETMASK; +extern unsigned IOCTL_SIOCSPGRP;  extern unsigned IOCTL_SIOCGPGRP; +extern unsigned IOCTL_SIOCADDRT; +extern unsigned IOCTL_SIOCDELRT;  extern unsigned IOCTL_SIOCSIFADDR; -extern unsigned IOCTL_SIOCSIFBRDADDR; +extern unsigned IOCTL_SIOCGIFADDR;  extern unsigned IOCTL_SIOCSIFDSTADDR; +extern unsigned IOCTL_SIOCGIFDSTADDR;  extern unsigned IOCTL_SIOCSIFFLAGS; +extern unsigned IOCTL_SIOCGIFFLAGS; +extern unsigned IOCTL_SIOCGIFBRDADDR; +extern unsigned IOCTL_SIOCSIFBRDADDR; +extern unsigned IOCTL_SIOCGIFCONF; +extern unsigned IOCTL_SIOCGIFNETMASK; +extern unsigned IOCTL_SIOCSIFNETMASK; +extern unsigned IOCTL_SIOCGIFMETRIC;  extern unsigned IOCTL_SIOCSIFMETRIC; +extern unsigned IOCTL_SIOCDIFADDR; +extern unsigned IOCTL_SIOCAIFADDR; +extern unsigned IOCTL_SIOCGIFALIAS; +extern unsigned IOCTL_SIOCGIFAFLAG_IN; +extern unsigned IOCTL_SIOCALIFADDR; +extern unsigned IOCTL_SIOCGLIFADDR; +extern unsigned IOCTL_SIOCDLIFADDR; +extern unsigned IOCTL_SIOCSIFADDRPREF; +extern unsigned IOCTL_SIOCGIFADDRPREF; +extern unsigned IOCTL_SIOCADDMULTI; +extern unsigned IOCTL_SIOCDELMULTI; +extern unsigned IOCTL_SIOCGETVIFCNT; +extern unsigned IOCTL_SIOCGETSGCNT; +extern unsigned IOCTL_SIOCSIFMEDIA; +extern unsigned IOCTL_SIOCGIFMEDIA; +extern unsigned IOCTL_SIOCSIFGENERIC; +extern unsigned IOCTL_SIOCGIFGENERIC; +extern unsigned IOCTL_SIOCSIFPHYADDR; +extern unsigned IOCTL_SIOCGIFPSRCADDR; +extern unsigned IOCTL_SIOCGIFPDSTADDR; +extern unsigned IOCTL_SIOCDIFPHYADDR; +extern unsigned IOCTL_SIOCSLIFPHYADDR; +extern unsigned IOCTL_SIOCGLIFPHYADDR;  extern unsigned IOCTL_SIOCSIFMTU; -extern unsigned IOCTL_SIOCSIFNETMASK; -extern unsigned IOCTL_SIOCSPGRP; -extern unsigned IOCTL_TIOCCONS; +extern unsigned IOCTL_SIOCGIFMTU; +extern unsigned IOCTL_SIOCSDRVSPEC; +extern unsigned IOCTL_SIOCGDRVSPEC; +extern unsigned IOCTL_SIOCIFCREATE; +extern unsigned IOCTL_SIOCIFDESTROY; +extern unsigned IOCTL_SIOCIFGCLONERS; +extern unsigned IOCTL_SIOCGIFDLT; +extern unsigned IOCTL_SIOCGIFCAP; +extern unsigned IOCTL_SIOCSIFCAP; +extern unsigned IOCTL_SIOCSVH; +extern unsigned IOCTL_SIOCGVH; +extern unsigned IOCTL_SIOCINITIFADDR; +extern unsigned IOCTL_SIOCGIFDATA; +extern unsigned IOCTL_SIOCZIFDATA; +extern unsigned IOCTL_SIOCGLINKSTR; +extern unsigned IOCTL_SIOCSLINKSTR; +extern unsigned IOCTL_SIOCGETHERCAP; +extern unsigned IOCTL_SIOCGIFINDEX; +extern unsigned IOCTL_SIOCSETPFSYNC; +extern unsigned IOCTL_SIOCGETPFSYNC; +extern unsigned IOCTL_PPS_IOC_CREATE; +extern unsigned IOCTL_PPS_IOC_DESTROY; +extern unsigned IOCTL_PPS_IOC_SETPARAMS; +extern unsigned IOCTL_PPS_IOC_GETPARAMS; +extern unsigned IOCTL_PPS_IOC_GETCAP; +extern unsigned IOCTL_PPS_IOC_FETCH; +extern unsigned IOCTL_PPS_IOC_KCBIND;  extern unsigned IOCTL_TIOCEXCL; -extern unsigned IOCTL_TIOCGETD; -extern unsigned IOCTL_TIOCGPGRP; -extern unsigned IOCTL_TIOCGWINSZ; -extern unsigned IOCTL_TIOCMBIC; -extern unsigned IOCTL_TIOCMBIS; -extern unsigned IOCTL_TIOCMGET; -extern unsigned IOCTL_TIOCMSET; -extern unsigned IOCTL_TIOCNOTTY;  extern unsigned IOCTL_TIOCNXCL; -extern unsigned IOCTL_TIOCOUTQ; -extern unsigned IOCTL_TIOCPKT; -extern unsigned IOCTL_TIOCSCTTY; +extern unsigned IOCTL_TIOCFLUSH; +extern unsigned IOCTL_TIOCGETA; +extern unsigned IOCTL_TIOCSETA; +extern unsigned IOCTL_TIOCSETAW; +extern unsigned IOCTL_TIOCSETAF; +extern unsigned IOCTL_TIOCGETD;  extern unsigned IOCTL_TIOCSETD; +extern unsigned IOCTL_TIOCGLINED; +extern unsigned IOCTL_TIOCSLINED; +extern unsigned IOCTL_TIOCSBRK; +extern unsigned IOCTL_TIOCCBRK; +extern unsigned IOCTL_TIOCSDTR; +extern unsigned IOCTL_TIOCCDTR; +extern unsigned IOCTL_TIOCGPGRP;  extern unsigned IOCTL_TIOCSPGRP; +extern unsigned IOCTL_TIOCOUTQ;  extern unsigned IOCTL_TIOCSTI; +extern unsigned IOCTL_TIOCNOTTY; +extern unsigned IOCTL_TIOCPKT; +extern unsigned IOCTL_TIOCSTOP; +extern unsigned IOCTL_TIOCSTART; +extern unsigned IOCTL_TIOCMSET; +extern unsigned IOCTL_TIOCMBIS; +extern unsigned IOCTL_TIOCMBIC; +extern unsigned IOCTL_TIOCMGET; +extern unsigned IOCTL_TIOCREMOTE; +extern unsigned IOCTL_TIOCGWINSZ;  extern unsigned IOCTL_TIOCSWINSZ; -extern unsigned IOCTL_SIOCGETSGCNT; -extern unsigned IOCTL_SIOCGETVIFCNT; -extern unsigned IOCTL_MTIOCGET; -extern unsigned IOCTL_MTIOCTOP; -extern unsigned IOCTL_SIOCADDRT; -extern unsigned IOCTL_SIOCDELRT; -extern unsigned IOCTL_SNDCTL_DSP_GETBLKSIZE; -extern unsigned IOCTL_SNDCTL_DSP_GETFMTS; -extern unsigned IOCTL_SNDCTL_DSP_NONBLOCK; -extern unsigned IOCTL_SNDCTL_DSP_POST; +extern unsigned IOCTL_TIOCUCNTL; +extern unsigned IOCTL_TIOCSTAT; +extern unsigned IOCTL_TIOCGSID; +extern unsigned IOCTL_TIOCCONS; +extern unsigned IOCTL_TIOCSCTTY; +extern unsigned IOCTL_TIOCEXT; +extern unsigned IOCTL_TIOCSIG; +extern unsigned IOCTL_TIOCDRAIN; +extern unsigned IOCTL_TIOCGFLAGS; +extern unsigned IOCTL_TIOCSFLAGS; +extern unsigned IOCTL_TIOCDCDTIMESTAMP; +extern unsigned IOCTL_TIOCRCVFRAME; +extern unsigned IOCTL_TIOCXMTFRAME; +extern unsigned IOCTL_TIOCPTMGET; +extern unsigned IOCTL_TIOCGRANTPT; +extern unsigned IOCTL_TIOCPTSNAME; +extern unsigned IOCTL_TIOCSQSIZE; +extern unsigned IOCTL_TIOCGQSIZE; +extern unsigned IOCTL_VERIEXEC_LOAD; +extern unsigned IOCTL_VERIEXEC_TABLESIZE; +extern unsigned IOCTL_VERIEXEC_DELETE; +extern unsigned IOCTL_VERIEXEC_QUERY; +extern unsigned IOCTL_VERIEXEC_DUMP; +extern unsigned IOCTL_VERIEXEC_FLUSH; +extern unsigned IOCTL_VIDIOC_QUERYCAP; +extern unsigned IOCTL_VIDIOC_RESERVED; +extern unsigned IOCTL_VIDIOC_ENUM_FMT; +extern unsigned IOCTL_VIDIOC_G_FMT; +extern unsigned IOCTL_VIDIOC_S_FMT; +extern unsigned IOCTL_VIDIOC_REQBUFS; +extern unsigned IOCTL_VIDIOC_QUERYBUF; +extern unsigned IOCTL_VIDIOC_G_FBUF; +extern unsigned IOCTL_VIDIOC_S_FBUF; +extern unsigned IOCTL_VIDIOC_OVERLAY; +extern unsigned IOCTL_VIDIOC_QBUF; +extern unsigned IOCTL_VIDIOC_DQBUF; +extern unsigned IOCTL_VIDIOC_STREAMON; +extern unsigned IOCTL_VIDIOC_STREAMOFF; +extern unsigned IOCTL_VIDIOC_G_PARM; +extern unsigned IOCTL_VIDIOC_S_PARM; +extern unsigned IOCTL_VIDIOC_G_STD; +extern unsigned IOCTL_VIDIOC_S_STD; +extern unsigned IOCTL_VIDIOC_ENUMSTD; +extern unsigned IOCTL_VIDIOC_ENUMINPUT; +extern unsigned IOCTL_VIDIOC_G_CTRL; +extern unsigned IOCTL_VIDIOC_S_CTRL; +extern unsigned IOCTL_VIDIOC_G_TUNER; +extern unsigned IOCTL_VIDIOC_S_TUNER; +extern unsigned IOCTL_VIDIOC_G_AUDIO; +extern unsigned IOCTL_VIDIOC_S_AUDIO; +extern unsigned IOCTL_VIDIOC_QUERYCTRL; +extern unsigned IOCTL_VIDIOC_QUERYMENU; +extern unsigned IOCTL_VIDIOC_G_INPUT; +extern unsigned IOCTL_VIDIOC_S_INPUT; +extern unsigned IOCTL_VIDIOC_G_OUTPUT; +extern unsigned IOCTL_VIDIOC_S_OUTPUT; +extern unsigned IOCTL_VIDIOC_ENUMOUTPUT; +extern unsigned IOCTL_VIDIOC_G_AUDOUT; +extern unsigned IOCTL_VIDIOC_S_AUDOUT; +extern unsigned IOCTL_VIDIOC_G_MODULATOR; +extern unsigned IOCTL_VIDIOC_S_MODULATOR; +extern unsigned IOCTL_VIDIOC_G_FREQUENCY; +extern unsigned IOCTL_VIDIOC_S_FREQUENCY; +extern unsigned IOCTL_VIDIOC_CROPCAP; +extern unsigned IOCTL_VIDIOC_G_CROP; +extern unsigned IOCTL_VIDIOC_S_CROP; +extern unsigned IOCTL_VIDIOC_G_JPEGCOMP; +extern unsigned IOCTL_VIDIOC_S_JPEGCOMP; +extern unsigned IOCTL_VIDIOC_QUERYSTD; +extern unsigned IOCTL_VIDIOC_TRY_FMT; +extern unsigned IOCTL_VIDIOC_ENUMAUDIO; +extern unsigned IOCTL_VIDIOC_ENUMAUDOUT; +extern unsigned IOCTL_VIDIOC_G_PRIORITY; +extern unsigned IOCTL_VIDIOC_S_PRIORITY; +extern unsigned IOCTL_VIDIOC_ENUM_FRAMESIZES; +extern unsigned IOCTL_VIDIOC_ENUM_FRAMEINTERVALS; +extern unsigned IOCTL_WDOGIOC_GMODE; +extern unsigned IOCTL_WDOGIOC_SMODE; +extern unsigned IOCTL_WDOGIOC_WHICH; +extern unsigned IOCTL_WDOGIOC_TICKLE; +extern unsigned IOCTL_WDOGIOC_GTICKLER; +extern unsigned IOCTL_WDOGIOC_GWDOGS;  extern unsigned IOCTL_SNDCTL_DSP_RESET; -extern unsigned IOCTL_SNDCTL_DSP_SETFMT; -extern unsigned IOCTL_SNDCTL_DSP_SETFRAGMENT; +extern unsigned IOCTL_SNDCTL_DSP_SYNC;  extern unsigned IOCTL_SNDCTL_DSP_SPEED; +extern unsigned IOCTL_SOUND_PCM_READ_RATE;  extern unsigned IOCTL_SNDCTL_DSP_STEREO; -extern unsigned IOCTL_SNDCTL_DSP_SUBDIVIDE; -extern unsigned IOCTL_SNDCTL_DSP_SYNC; -extern unsigned IOCTL_SNDCTL_FM_4OP_ENABLE; -extern unsigned IOCTL_SNDCTL_FM_LOAD_INSTR; -extern unsigned IOCTL_SNDCTL_MIDI_INFO; -extern unsigned IOCTL_SNDCTL_MIDI_PRETIME; -extern unsigned IOCTL_SNDCTL_SEQ_CTRLRATE; -extern unsigned IOCTL_SNDCTL_SEQ_GETINCOUNT; -extern unsigned IOCTL_SNDCTL_SEQ_GETOUTCOUNT; -extern unsigned IOCTL_SNDCTL_SEQ_NRMIDIS; -extern unsigned IOCTL_SNDCTL_SEQ_NRSYNTHS; -extern unsigned IOCTL_SNDCTL_SEQ_OUTOFBAND; -extern unsigned IOCTL_SNDCTL_SEQ_PANIC; -extern unsigned IOCTL_SNDCTL_SEQ_PERCMODE; -extern unsigned IOCTL_SNDCTL_SEQ_RESET; -extern unsigned IOCTL_SNDCTL_SEQ_RESETSAMPLES; -extern unsigned IOCTL_SNDCTL_SEQ_SYNC; -extern unsigned IOCTL_SNDCTL_SEQ_TESTMIDI; -extern unsigned IOCTL_SNDCTL_SEQ_THRESHOLD; -extern unsigned IOCTL_SNDCTL_SYNTH_INFO; -extern unsigned IOCTL_SNDCTL_SYNTH_MEMAVL; -extern unsigned IOCTL_SNDCTL_TMR_CONTINUE; -extern unsigned IOCTL_SNDCTL_TMR_METRONOME; -extern unsigned IOCTL_SNDCTL_TMR_SELECT; -extern unsigned IOCTL_SNDCTL_TMR_SOURCE; -extern unsigned IOCTL_SNDCTL_TMR_START; -extern unsigned IOCTL_SNDCTL_TMR_STOP; -extern unsigned IOCTL_SNDCTL_TMR_TEMPO; -extern unsigned IOCTL_SNDCTL_TMR_TIMEBASE; -extern unsigned IOCTL_SOUND_MIXER_READ_ALTPCM; -extern unsigned IOCTL_SOUND_MIXER_READ_BASS; -extern unsigned IOCTL_SOUND_MIXER_READ_CAPS; -extern unsigned IOCTL_SOUND_MIXER_READ_CD; -extern unsigned IOCTL_SOUND_MIXER_READ_DEVMASK; -extern unsigned IOCTL_SOUND_MIXER_READ_ENHANCE; -extern unsigned IOCTL_SOUND_MIXER_READ_IGAIN; -extern unsigned IOCTL_SOUND_MIXER_READ_IMIX; -extern unsigned IOCTL_SOUND_MIXER_READ_LINE1; -extern unsigned IOCTL_SOUND_MIXER_READ_LINE2; -extern unsigned IOCTL_SOUND_MIXER_READ_LINE3; -extern unsigned IOCTL_SOUND_MIXER_READ_LINE; -extern unsigned IOCTL_SOUND_MIXER_READ_LOUD; -extern unsigned IOCTL_SOUND_MIXER_READ_MIC; -extern unsigned IOCTL_SOUND_MIXER_READ_MUTE; -extern unsigned IOCTL_SOUND_MIXER_READ_OGAIN; -extern unsigned IOCTL_SOUND_MIXER_READ_PCM; -extern unsigned IOCTL_SOUND_MIXER_READ_RECLEV; -extern unsigned IOCTL_SOUND_MIXER_READ_RECMASK; -extern unsigned IOCTL_SOUND_MIXER_READ_RECSRC; -extern unsigned IOCTL_SOUND_MIXER_READ_SPEAKER; -extern unsigned IOCTL_SOUND_MIXER_READ_STEREODEVS; -extern unsigned IOCTL_SOUND_MIXER_READ_SYNTH; -extern unsigned IOCTL_SOUND_MIXER_READ_TREBLE; -extern unsigned IOCTL_SOUND_MIXER_READ_VOLUME; -extern unsigned IOCTL_SOUND_MIXER_WRITE_ALTPCM; -extern unsigned IOCTL_SOUND_MIXER_WRITE_BASS; -extern unsigned IOCTL_SOUND_MIXER_WRITE_CD; -extern unsigned IOCTL_SOUND_MIXER_WRITE_ENHANCE; -extern unsigned IOCTL_SOUND_MIXER_WRITE_IGAIN; -extern unsigned IOCTL_SOUND_MIXER_WRITE_IMIX; -extern unsigned IOCTL_SOUND_MIXER_WRITE_LINE1; -extern unsigned IOCTL_SOUND_MIXER_WRITE_LINE2; -extern unsigned IOCTL_SOUND_MIXER_WRITE_LINE3; -extern unsigned IOCTL_SOUND_MIXER_WRITE_LINE; -extern unsigned IOCTL_SOUND_MIXER_WRITE_LOUD; -extern unsigned IOCTL_SOUND_MIXER_WRITE_MIC; -extern unsigned IOCTL_SOUND_MIXER_WRITE_MUTE; -extern unsigned IOCTL_SOUND_MIXER_WRITE_OGAIN; -extern unsigned IOCTL_SOUND_MIXER_WRITE_PCM; -extern unsigned IOCTL_SOUND_MIXER_WRITE_RECLEV; -extern unsigned IOCTL_SOUND_MIXER_WRITE_RECSRC; -extern unsigned IOCTL_SOUND_MIXER_WRITE_SPEAKER; -extern unsigned IOCTL_SOUND_MIXER_WRITE_SYNTH; -extern unsigned IOCTL_SOUND_MIXER_WRITE_TREBLE; -extern unsigned IOCTL_SOUND_MIXER_WRITE_VOLUME; +extern unsigned IOCTL_SNDCTL_DSP_GETBLKSIZE; +extern unsigned IOCTL_SNDCTL_DSP_SETFMT;  extern unsigned IOCTL_SOUND_PCM_READ_BITS; +extern unsigned IOCTL_SNDCTL_DSP_CHANNELS;  extern unsigned IOCTL_SOUND_PCM_READ_CHANNELS; -extern unsigned IOCTL_SOUND_PCM_READ_FILTER; -extern unsigned IOCTL_SOUND_PCM_READ_RATE; -extern unsigned IOCTL_SOUND_PCM_WRITE_CHANNELS;  extern unsigned IOCTL_SOUND_PCM_WRITE_FILTER; -extern unsigned IOCTL_VT_ACTIVATE; -extern unsigned IOCTL_VT_GETMODE; -extern unsigned IOCTL_VT_OPENQRY; -extern unsigned IOCTL_VT_RELDISP; -extern unsigned IOCTL_VT_SETMODE; -extern unsigned IOCTL_VT_WAITACTIVE; -extern unsigned IOCTL_KDDISABIO; -extern unsigned IOCTL_KDENABIO; -extern unsigned IOCTL_KDGETLED; -extern unsigned IOCTL_KDGKBMODE; -extern unsigned IOCTL_KDGKBTYPE; -extern unsigned IOCTL_KDMKTONE; -extern unsigned IOCTL_KDSETLED; -extern unsigned IOCTL_KDSETMODE; -extern unsigned IOCTL_KDSKBMODE; +extern unsigned IOCTL_SOUND_PCM_READ_FILTER; +extern unsigned IOCTL_SNDCTL_DSP_POST; +extern unsigned IOCTL_SNDCTL_DSP_SUBDIVIDE; +extern unsigned IOCTL_SNDCTL_DSP_SETFRAGMENT; +extern unsigned IOCTL_SNDCTL_DSP_GETFMTS; +extern unsigned IOCTL_SNDCTL_DSP_GETOSPACE; +extern unsigned IOCTL_SNDCTL_DSP_GETISPACE; +extern unsigned IOCTL_SNDCTL_DSP_NONBLOCK; +extern unsigned IOCTL_SNDCTL_DSP_GETCAPS; +extern unsigned IOCTL_SNDCTL_DSP_GETTRIGGER; +extern unsigned IOCTL_SNDCTL_DSP_SETTRIGGER; +extern unsigned IOCTL_SNDCTL_DSP_GETIPTR; +extern unsigned IOCTL_SNDCTL_DSP_GETOPTR; +extern unsigned IOCTL_SNDCTL_DSP_MAPINBUF; +extern unsigned IOCTL_SNDCTL_DSP_MAPOUTBUF; +extern unsigned IOCTL_SNDCTL_DSP_SETSYNCRO; +extern unsigned IOCTL_SNDCTL_DSP_SETDUPLEX; +extern unsigned IOCTL_SNDCTL_DSP_PROFILE; +extern unsigned IOCTL_SNDCTL_DSP_GETODELAY; +extern unsigned IOCTL_SOUND_MIXER_INFO; +extern unsigned IOCTL_SOUND_OLD_MIXER_INFO; +extern unsigned IOCTL_OSS_GETVERSION; +extern unsigned IOCTL_SNDCTL_SYSINFO; +extern unsigned IOCTL_SNDCTL_AUDIOINFO; +extern unsigned IOCTL_SNDCTL_ENGINEINFO; +extern unsigned IOCTL_SNDCTL_DSP_GETPLAYVOL; +extern unsigned IOCTL_SNDCTL_DSP_SETPLAYVOL; +extern unsigned IOCTL_SNDCTL_DSP_GETRECVOL; +extern unsigned IOCTL_SNDCTL_DSP_SETRECVOL; +extern unsigned IOCTL_SNDCTL_DSP_SKIP; +extern unsigned IOCTL_SNDCTL_DSP_SILENCE;  extern const int si_SEGV_MAPERR;  extern const int si_SEGV_ACCERR; diff --git a/lib/sanitizer_common/sanitizer_platform_limits_openbsd.cc b/lib/sanitizer_common/sanitizer_platform_limits_openbsd.cc new file mode 100644 index 0000000000000..7ab0ff60a24de --- /dev/null +++ b/lib/sanitizer_common/sanitizer_platform_limits_openbsd.cc @@ -0,0 +1,279 @@ +//===-- sanitizer_platform_limits_openbsd.cc ------------------------------===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of Sanitizer common code. +// +// Sizes and layouts of platform-specific NetBSD data structures. +//===----------------------------------------------------------------------===// + +#include "sanitizer_platform.h" + +#if SANITIZER_OPENBSD +#include <arpa/inet.h> +#include <dirent.h> +#include <glob.h> +#include <grp.h> +#include <ifaddrs.h> +#include <limits.h> +#include <link_elf.h> +#include <sys/socket.h> +#include <net/if.h> +#include <net/ppp_defs.h> +#include <net/route.h> +#include <netdb.h> +#include <netinet/in.h> +#include <netinet/ip_mroute.h> +#include <poll.h> +#include <pthread.h> +#include <pwd.h> +#include <semaphore.h> +#include <signal.h> +#include <soundcard.h> +#include <stddef.h> +#include <stdint.h> +#include <sys/filio.h> +#include <sys/ipc.h> +#include <sys/mman.h> +#include <sys/mount.h> +#include <sys/msg.h> +#include <sys/mtio.h> +#include <sys/ptrace.h> +#include <sys/resource.h> +#include <sys/shm.h> +#include <sys/signal.h> +#include <sys/sockio.h> +#include <sys/stat.h> +#include <sys/statvfs.h> +#include <sys/time.h> +#include <sys/times.h> +#include <sys/types.h> +#include <sys/utsname.h> +#include <term.h> +#include <time.h> +#include <utime.h> +#include <utmp.h> +#include <wchar.h> + +// Include these after system headers to avoid name clashes and ambiguities. +#include "sanitizer_internal_defs.h" +#include "sanitizer_platform_limits_openbsd.h" + +namespace __sanitizer { +unsigned struct_utsname_sz = sizeof(struct utsname); +unsigned struct_stat_sz = sizeof(struct stat); +unsigned struct_rusage_sz = sizeof(struct rusage); +unsigned struct_tm_sz = sizeof(struct tm); +unsigned struct_passwd_sz = sizeof(struct passwd); +unsigned struct_group_sz = sizeof(struct group); +unsigned siginfo_t_sz = sizeof(siginfo_t); +unsigned struct_sigaction_sz = sizeof(struct sigaction); +unsigned struct_itimerval_sz = sizeof(struct itimerval); +unsigned pthread_t_sz = sizeof(pthread_t); +unsigned pthread_mutex_t_sz = sizeof(pthread_mutex_t); +unsigned pthread_cond_t_sz = sizeof(pthread_cond_t); +unsigned pid_t_sz = sizeof(pid_t); +unsigned timeval_sz = sizeof(timeval); +unsigned uid_t_sz = sizeof(uid_t); +unsigned gid_t_sz = sizeof(gid_t); +unsigned mbstate_t_sz = sizeof(mbstate_t); +unsigned sigset_t_sz = sizeof(sigset_t); +unsigned struct_timezone_sz = sizeof(struct timezone); +unsigned struct_tms_sz = sizeof(struct tms); +unsigned struct_sched_param_sz = sizeof(struct sched_param); +unsigned struct_sockaddr_sz = sizeof(struct sockaddr); +unsigned struct_rlimit_sz = sizeof(struct rlimit); +unsigned struct_timespec_sz = sizeof(struct timespec); +unsigned struct_utimbuf_sz = sizeof(struct utimbuf); +unsigned struct_itimerspec_sz = sizeof(struct itimerspec); +unsigned struct_msqid_ds_sz = sizeof(struct msqid_ds); +unsigned struct_statvfs_sz = sizeof(struct statvfs); + +const uptr sig_ign = (uptr)SIG_IGN; +const uptr sig_dfl = (uptr)SIG_DFL; +const uptr sig_err = (uptr)SIG_ERR; +const uptr sa_siginfo = (uptr)SA_SIGINFO; + +int shmctl_ipc_stat = (int)IPC_STAT; + +unsigned struct_utmp_sz = sizeof(struct utmp); + +int map_fixed = MAP_FIXED; + +int af_inet = (int)AF_INET; +int af_inet6 = (int)AF_INET6; + +uptr __sanitizer_in_addr_sz(int af) { +  if (af == AF_INET) +    return sizeof(struct in_addr); +  else if (af == AF_INET6) +    return sizeof(struct in6_addr); +  else +    return 0; +} + +unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr); + +int glob_nomatch = GLOB_NOMATCH; +int glob_altdirfunc = GLOB_ALTDIRFUNC; + +unsigned path_max = PATH_MAX; + +const int si_SEGV_MAPERR = SEGV_MAPERR; +const int si_SEGV_ACCERR = SEGV_ACCERR; +}  // namespace __sanitizer + +using namespace __sanitizer; + +COMPILER_CHECK(sizeof(__sanitizer_pthread_attr_t) >= sizeof(pthread_attr_t)); + +COMPILER_CHECK(sizeof(socklen_t) == sizeof(unsigned)); +CHECK_TYPE_SIZE(pthread_key_t); + +CHECK_TYPE_SIZE(dl_phdr_info); +CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_addr); +CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_name); +CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_phdr); +CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_phnum); + +CHECK_TYPE_SIZE(glob_t); +CHECK_SIZE_AND_OFFSET(glob_t, gl_pathc); +CHECK_SIZE_AND_OFFSET(glob_t, gl_pathv); +CHECK_SIZE_AND_OFFSET(glob_t, gl_offs); +CHECK_SIZE_AND_OFFSET(glob_t, gl_flags); +CHECK_SIZE_AND_OFFSET(glob_t, gl_closedir); +CHECK_SIZE_AND_OFFSET(glob_t, gl_readdir); +CHECK_SIZE_AND_OFFSET(glob_t, gl_opendir); +CHECK_SIZE_AND_OFFSET(glob_t, gl_lstat); +CHECK_SIZE_AND_OFFSET(glob_t, gl_stat); + +CHECK_TYPE_SIZE(addrinfo); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_flags); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_family); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_socktype); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_protocol); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_addrlen); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_addr); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_canonname); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_next); + +CHECK_TYPE_SIZE(hostent); +CHECK_SIZE_AND_OFFSET(hostent, h_name); +CHECK_SIZE_AND_OFFSET(hostent, h_aliases); +CHECK_SIZE_AND_OFFSET(hostent, h_addrtype); +CHECK_SIZE_AND_OFFSET(hostent, h_length); +CHECK_SIZE_AND_OFFSET(hostent, h_addr_list); + +CHECK_TYPE_SIZE(iovec); +CHECK_SIZE_AND_OFFSET(iovec, iov_base); +CHECK_SIZE_AND_OFFSET(iovec, iov_len); + +CHECK_TYPE_SIZE(msghdr); +CHECK_SIZE_AND_OFFSET(msghdr, msg_name); +CHECK_SIZE_AND_OFFSET(msghdr, msg_namelen); +CHECK_SIZE_AND_OFFSET(msghdr, msg_iov); +CHECK_SIZE_AND_OFFSET(msghdr, msg_iovlen); +CHECK_SIZE_AND_OFFSET(msghdr, msg_control); +CHECK_SIZE_AND_OFFSET(msghdr, msg_controllen); +CHECK_SIZE_AND_OFFSET(msghdr, msg_flags); + +CHECK_TYPE_SIZE(cmsghdr); +CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_len); +CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_level); +CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_type); + +COMPILER_CHECK(sizeof(__sanitizer_dirent) <= sizeof(dirent)); +CHECK_SIZE_AND_OFFSET(dirent, d_fileno); +CHECK_SIZE_AND_OFFSET(dirent, d_off); +CHECK_SIZE_AND_OFFSET(dirent, d_reclen); + +CHECK_TYPE_SIZE(ifconf); +CHECK_SIZE_AND_OFFSET(ifconf, ifc_len); +CHECK_SIZE_AND_OFFSET(ifconf, ifc_ifcu); + +CHECK_TYPE_SIZE(pollfd); +CHECK_SIZE_AND_OFFSET(pollfd, fd); +CHECK_SIZE_AND_OFFSET(pollfd, events); +CHECK_SIZE_AND_OFFSET(pollfd, revents); + +CHECK_TYPE_SIZE(nfds_t); + +CHECK_TYPE_SIZE(sigset_t); + +COMPILER_CHECK(sizeof(__sanitizer_sigaction) == sizeof(struct sigaction)); +// Can't write checks for sa_handler and sa_sigaction due to them being +// preprocessor macros. +CHECK_STRUCT_SIZE_AND_OFFSET(sigaction, sa_mask); + +CHECK_TYPE_SIZE(tm); +CHECK_SIZE_AND_OFFSET(tm, tm_sec); +CHECK_SIZE_AND_OFFSET(tm, tm_min); +CHECK_SIZE_AND_OFFSET(tm, tm_hour); +CHECK_SIZE_AND_OFFSET(tm, tm_mday); +CHECK_SIZE_AND_OFFSET(tm, tm_mon); +CHECK_SIZE_AND_OFFSET(tm, tm_year); +CHECK_SIZE_AND_OFFSET(tm, tm_wday); +CHECK_SIZE_AND_OFFSET(tm, tm_yday); +CHECK_SIZE_AND_OFFSET(tm, tm_isdst); +CHECK_SIZE_AND_OFFSET(tm, tm_gmtoff); +CHECK_SIZE_AND_OFFSET(tm, tm_zone); + +CHECK_TYPE_SIZE(ipc_perm); +CHECK_SIZE_AND_OFFSET(ipc_perm, cuid); +CHECK_SIZE_AND_OFFSET(ipc_perm, cgid); +CHECK_SIZE_AND_OFFSET(ipc_perm, uid); +CHECK_SIZE_AND_OFFSET(ipc_perm, gid); +CHECK_SIZE_AND_OFFSET(ipc_perm, mode); +CHECK_SIZE_AND_OFFSET(ipc_perm, seq); +CHECK_SIZE_AND_OFFSET(ipc_perm, key); + +CHECK_TYPE_SIZE(shmid_ds); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_perm); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_segsz); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_atime); +CHECK_SIZE_AND_OFFSET(shmid_ds, __shm_atimensec); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_dtime); +CHECK_SIZE_AND_OFFSET(shmid_ds, __shm_dtimensec); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_ctime); +CHECK_SIZE_AND_OFFSET(shmid_ds, __shm_ctimensec); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_cpid); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_lpid); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_nattch); + +CHECK_TYPE_SIZE(clock_t); + +CHECK_TYPE_SIZE(ifaddrs); +CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_next); +CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_name); +CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_addr); +CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_netmask); +// Compare against the union, because we can't reach into the union in a +// compliant way. +#ifdef ifa_dstaddr +#undef ifa_dstaddr +#endif +CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_dstaddr); +CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_data); + +CHECK_TYPE_SIZE(passwd); +CHECK_SIZE_AND_OFFSET(passwd, pw_name); +CHECK_SIZE_AND_OFFSET(passwd, pw_passwd); +CHECK_SIZE_AND_OFFSET(passwd, pw_uid); +CHECK_SIZE_AND_OFFSET(passwd, pw_gid); +CHECK_SIZE_AND_OFFSET(passwd, pw_dir); +CHECK_SIZE_AND_OFFSET(passwd, pw_shell); + +CHECK_SIZE_AND_OFFSET(passwd, pw_gecos); + +CHECK_TYPE_SIZE(group); +CHECK_SIZE_AND_OFFSET(group, gr_name); +CHECK_SIZE_AND_OFFSET(group, gr_passwd); +CHECK_SIZE_AND_OFFSET(group, gr_gid); +CHECK_SIZE_AND_OFFSET(group, gr_mem); + +#endif  // SANITIZER_OPENBSD diff --git a/lib/sanitizer_common/sanitizer_platform_limits_openbsd.h b/lib/sanitizer_common/sanitizer_platform_limits_openbsd.h new file mode 100644 index 0000000000000..d9899913e576c --- /dev/null +++ b/lib/sanitizer_common/sanitizer_platform_limits_openbsd.h @@ -0,0 +1,382 @@ +//===-- sanitizer_platform_limits_openbsd.h -------------------------------===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of Sanitizer common code. +// +// Sizes and layouts of platform-specific OpenBSD data structures. +//===----------------------------------------------------------------------===// + +#ifndef SANITIZER_PLATFORM_LIMITS_OPENBSD_H +#define SANITIZER_PLATFORM_LIMITS_OPENBSD_H + +#if SANITIZER_OPENBSD + +#include "sanitizer_internal_defs.h" +#include "sanitizer_platform.h" + +#define _GET_LINK_MAP_BY_DLOPEN_HANDLE(handle, shift) \ +  ((link_map *)((handle) == nullptr ? nullptr : ((char *)(handle) + (shift)))) + +#if defined(__x86_64__) +#define GET_LINK_MAP_BY_DLOPEN_HANDLE(handle) \ +  _GET_LINK_MAP_BY_DLOPEN_HANDLE(handle, 312) +#elif defined(__i386__) +#define GET_LINK_MAP_BY_DLOPEN_HANDLE(handle) \ +  _GET_LINK_MAP_BY_DLOPEN_HANDLE(handle, 164) +#endif + +#define RLIMIT_AS RLIMIT_DATA + +namespace __sanitizer { +extern unsigned struct_utsname_sz; +extern unsigned struct_stat_sz; +extern unsigned struct_rusage_sz; +extern unsigned siginfo_t_sz; +extern unsigned struct_itimerval_sz; +extern unsigned pthread_t_sz; +extern unsigned pthread_mutex_t_sz; +extern unsigned pthread_cond_t_sz; +extern unsigned pid_t_sz; +extern unsigned timeval_sz; +extern unsigned uid_t_sz; +extern unsigned gid_t_sz; +extern unsigned mbstate_t_sz; +extern unsigned struct_timezone_sz; +extern unsigned struct_tms_sz; +extern unsigned struct_itimerspec_sz; +extern unsigned struct_sigevent_sz; +extern unsigned struct_statfs_sz; +extern unsigned struct_sockaddr_sz; + +extern unsigned struct_rlimit_sz; +extern unsigned struct_utimbuf_sz; +extern unsigned struct_timespec_sz; + +struct __sanitizer_iocb { +  u64 aio_offset; +  uptr aio_buf; +  long aio_nbytes; +  u32 aio_fildes; +  u32 aio_lio_opcode; +  long aio_reqprio; +#if SANITIZER_WORDSIZE == 64 +  u8 aio_sigevent[32]; +#else +  u8 aio_sigevent[20]; +#endif +  u32 _state; +  u32 _errno; +  long _retval; +}; + +struct __sanitizer___sysctl_args { +  int *name; +  int nlen; +  void *oldval; +  uptr *oldlenp; +  void *newval; +  uptr newlen; +}; + +struct __sanitizer_sem_t { +  uptr data[5]; +}; + +struct __sanitizer_ipc_perm { +  u32 cuid; +  u32 cgid; +  u32 uid; +  u32 gid; +  u32 mode; +  unsigned short seq; +  long key; +}; + +struct __sanitizer_shmid_ds { +  __sanitizer_ipc_perm shm_perm; +  int shm_segsz; +  u32 shm_lpid; +  u32 shm_cpid; +  short shm_nattch; +  u64 shm_atime; +  long __shm_atimensec; +  u64 shm_dtime; +  long __shm_dtimensec; +  u64 shm_ctime; +  long __shm_ctimensec; +  void *_shm_internal; +}; + +extern unsigned struct_msqid_ds_sz; +extern unsigned struct_mq_attr_sz; +extern unsigned struct_timex_sz; +extern unsigned struct_statvfs_sz; + +struct __sanitizer_iovec { +  void *iov_base; +  uptr iov_len; +}; + +struct __sanitizer_ifaddrs { +  struct __sanitizer_ifaddrs *ifa_next; +  char *ifa_name; +  unsigned int ifa_flags; +  struct __sanitizer_sockaddr *ifa_addr;     // (struct sockaddr *) +  struct __sanitizer_sockaddr *ifa_netmask;  // (struct sockaddr *) +  struct __sanitizer_sockaddr *ifa_dstaddr;  // (struct sockaddr *) +  void *ifa_data; +}; + +typedef unsigned __sanitizer_pthread_key_t; + +typedef long long __sanitizer_time_t; +typedef int __sanitizer_suseconds_t; + +struct __sanitizer_timeval { +  __sanitizer_time_t tv_sec; +  __sanitizer_suseconds_t tv_usec; +}; + +struct __sanitizer_itimerval { +  struct __sanitizer_timeval it_interval; +  struct __sanitizer_timeval it_value; +}; + +struct __sanitizer_passwd { +  char *pw_name; +  char *pw_passwd; +  int pw_uid; +  int pw_gid; +  __sanitizer_time_t pw_change; +  char *pw_class; +  char *pw_gecos; +  char *pw_dir; +  char *pw_shell; +  __sanitizer_time_t pw_expire; +}; + +struct __sanitizer_group { +  char *gr_name; +  char *gr_passwd; +  int gr_gid; +  char **gr_mem; +}; + +struct __sanitizer_ether_addr { +  u8 octet[6]; +}; + +struct __sanitizer_tm { +  int tm_sec; +  int tm_min; +  int tm_hour; +  int tm_mday; +  int tm_mon; +  int tm_year; +  int tm_wday; +  int tm_yday; +  int tm_isdst; +  long int tm_gmtoff; +  const char *tm_zone; +}; + +struct __sanitizer_msghdr { +  void *msg_name; +  unsigned msg_namelen; +  struct __sanitizer_iovec *msg_iov; +  unsigned msg_iovlen; +  void *msg_control; +  unsigned msg_controllen; +  int msg_flags; +}; +struct __sanitizer_cmsghdr { +  unsigned cmsg_len; +  int cmsg_level; +  int cmsg_type; +}; + +struct __sanitizer_dirent { +  u64 d_fileno; +  u64 d_off; +  u16 d_reclen; +}; + +typedef u64 __sanitizer_clock_t; +typedef u32 __sanitizer_clockid_t; + +typedef u32 __sanitizer___kernel_uid_t; +typedef u32 __sanitizer___kernel_gid_t; +typedef u64 __sanitizer___kernel_off_t; +typedef struct { +  u32 fds_bits[8]; +} __sanitizer___kernel_fd_set; + +typedef struct { +  unsigned int pta_magic; +  int pta_flags; +  void *pta_private; +} __sanitizer_pthread_attr_t; + +typedef unsigned int __sanitizer_sigset_t; + +struct __sanitizer_siginfo { +  // The size is determined by looking at sizeof of real siginfo_t on linux. +  u64 opaque[128 / sizeof(u64)]; +}; + +using __sanitizer_sighandler_ptr = void (*)(int sig); +using __sanitizer_sigactionhandler_ptr = void (*)(int sig, +                                                  __sanitizer_siginfo *siginfo, +                                                  void *uctx); + +struct __sanitizer_sigaction { +  union { +    __sanitizer_sighandler_ptr handler; +    __sanitizer_sigactionhandler_ptr sigaction; +  }; +  __sanitizer_sigset_t sa_mask; +  int sa_flags; +}; + +typedef __sanitizer_sigset_t __sanitizer_kernel_sigset_t; + +struct __sanitizer_kernel_sigaction_t { +  union { +    void (*handler)(int signo); +    void (*sigaction)(int signo, void *info, void *ctx); +  }; +  unsigned long sa_flags; +  void (*sa_restorer)(void); +  __sanitizer_kernel_sigset_t sa_mask; +}; + +extern const uptr sig_ign; +extern const uptr sig_dfl; +extern const uptr sig_err; +extern const uptr sa_siginfo; + +extern int af_inet; +extern int af_inet6; +uptr __sanitizer_in_addr_sz(int af); + +struct __sanitizer_dl_phdr_info { +#if SANITIZER_WORDSIZE == 64 +  u64 dlpi_addr; +#else +  u32 dlpi_addr; +#endif +  const char *dlpi_name; +  const void *dlpi_phdr; +#if SANITIZER_WORDSIZE == 64 +  u32 dlpi_phnum; +#else +  u16 dlpi_phnum; +#endif +}; + +extern unsigned struct_ElfW_Phdr_sz; + +struct __sanitizer_addrinfo { +  int ai_flags; +  int ai_family; +  int ai_socktype; +  int ai_protocol; +  unsigned ai_addrlen; +  struct __sanitizer_sockaddr *ai_addr; +  char *ai_canonname; +  struct __sanitizer_addrinfo *ai_next; +}; + +struct __sanitizer_hostent { +  char *h_name; +  char **h_aliases; +  int h_addrtype; +  int h_length; +  char **h_addr_list; +}; + +struct __sanitizer_pollfd { +  int fd; +  short events; +  short revents; +}; + +typedef unsigned __sanitizer_nfds_t; + +struct __sanitizer_glob_t { +  int gl_pathc; +  int gl_matchc; +  int gl_offs; +  int gl_flags; +  char **gl_pathv; +  void **gl_statv; +  int (*gl_errfunc)(const char *, int); +  void (*gl_closedir)(void *dirp); +  struct dirent *(*gl_readdir)(void *dirp); +  void *(*gl_opendir)(const char *); +  int (*gl_lstat)(const char *, void * /* struct stat* */); +  int (*gl_stat)(const char *, void * /* struct stat* */); +}; + +extern int glob_nomatch; +extern int glob_altdirfunc; + +extern unsigned path_max; + +typedef char __sanitizer_FILE; +#define SANITIZER_HAS_STRUCT_FILE 0 + +extern int shmctl_ipc_stat; + +// This simplifies generic code +#define struct_shminfo_sz -1 +#define struct_shm_info_sz -1 +#define shmctl_shm_stat -1 +#define shmctl_ipc_info -1 +#define shmctl_shm_info -1 + +extern unsigned struct_utmp_sz; +extern unsigned struct_utmpx_sz; + +extern int map_fixed; + +// ioctl arguments +struct __sanitizer_ifconf { +  int ifc_len; +  union { +    void *ifcu_req; +  } ifc_ifcu; +}; + +extern const int si_SEGV_MAPERR; +extern const int si_SEGV_ACCERR; +}  // namespace __sanitizer + +#define CHECK_TYPE_SIZE(TYPE) \ +  COMPILER_CHECK(sizeof(__sanitizer_##TYPE) == sizeof(TYPE)) + +#define CHECK_SIZE_AND_OFFSET(CLASS, MEMBER)                      \ +  COMPILER_CHECK(sizeof(((__sanitizer_##CLASS *)NULL)->MEMBER) == \ +                 sizeof(((CLASS *)NULL)->MEMBER));                \ +  COMPILER_CHECK(offsetof(__sanitizer_##CLASS, MEMBER) ==         \ +                 offsetof(CLASS, MEMBER)) + +// For sigaction, which is a function and struct at the same time, +// and thus requires explicit "struct" in sizeof() expression. +#define CHECK_STRUCT_SIZE_AND_OFFSET(CLASS, MEMBER)                      \ +  COMPILER_CHECK(sizeof(((struct __sanitizer_##CLASS *)NULL)->MEMBER) == \ +                 sizeof(((struct CLASS *)NULL)->MEMBER));                \ +  COMPILER_CHECK(offsetof(struct __sanitizer_##CLASS, MEMBER) ==         \ +                 offsetof(struct CLASS, MEMBER)) + +#define SIGACTION_SYMNAME __sigaction14 + +#endif  // SANITIZER_OPENBSD + +#endif diff --git a/lib/sanitizer_common/sanitizer_platform_limits_posix.cc b/lib/sanitizer_common/sanitizer_platform_limits_posix.cc index f12e8206abe63..c27055f2aa808 100644 --- a/lib/sanitizer_common/sanitizer_platform_limits_posix.cc +++ b/lib/sanitizer_common/sanitizer_platform_limits_posix.cc @@ -159,7 +159,6 @@ typedef struct user_fpregs elf_fpregset_t;  # include <sys/procfs.h>  #endif  #include <sys/user.h> -#include <sys/ustat.h>  #include <linux/cyclades.h>  #include <linux/if_eql.h>  #include <linux/if_plip.h> @@ -253,7 +252,19 @@ namespace __sanitizer {  #endif // SANITIZER_LINUX || SANITIZER_FREEBSD  #if SANITIZER_LINUX && !SANITIZER_ANDROID -  unsigned struct_ustat_sz = sizeof(struct ustat); +  // Use pre-computed size of struct ustat to avoid <sys/ustat.h> which +  // has been removed from glibc 2.28. +#if defined(__aarch64__) || defined(__s390x__) || defined (__mips64) \ +  || defined(__powerpc64__) || defined(__arch64__) || defined(__sparcv9) \ +  || defined(__x86_64__) +#define SIZEOF_STRUCT_USTAT 32 +#elif defined(__arm__) || defined(__i386__) || defined(__mips__) \ +  || defined(__powerpc__) || defined(__s390__) || defined(__sparc__) +#define SIZEOF_STRUCT_USTAT 20 +#else +#error Unknown size of struct ustat +#endif +  unsigned struct_ustat_sz = SIZEOF_STRUCT_USTAT;    unsigned struct_rlimit64_sz = sizeof(struct rlimit64);    unsigned struct_statvfs64_sz = sizeof(struct statvfs64);  #endif // SANITIZER_LINUX && !SANITIZER_ANDROID @@ -1026,6 +1037,12 @@ CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_len);  CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_level);  CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_type); +#if SANITIZER_LINUX && (!defined(__ANDROID__) || __ANDROID_API__ >= 21) +CHECK_TYPE_SIZE(mmsghdr); +CHECK_SIZE_AND_OFFSET(mmsghdr, msg_hdr); +CHECK_SIZE_AND_OFFSET(mmsghdr, msg_len); +#endif +  COMPILER_CHECK(sizeof(__sanitizer_dirent) <= sizeof(dirent));  CHECK_SIZE_AND_OFFSET(dirent, d_ino);  #if SANITIZER_MAC diff --git a/lib/sanitizer_common/sanitizer_platform_limits_posix.h b/lib/sanitizer_common/sanitizer_platform_limits_posix.h index b1901fb63edc4..f89a11312d8bd 100644 --- a/lib/sanitizer_common/sanitizer_platform_limits_posix.h +++ b/lib/sanitizer_common/sanitizer_platform_limits_posix.h @@ -24,7 +24,7 @@  // FreeBSD's dlopen() returns a pointer to an Obj_Entry structure that  // incorporates the map structure.  # define GET_LINK_MAP_BY_DLOPEN_HANDLE(handle) \ -    ((link_map*)((handle) == nullptr ? nullptr : ((char*)(handle) + 544))) +    ((link_map*)((handle) == nullptr ? nullptr : ((char*)(handle) + 560)))  // Get sys/_types.h, because that tells us whether 64-bit inodes are  // used in struct dirent below.  #include <sys/_types.h> @@ -414,6 +414,18 @@ namespace __sanitizer {    typedef long __sanitizer_time_t;  #endif +  typedef long __sanitizer_suseconds_t; + +  struct __sanitizer_timeval { +    __sanitizer_time_t tv_sec; +    __sanitizer_suseconds_t tv_usec; +  }; + +  struct __sanitizer_itimerval { +    struct __sanitizer_timeval it_interval; +    struct __sanitizer_timeval it_value; +  }; +    struct __sanitizer_timeb {      __sanitizer_time_t time;      unsigned short millitm; @@ -448,6 +460,12 @@ namespace __sanitizer {      int mnt_freq;      int mnt_passno;    }; + +  struct __sanitizer_file_handle { +    unsigned int handle_bytes; +    int handle_type; +    unsigned char f_handle[1];  // variable sized +  };  #endif  #if SANITIZER_MAC || SANITIZER_FREEBSD @@ -482,6 +500,13 @@ namespace __sanitizer {    };  #endif +#if SANITIZER_LINUX +  struct __sanitizer_mmsghdr { +    __sanitizer_msghdr msg_hdr; +    unsigned int msg_len; +  }; +#endif +  #if SANITIZER_MAC    struct __sanitizer_dirent {      unsigned long long d_ino; diff --git a/lib/sanitizer_common/sanitizer_platform_limits_solaris.h b/lib/sanitizer_common/sanitizer_platform_limits_solaris.h index a9db71b99c812..c0aa4cc1b17ef 100644 --- a/lib/sanitizer_common/sanitizer_platform_limits_solaris.h +++ b/lib/sanitizer_common/sanitizer_platform_limits_solaris.h @@ -160,6 +160,18 @@ struct __sanitizer_group {  typedef long __sanitizer_time_t; +typedef long __sanitizer_suseconds_t; + +struct __sanitizer_timeval { +  __sanitizer_time_t tv_sec; +  __sanitizer_suseconds_t tv_usec; +}; + +struct __sanitizer_itimerval { +  struct __sanitizer_timeval it_interval; +  struct __sanitizer_timeval it_value; +}; +  struct __sanitizer_timeb {    __sanitizer_time_t time;    unsigned short millitm; diff --git a/lib/sanitizer_common/sanitizer_posix.cc b/lib/sanitizer_common/sanitizer_posix.cc index 1fad71f3582b9..f7dfc86f58c65 100644 --- a/lib/sanitizer_common/sanitizer_posix.cc +++ b/lib/sanitizer_common/sanitizer_posix.cc @@ -21,7 +21,6 @@  #include "sanitizer_libc.h"  #include "sanitizer_posix.h"  #include "sanitizer_procmaps.h" -#include "sanitizer_stacktrace.h"  #include <errno.h>  #include <fcntl.h> @@ -153,11 +152,15 @@ bool MprotectReadOnly(uptr addr, uptr size) {    return 0 == internal_mprotect((void *)addr, size, PROT_READ);  } +#if !SANITIZER_MAC +void MprotectMallocZones(void *addr, int prot) {} +#endif +  fd_t OpenFile(const char *filename, FileAccessMode mode, error_t *errno_p) {    int flags;    switch (mode) {      case RdOnly: flags = O_RDONLY; break; -    case WrOnly: flags = O_WRONLY | O_CREAT; break; +    case WrOnly: flags = O_WRONLY | O_CREAT | O_TRUNC; break;      case RdWr: flags = O_RDWR | O_CREAT; break;    }    fd_t res = internal_open(filename, flags, 0660); diff --git a/lib/sanitizer_common/sanitizer_posix.h b/lib/sanitizer_common/sanitizer_posix.h index adef08248004a..da447002b66c3 100644 --- a/lib/sanitizer_common/sanitizer_posix.h +++ b/lib/sanitizer_common/sanitizer_posix.h @@ -17,6 +17,7 @@  // This header should NOT include any other headers from sanitizer runtime.  #include "sanitizer_internal_defs.h"  #include "sanitizer_platform_limits_netbsd.h" +#include "sanitizer_platform_limits_openbsd.h"  #include "sanitizer_platform_limits_posix.h"  #include "sanitizer_platform_limits_solaris.h" diff --git a/lib/sanitizer_common/sanitizer_posix_libcdep.cc b/lib/sanitizer_common/sanitizer_posix_libcdep.cc index db41cad6c3182..266e9bdba051e 100644 --- a/lib/sanitizer_common/sanitizer_posix_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_posix_libcdep.cc @@ -19,12 +19,11 @@  #include "sanitizer_common.h"  #include "sanitizer_flags.h"  #include "sanitizer_platform_limits_netbsd.h" +#include "sanitizer_platform_limits_openbsd.h"  #include "sanitizer_platform_limits_posix.h"  #include "sanitizer_platform_limits_solaris.h"  #include "sanitizer_posix.h"  #include "sanitizer_procmaps.h" -#include "sanitizer_stacktrace.h" -#include "sanitizer_symbolizer.h"  #include <errno.h>  #include <fcntl.h> @@ -42,7 +41,7 @@  #if SANITIZER_FREEBSD  // The MAP_NORESERVE define has been removed in FreeBSD 11.x, and even before  // that, it was never implemented.  So just define it to zero. -#undef  MAP_NORESERVE +#undef MAP_NORESERVE  #define MAP_NORESERVE 0  #endif @@ -70,16 +69,22 @@ void ReleaseMemoryPagesToOS(uptr beg, uptr end) {              SANITIZER_MADVISE_DONTNEED);  } -void NoHugePagesInRegion(uptr addr, uptr size) { +bool NoHugePagesInRegion(uptr addr, uptr size) {  #ifdef MADV_NOHUGEPAGE  // May not be defined on old systems. -  madvise((void *)addr, size, MADV_NOHUGEPAGE); +  return madvise((void *)addr, size, MADV_NOHUGEPAGE) == 0; +#else +  return true;  #endif  // MADV_NOHUGEPAGE  } -void DontDumpShadowMemory(uptr addr, uptr length) { -#ifdef MADV_DONTDUMP -  madvise((void *)addr, length, MADV_DONTDUMP); -#endif +bool DontDumpShadowMemory(uptr addr, uptr length) { +#if defined(MADV_DONTDUMP) +  return madvise((void *)addr, length, MADV_DONTDUMP) == 0; +#elif defined(MADV_NOCORE) +  return madvise((void *)addr, length, MADV_NOCORE) == 0; +#else +  return true; +#endif  // MADV_DONTDUMP  }  static rlim_t getlim(int res) { @@ -218,6 +223,7 @@ void InstallDeadlySignalHandlers(SignalHandlerType handler) {    MaybeInstallSigaction(SIGABRT, handler);    MaybeInstallSigaction(SIGFPE, handler);    MaybeInstallSigaction(SIGILL, handler); +  MaybeInstallSigaction(SIGTRAP, handler);  }  bool SignalContext::IsStackOverflow() const { @@ -230,7 +236,9 @@ bool SignalContext::IsStackOverflow() const {    // take it into account.    bool IsStackAccess = addr >= (sp & ~0xFFF) && addr < sp + 0xFFFF;  #else -  bool IsStackAccess = addr + 512 > sp && addr < sp + 0xFFFF; +  // Let's accept up to a page size away from top of stack. Things like stack +  // probing can trigger accesses with such large offsets. +  bool IsStackAccess = addr + GetPageSizeCached() > sp && addr < sp + 0xFFFF;  #endif  #if __powerpc__ @@ -290,16 +298,12 @@ bool IsAccessibleMemoryRange(uptr beg, uptr size) {    return result;  } -void PrepareForSandboxing(__sanitizer_sandbox_arguments *args) { +void PlatformPrepareForSandboxing(__sanitizer_sandbox_arguments *args) {    // Some kinds of sandboxes may forbid filesystem access, so we won't be able    // to read the file mappings from /proc/self/maps. Luckily, neither the    // process will be able to load additional libraries, so it's fine to use the    // cached mappings.    MemoryMappingLayout::CacheMemoryMappings(); -  // Same for /proc/self/exe in the symbolizer. -#if !SANITIZER_GO -  Symbolizer::GetOrInit()->PrepareForSandboxing(); -#endif  }  #if SANITIZER_ANDROID || SANITIZER_GO @@ -324,7 +328,7 @@ int GetNamedMappingFd(const char *name, uptr size) {  }  #endif -void *MmapFixedNoReserve(uptr fixed_addr, uptr size, const char *name) { +bool MmapFixedNoReserve(uptr fixed_addr, uptr size, const char *name) {    int fd = name ? GetNamedMappingFd(name, size) : -1;    unsigned flags = MAP_PRIVATE | MAP_FIXED | MAP_NORESERVE;    if (fd == -1) flags |= MAP_ANON; @@ -334,12 +338,14 @@ void *MmapFixedNoReserve(uptr fixed_addr, uptr size, const char *name) {                           RoundUpTo(size, PageSize), PROT_READ | PROT_WRITE,                           flags, fd, 0);    int reserrno; -  if (internal_iserror(p, &reserrno)) +  if (internal_iserror(p, &reserrno)) {      Report("ERROR: %s failed to "             "allocate 0x%zx (%zd) bytes at address %zx (errno: %d)\n",             SanitizerToolName, size, size, fixed_addr, reserrno); +    return false; +  }    IncreaseTotalMmap(size); -  return (void *)p; +  return true;  }  uptr ReservedAddressRange::Init(uptr size, const char *name, uptr fixed_addr) { @@ -348,11 +354,7 @@ uptr ReservedAddressRange::Init(uptr size, const char *name, uptr fixed_addr) {    // `open` (e.g. TSAN, ESAN), then you'll get a failure during initialization.    // TODO(flowerhack): Fix the implementation of GetNamedMappingFd to solve    // this problem. -  if (fixed_addr) { -    base_ = MmapFixedNoAccess(fixed_addr, size); -  } else { -    base_ = MmapNoAccess(size); -  } +  base_ = fixed_addr ? MmapFixedNoAccess(fixed_addr, size) : MmapNoAccess(size);    size_ = size;    name_ = name;    (void)os_handle_;  // unsupported @@ -370,16 +372,14 @@ uptr ReservedAddressRange::MapOrDie(uptr fixed_addr, uptr size) {  }  void ReservedAddressRange::Unmap(uptr addr, uptr size) { -  void* addr_as_void = reinterpret_cast<void*>(addr); -  uptr base_as_uptr = reinterpret_cast<uptr>(base_); -  // Only unmap at the beginning or end of the range. -  CHECK((addr_as_void == base_) || (addr + size == base_as_uptr + size_));    CHECK_LE(size, size_); +  if (addr == reinterpret_cast<uptr>(base_)) +    // If we unmap the whole range, just null out the base. +    base_ = (size == size_) ? nullptr : reinterpret_cast<void*>(addr + size); +  else +    CHECK_EQ(addr + size, reinterpret_cast<uptr>(base_) + size_); +  size_ -= size;    UnmapOrDie(reinterpret_cast<void*>(addr), size); -  if (addr_as_void == base_) { -    base_ = reinterpret_cast<void*>(addr + size); -  } -  size_ = size_ - size;  }  void *MmapFixedNoAccess(uptr fixed_addr, uptr size, const char *name) { diff --git a/lib/sanitizer_common/sanitizer_printf.cc b/lib/sanitizer_common/sanitizer_printf.cc index 5c2360043b078..4315f6516c036 100644 --- a/lib/sanitizer_common/sanitizer_printf.cc +++ b/lib/sanitizer_common/sanitizer_printf.cc @@ -95,22 +95,31 @@ static int AppendSignedDecimal(char **buff, const char *buff_end, s64 num,                        false /* uppercase */);  } -static int AppendString(char **buff, const char *buff_end, int precision, -                        const char *s) { + +// Use the fact that explicitly requesting 0 width (%0s) results in UB and +// interpret width == 0 as "no width requested": +// width == 0 - no width requested +// width  < 0 - left-justify s within and pad it to -width chars, if necessary +// width  > 0 - right-justify s, not implemented yet +static int AppendString(char **buff, const char *buff_end, int width, +                        int max_chars, const char *s) {    if (!s)      s = "<null>";    int result = 0;    for (; *s; s++) { -    if (precision >= 0 && result >= precision) +    if (max_chars >= 0 && result >= max_chars)        break;      result += AppendChar(buff, buff_end, *s);    } +  // Only the left justified strings are supported. +  while (width < -result) +    result += AppendChar(buff, buff_end, ' ');    return result;  }  static int AppendPointer(char **buff, const char *buff_end, u64 ptr_value) {    int result = 0; -  result += AppendString(buff, buff_end, -1, "0x"); +  result += AppendString(buff, buff_end, 0, -1, "0x");    result += AppendUnsigned(buff, buff_end, ptr_value, 16,                             SANITIZER_POINTER_FORMAT_LENGTH,                             true /* pad_with_zero */, false /* uppercase */); @@ -120,8 +129,8 @@ static int AppendPointer(char **buff, const char *buff_end, u64 ptr_value) {  int VSNPrintf(char *buff, int buff_length,                const char *format, va_list args) {    static const char *kPrintfFormatsHelp = -      "Supported Printf formats: %([0-9]*)?(z|ll)?{d,u,x,X}; %p; %(\\.\\*)?s; " -      "%c\n"; +      "Supported Printf formats: %([0-9]*)?(z|ll)?{d,u,x,X}; %p; " +      "%[-]([0-9]*)?(\\.\\*)?s; %c\n";    RAW_CHECK(format);    RAW_CHECK(buff_length > 0);    const char *buff_end = &buff[buff_length - 1]; @@ -133,6 +142,9 @@ int VSNPrintf(char *buff, int buff_length,        continue;      }      cur++; +    bool left_justified = *cur == '-'; +    if (left_justified) +      cur++;      bool have_width = (*cur >= '0' && *cur <= '9');      bool pad_with_zero = (*cur == '0');      int width = 0; @@ -153,9 +165,10 @@ int VSNPrintf(char *buff, int buff_length,      cur += have_ll * 2;      s64 dval;      u64 uval; -    bool have_flags = have_width | have_z | have_ll; -    // Only %s supports precision for now -    CHECK(!(precision >= 0 && *cur != 's')); +    const bool have_length = have_z || have_ll; +    const bool have_flags = have_width || have_length; +    // At the moment only %s supports precision and left-justification. +    CHECK(!((precision >= 0 || left_justified) && *cur != 's'));      switch (*cur) {        case 'd': {          dval = have_ll ? va_arg(args, s64) @@ -182,8 +195,11 @@ int VSNPrintf(char *buff, int buff_length,          break;        }        case 's': { -        RAW_CHECK_MSG(!have_flags, kPrintfFormatsHelp); -        result += AppendString(&buff, buff_end, precision, va_arg(args, char*)); +        RAW_CHECK_MSG(!have_length, kPrintfFormatsHelp); +        // Only left-justified width is supported. +        CHECK(!have_width || left_justified); +        result += AppendString(&buff, buff_end, left_justified ? -width : width, +                               precision, va_arg(args, char*));          break;        }        case 'c': { diff --git a/lib/sanitizer_common/sanitizer_procmaps.h b/lib/sanitizer_common/sanitizer_procmaps.h index ea2cb7a5c68b3..9fde040a11a61 100644 --- a/lib/sanitizer_common/sanitizer_procmaps.h +++ b/lib/sanitizer_common/sanitizer_procmaps.h @@ -16,8 +16,8 @@  #include "sanitizer_platform.h" -#if SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD || \ -    SANITIZER_MAC || SANITIZER_SOLARIS +#if SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD ||                \ +    SANITIZER_OPENBSD || SANITIZER_MAC || SANITIZER_SOLARIS  #include "sanitizer_common.h"  #include "sanitizer_internal_defs.h" @@ -95,6 +95,5 @@ uptr ParseHex(const char **p);  }  // namespace __sanitizer -#endif  // SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD || -        // SANITIZER_MAC || SANITIZER_SOLARIS +#endif  #endif  // SANITIZER_PROCMAPS_H diff --git a/lib/sanitizer_common/sanitizer_procmaps_freebsd.cc b/lib/sanitizer_common/sanitizer_procmaps_bsd.cc index c26a6d47ea75a..e41dc987dcd77 100644 --- a/lib/sanitizer_common/sanitizer_procmaps_freebsd.cc +++ b/lib/sanitizer_common/sanitizer_procmaps_bsd.cc @@ -1,4 +1,4 @@ -//===-- sanitizer_procmaps_freebsd.cc -------------------------------------===// +//===-- sanitizer_procmaps_bsd.cc -----------------------------------------===//  //  //                     The LLVM Compiler Infrastructure  // @@ -7,29 +7,40 @@  //  //===----------------------------------------------------------------------===//  // -// Information about the process mappings (FreeBSD and NetBSD-specific parts). +// Information about the process mappings +// (FreeBSD, OpenBSD and NetBSD-specific parts).  //===----------------------------------------------------------------------===//  #include "sanitizer_platform.h" -#if SANITIZER_FREEBSD || SANITIZER_NETBSD +#if SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_OPENBSD  #include "sanitizer_common.h"  #if SANITIZER_FREEBSD  #include "sanitizer_freebsd.h"  #endif  #include "sanitizer_procmaps.h" -#include <unistd.h> +// clang-format off +#include <sys/types.h>  #include <sys/sysctl.h> +// clang-format on +#include <unistd.h>  #if SANITIZER_FREEBSD  #include <sys/user.h>  #endif +#include <limits.h> +#if SANITIZER_OPENBSD +#define KVME_PROT_READ KVE_PROT_READ +#define KVME_PROT_WRITE KVE_PROT_WRITE +#define KVME_PROT_EXEC KVE_PROT_EXEC +#endif +  // Fix 'kinfo_vmentry' definition on FreeBSD prior v9.2 in 32-bit mode.  #if SANITIZER_FREEBSD && (SANITIZER_WORDSIZE == 32) -# include <osreldate.h> -# if __FreeBSD_version <= 902001  // v9.2 -#  define kinfo_vmentry xkinfo_vmentry -# endif +#include <osreldate.h> +#if __FreeBSD_version <= 902001 // v9.2 +#define kinfo_vmentry xkinfo_vmentry +#endif  #endif  namespace __sanitizer { @@ -41,12 +52,18 @@ void ReadProcMaps(ProcSelfMapsBuff *proc_maps) {      KERN_PROC,      KERN_PROC_VMMAP,      getpid() -#else +#elif SANITIZER_OPENBSD +    CTL_KERN, +    KERN_PROC_VMMAP, +    getpid() +#elif SANITIZER_NETBSD      CTL_VM,      VM_PROC,      VM_PROC_MAP,      getpid(),      sizeof(struct kinfo_vmentry) +#else +#error "not supported"  #endif    }; @@ -55,21 +72,38 @@ void ReadProcMaps(ProcSelfMapsBuff *proc_maps) {    CHECK_EQ(Err, 0);    CHECK_GT(Size, 0); +#if !SANITIZER_OPENBSD    size_t MmapedSize = Size * 4 / 3;    void *VmMap = MmapOrDie(MmapedSize, "ReadProcMaps()");    Size = MmapedSize;    Err = sysctl(Mib, ARRAY_SIZE(Mib), VmMap, &Size, NULL, 0);    CHECK_EQ(Err, 0); +  proc_maps->data = (char *)VmMap; +#else +  size_t PageSize = GetPageSize(); +  size_t MmapedSize = Size; +  MmapedSize = ((MmapedSize - 1) / PageSize + 1) * PageSize; +  char *Mem = (char *)MmapOrDie(MmapedSize, "ReadProcMaps()"); +  Size = 2 * Size + 10 * sizeof(struct kinfo_vmentry); +  if (Size > 0x10000) +    Size = 0x10000; +  Size = (Size / sizeof(struct kinfo_vmentry)) * sizeof(struct kinfo_vmentry); +  Err = sysctl(Mib, ARRAY_SIZE(Mib), Mem, &Size, NULL, 0); +  CHECK_EQ(Err, 0); +  MmapedSize = Size; +  proc_maps->data = Mem; +#endif -  proc_maps->data = (char*)VmMap;    proc_maps->mmaped_size = MmapedSize;    proc_maps->len = Size;  }  bool MemoryMappingLayout::Next(MemoryMappedSegment *segment) {    char *last = data_.proc_self_maps.data + data_.proc_self_maps.len; -  if (data_.current >= last) return false; -  struct kinfo_vmentry *VmEntry = (struct kinfo_vmentry *)data_.current; +  if (data_.current >= last) +    return false; +  const struct kinfo_vmentry *VmEntry = +      (const struct kinfo_vmentry *)data_.current;    segment->start = (uptr)VmEntry->kve_start;    segment->end = (uptr)VmEntry->kve_end; @@ -83,11 +117,13 @@ bool MemoryMappingLayout::Next(MemoryMappedSegment *segment) {    if ((VmEntry->kve_protection & KVME_PROT_EXEC) != 0)      segment->protection |= kProtectionExecute; +#if !SANITIZER_OPENBSD    if (segment->filename != NULL && segment->filename_size > 0) {      internal_snprintf(segment->filename,                        Min(segment->filename_size, (uptr)PATH_MAX), "%s",                        VmEntry->kve_path);    } +#endif  #if SANITIZER_FREEBSD    data_.current += VmEntry->kve_structsize; @@ -98,6 +134,6 @@ bool MemoryMappingLayout::Next(MemoryMappedSegment *segment) {    return true;  } -}  // namespace __sanitizer +} // namespace __sanitizer -#endif  // SANITIZER_FREEBSD || SANITIZER_NETBSD +#endif diff --git a/lib/sanitizer_common/sanitizer_procmaps_common.cc b/lib/sanitizer_common/sanitizer_procmaps_common.cc index 0cd3e2458d872..1f2b431c7ccd3 100644 --- a/lib/sanitizer_common/sanitizer_procmaps_common.cc +++ b/lib/sanitizer_common/sanitizer_procmaps_common.cc @@ -12,8 +12,8 @@  #include "sanitizer_platform.h" -#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \ -    SANITIZER_SOLARIS +#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD ||                \ +    SANITIZER_OPENBSD || SANITIZER_SOLARIS  #include "sanitizer_common.h"  #include "sanitizer_placement_new.h" @@ -170,5 +170,4 @@ void GetMemoryProfile(fill_profile_f cb, uptr *stats, uptr stats_size) {  } // namespace __sanitizer -#endif // SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || -       // SANITIZER_SOLARIS +#endif diff --git a/lib/sanitizer_common/sanitizer_quarantine.h b/lib/sanitizer_common/sanitizer_quarantine.h index 886445a27322e..d4aa12fbebce4 100644 --- a/lib/sanitizer_common/sanitizer_quarantine.h +++ b/lib/sanitizer_common/sanitizer_quarantine.h @@ -90,6 +90,9 @@ class Quarantine {      atomic_store_relaxed(&max_size_, size);      atomic_store_relaxed(&min_size_, size / 10 * 9);  // 90% of max size.      atomic_store_relaxed(&max_cache_size_, cache_size); + +    cache_mutex_.Init(); +    recycle_mutex_.Init();    }    uptr GetSize() const { return atomic_load_relaxed(&max_size_); } @@ -142,8 +145,8 @@ class Quarantine {    atomic_uintptr_t min_size_;    atomic_uintptr_t max_cache_size_;    char pad1_[kCacheLineSize]; -  SpinMutex cache_mutex_; -  SpinMutex recycle_mutex_; +  StaticSpinMutex cache_mutex_; +  StaticSpinMutex recycle_mutex_;    Cache cache_;    char pad2_[kCacheLineSize]; diff --git a/lib/sanitizer_common/sanitizer_report_decorator.h b/lib/sanitizer_common/sanitizer_report_decorator.h index 060b58d3f2d3c..a7878684a60de 100644 --- a/lib/sanitizer_common/sanitizer_report_decorator.h +++ b/lib/sanitizer_common/sanitizer_report_decorator.h @@ -25,10 +25,11 @@ class SanitizerCommonDecorator {    // stdout, which is not the case on Windows (see SetConsoleTextAttribute()).   public:    SanitizerCommonDecorator() : ansi_(ColorizeReports()) {} -  const char *Bold()    const { return ansi_ ? "\033[1m" : ""; } +  const char *Bold() const { return ansi_ ? "\033[1m" : ""; }    const char *Default() const { return ansi_ ? "\033[1m\033[0m"  : ""; }    const char *Warning() const { return Red(); } -  const char *MemoryByte() { return Magenta(); } +  const char *Error() const { return Red(); } +  const char *MemoryByte() const { return Magenta(); }   protected:    const char *Black()   const { return ansi_ ? "\033[1m\033[30m" : ""; } diff --git a/lib/sanitizer_common/sanitizer_rtems.cc b/lib/sanitizer_common/sanitizer_rtems.cc new file mode 100644 index 0000000000000..4be367911e3fd --- /dev/null +++ b/lib/sanitizer_common/sanitizer_rtems.cc @@ -0,0 +1,282 @@ +//===-- sanitizer_rtems.cc ------------------------------------------------===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is shared between various sanitizers' runtime libraries and +// implements RTEMS-specific functions. +//===----------------------------------------------------------------------===// + +#include "sanitizer_rtems.h" +#if SANITIZER_RTEMS + +#define posix_memalign __real_posix_memalign +#define free __real_free +#define memset __real_memset + +#include "sanitizer_file.h" +#include "sanitizer_symbolizer.h" +#include <errno.h> +#include <fcntl.h> +#include <pthread.h> +#include <sched.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +// There is no mmap on RTEMS.  Use memalign, etc. +#define __mmap_alloc_aligned posix_memalign +#define __mmap_free free +#define __mmap_memset memset + +namespace __sanitizer { + +#include "sanitizer_syscall_generic.inc" + +void NORETURN internal__exit(int exitcode) { +  _exit(exitcode); +} + +uptr internal_sched_yield() { +  return sched_yield(); +} + +uptr internal_getpid() { +  return getpid(); +} + +bool FileExists(const char *filename) { +  struct stat st; +  if (stat(filename, &st)) +    return false; +  // Sanity check: filename is a regular file. +  return S_ISREG(st.st_mode); +} + +uptr GetThreadSelf() { return static_cast<uptr>(pthread_self()); } + +tid_t GetTid() { return GetThreadSelf(); } + +void Abort() { abort(); } + +int Atexit(void (*function)(void)) { return atexit(function); } + +void SleepForSeconds(int seconds) { sleep(seconds); } + +void SleepForMillis(int millis) { usleep(millis * 1000); } + +bool SupportsColoredOutput(fd_t fd) { return false; } + +void GetThreadStackTopAndBottom(bool at_initialization, +                                uptr *stack_top, uptr *stack_bottom) { +  pthread_attr_t attr; +  pthread_attr_init(&attr); +  CHECK_EQ(pthread_getattr_np(pthread_self(), &attr), 0); +  void *base = nullptr; +  size_t size = 0; +  CHECK_EQ(pthread_attr_getstack(&attr, &base, &size), 0); +  CHECK_EQ(pthread_attr_destroy(&attr), 0); + +  *stack_bottom = reinterpret_cast<uptr>(base); +  *stack_top = *stack_bottom + size; +} + +void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size, +                          uptr *tls_addr, uptr *tls_size) { +  uptr stack_top, stack_bottom; +  GetThreadStackTopAndBottom(main, &stack_top, &stack_bottom); +  *stk_addr = stack_bottom; +  *stk_size = stack_top - stack_bottom; +  *tls_addr = *tls_size = 0; +} + +void MaybeReexec() {} +void CheckASLR() {} +void DisableCoreDumperIfNecessary() {} +void InstallDeadlySignalHandlers(SignalHandlerType handler) {} +void SetAlternateSignalStack() {} +void UnsetAlternateSignalStack() {} +void InitTlsSize() {} + +void PrintModuleMap() {} + +void SignalContext::DumpAllRegisters(void *context) {} +const char *DescribeSignalOrException(int signo) { UNIMPLEMENTED(); } + +enum MutexState { MtxUnlocked = 0, MtxLocked = 1, MtxSleeping = 2 }; + +BlockingMutex::BlockingMutex() { +  internal_memset(this, 0, sizeof(*this)); +} + +void BlockingMutex::Lock() { +  CHECK_EQ(owner_, 0); +  atomic_uint32_t *m = reinterpret_cast<atomic_uint32_t *>(&opaque_storage_); +  if (atomic_exchange(m, MtxLocked, memory_order_acquire) == MtxUnlocked) +    return; +  while (atomic_exchange(m, MtxSleeping, memory_order_acquire) != MtxUnlocked) { +    internal_sched_yield(); +  } +} + +void BlockingMutex::Unlock() { +  atomic_uint32_t *m = reinterpret_cast<atomic_uint32_t *>(&opaque_storage_); +  u32 v = atomic_exchange(m, MtxUnlocked, memory_order_release); +  CHECK_NE(v, MtxUnlocked); +} + +void BlockingMutex::CheckLocked() { +  atomic_uint32_t *m = reinterpret_cast<atomic_uint32_t *>(&opaque_storage_); +  CHECK_NE(MtxUnlocked, atomic_load(m, memory_order_relaxed)); +} + +uptr GetPageSize() { return getpagesize(); } + +uptr GetMmapGranularity() { return GetPageSize(); } + +uptr GetMaxVirtualAddress() { +  return (1ULL << 32) - 1;  // 0xffffffff +} + +void *MmapOrDie(uptr size, const char *mem_type, bool raw_report) { +  void* ptr = 0; +  int res = __mmap_alloc_aligned(&ptr, GetPageSize(), size); +  if (UNLIKELY(res)) +    ReportMmapFailureAndDie(size, mem_type, "allocate", res, raw_report); +  __mmap_memset(ptr, 0, size); +  IncreaseTotalMmap(size); +  return ptr; +} + +void *MmapOrDieOnFatalError(uptr size, const char *mem_type) { +  void* ptr = 0; +  int res = __mmap_alloc_aligned(&ptr, GetPageSize(), size); +  if (UNLIKELY(res)) { +    if (res == ENOMEM) +      return nullptr; +    ReportMmapFailureAndDie(size, mem_type, "allocate", false); +  } +  __mmap_memset(ptr, 0, size); +  IncreaseTotalMmap(size); +  return ptr; +} + +void *MmapAlignedOrDieOnFatalError(uptr size, uptr alignment, +                                   const char *mem_type) { +  CHECK(IsPowerOfTwo(size)); +  CHECK(IsPowerOfTwo(alignment)); +  void* ptr = 0; +  int res = __mmap_alloc_aligned(&ptr, alignment, size); +  if (res) +    ReportMmapFailureAndDie(size, mem_type, "align allocate", res, false); +  __mmap_memset(ptr, 0, size); +  IncreaseTotalMmap(size); +  return ptr; +} + +void *MmapNoReserveOrDie(uptr size, const char *mem_type) { +  return MmapOrDie(size, mem_type, false); +} + +void UnmapOrDie(void *addr, uptr size) { +  if (!addr || !size) return; +  __mmap_free(addr); +  DecreaseTotalMmap(size); +} + +fd_t OpenFile(const char *filename, FileAccessMode mode, error_t *errno_p) { +  int flags; +  switch (mode) { +    case RdOnly: flags = O_RDONLY; break; +    case WrOnly: flags = O_WRONLY | O_CREAT | O_TRUNC; break; +    case RdWr: flags = O_RDWR | O_CREAT; break; +  } +  fd_t res = open(filename, flags, 0660); +  if (internal_iserror(res, errno_p)) +    return kInvalidFd; +  return res; +} + +void CloseFile(fd_t fd) { +  close(fd); +} + +bool ReadFromFile(fd_t fd, void *buff, uptr buff_size, uptr *bytes_read, +                  error_t *error_p) { +  uptr res = read(fd, buff, buff_size); +  if (internal_iserror(res, error_p)) +    return false; +  if (bytes_read) +    *bytes_read = res; +  return true; +} + +bool WriteToFile(fd_t fd, const void *buff, uptr buff_size, uptr *bytes_written, +                 error_t *error_p) { +  uptr res = write(fd, buff, buff_size); +  if (internal_iserror(res, error_p)) +    return false; +  if (bytes_written) +    *bytes_written = res; +  return true; +} + +bool RenameFile(const char *oldpath, const char *newpath, error_t *error_p) { +  uptr res = rename(oldpath, newpath); +  return !internal_iserror(res, error_p); +} + +void ReleaseMemoryPagesToOS(uptr beg, uptr end) {} +void DumpProcessMap() {} + +// There is no page protection so everything is "accessible." +bool IsAccessibleMemoryRange(uptr beg, uptr size) { +  return true; +} + +char **GetArgv() { return nullptr; } + +const char *GetEnv(const char *name) { +  return getenv(name); +} + +uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) { +  internal_strncpy(buf, "StubBinaryName", buf_len); +  return internal_strlen(buf); +} + +uptr ReadLongProcessName(/*out*/ char *buf, uptr buf_len) { +  internal_strncpy(buf, "StubProcessName", buf_len); +  return internal_strlen(buf); +} + +bool IsPathSeparator(const char c) { +  return c == '/'; +} + +bool IsAbsolutePath(const char *path) { +  return path != nullptr && IsPathSeparator(path[0]); +} + +void ReportFile::Write(const char *buffer, uptr length) { +  SpinMutexLock l(mu); +  static const char *kWriteError = +      "ReportFile::Write() can't output requested buffer!\n"; +  ReopenIfNecessary(); +  if (length != write(fd, buffer, length)) { +    write(fd, kWriteError, internal_strlen(kWriteError)); +    Die(); +  } +} + +uptr MainThreadStackBase, MainThreadStackSize; +uptr MainThreadTlsBase, MainThreadTlsSize; + +} // namespace __sanitizer + +#endif  // SANITIZER_RTEMS diff --git a/lib/sanitizer_common/sanitizer_rtems.h b/lib/sanitizer_common/sanitizer_rtems.h new file mode 100644 index 0000000000000..968fa66e1be72 --- /dev/null +++ b/lib/sanitizer_common/sanitizer_rtems.h @@ -0,0 +1,21 @@ +//===-- sanitizer_rtems.h ---------------------------------------*- C++ -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is shared between various sanitizers' runtime libraries and +// provides definitions for RTEMS-specific functions. +//===----------------------------------------------------------------------===// +#ifndef SANITIZER_RTEMS_H +#define SANITIZER_RTEMS_H + +#include "sanitizer_platform.h" +#if SANITIZER_RTEMS +#include "sanitizer_common.h" + +#endif  // SANITIZER_RTEMS +#endif  // SANITIZER_RTEMS_H diff --git a/lib/sanitizer_common/sanitizer_stackdepot.cc b/lib/sanitizer_common/sanitizer_stackdepot.cc index 214dda56df34a..3bd5b677a1f87 100644 --- a/lib/sanitizer_common/sanitizer_stackdepot.cc +++ b/lib/sanitizer_common/sanitizer_stackdepot.cc @@ -135,8 +135,8 @@ bool StackDepotReverseMap::IdDescPair::IdComparator(    return a.id < b.id;  } -StackDepotReverseMap::StackDepotReverseMap() -    : map_(StackDepotGetStats()->n_uniq_ids + 100) { +StackDepotReverseMap::StackDepotReverseMap() { +  map_.reserve(StackDepotGetStats()->n_uniq_ids + 100);    for (int idx = 0; idx < StackDepot::kTabSize; idx++) {      atomic_uintptr_t *p = &theDepot.tab[idx];      uptr v = atomic_load(p, memory_order_consume); @@ -146,7 +146,7 @@ StackDepotReverseMap::StackDepotReverseMap()        map_.push_back(pair);      }    } -  InternalSort(&map_, map_.size(), IdDescPair::IdComparator); +  Sort(map_.data(), map_.size(), &IdDescPair::IdComparator);  }  StackTrace StackDepotReverseMap::Get(u32 id) { diff --git a/lib/sanitizer_common/sanitizer_stacktrace.cc b/lib/sanitizer_common/sanitizer_stacktrace.cc index 2741dde7a3f3d..21976b6b15319 100644 --- a/lib/sanitizer_common/sanitizer_stacktrace.cc +++ b/lib/sanitizer_common/sanitizer_stacktrace.cc @@ -20,7 +20,8 @@ namespace __sanitizer {  uptr StackTrace::GetNextInstructionPc(uptr pc) {  #if defined(__mips__)    return pc + 8; -#elif defined(__powerpc__) +#elif defined(__powerpc__) || defined(__sparc__) || defined(__arm__) || \ +    defined(__aarch64__)    return pc + 4;  #else    return pc + 1; @@ -40,6 +41,9 @@ void BufferedStackTrace::Init(const uptr *pcs, uptr cnt, uptr extra_top_pc) {    top_frame_bp = 0;  } +// Sparc implemention is in its own file. +#if !defined(__sparc__) +  // In GCC on ARM bp points to saved lr, not fp, so we should check the next  // cell in stack to be a saved frame pointer. GetCanonicFrame returns the  // pointer to saved frame pointer in any case. @@ -106,6 +110,8 @@ void BufferedStackTrace::FastUnwindStack(uptr pc, uptr bp, uptr stack_top,    }  } +#endif  // !defined(__sparc__) +  void BufferedStackTrace::PopStackFrames(uptr count) {    CHECK_LT(count, size);    size -= count; diff --git a/lib/sanitizer_common/sanitizer_stacktrace.h b/lib/sanitizer_common/sanitizer_stacktrace.h index f15196e4b7257..562d2e9f737ce 100644 --- a/lib/sanitizer_common/sanitizer_stacktrace.h +++ b/lib/sanitizer_common/sanitizer_stacktrace.h @@ -23,6 +23,8 @@ static const u32 kStackTraceMax = 256;  # define SANITIZER_CAN_FAST_UNWIND 0  #elif SANITIZER_WINDOWS  # define SANITIZER_CAN_FAST_UNWIND 0 +#elif SANITIZER_OPENBSD +# define SANITIZER_CAN_FAST_UNWIND 0  #else  # define SANITIZER_CAN_FAST_UNWIND 1  #endif @@ -30,7 +32,7 @@ static const u32 kStackTraceMax = 256;  // Fast unwind is the only option on Mac for now; we will need to  // revisit this macro when slow unwind works on Mac, see  // https://github.com/google/sanitizers/issues/137 -#if SANITIZER_MAC +#if SANITIZER_MAC || SANITIZER_OPENBSD || SANITIZER_RTEMS  # define SANITIZER_CAN_SLOW_UNWIND 0  #else  # define SANITIZER_CAN_SLOW_UNWIND 1 @@ -73,10 +75,11 @@ struct StackTrace {  ALWAYS_INLINE  uptr StackTrace::GetPreviousInstructionPc(uptr pc) {  #if defined(__arm__) -  // Cancel Thumb bit. -  pc = pc & (~1); -#endif -#if defined(__powerpc__) || defined(__powerpc64__) +  // T32 (Thumb) branch instructions might be 16 or 32 bit long, +  // so we return (pc-2) in that case in order to be safe. +  // For A32 mode we return (pc-4) because all instructions are 32 bit long. +  return (pc - 3) & (~1); +#elif defined(__powerpc__) || defined(__powerpc64__) || defined(__aarch64__)    // PCs are always 4 byte aligned.    return pc - 4;  #elif defined(__sparc__) || defined(__mips__) diff --git a/lib/sanitizer_common/sanitizer_stacktrace_printer.cc b/lib/sanitizer_common/sanitizer_stacktrace_printer.cc index a271302708bed..ac0731d46a6bf 100644 --- a/lib/sanitizer_common/sanitizer_stacktrace_printer.cc +++ b/lib/sanitizer_common/sanitizer_stacktrace_printer.cc @@ -17,8 +17,8 @@  namespace __sanitizer { -// sanitizer_symbolizer_fuchsia.cc implements these differently for Fuchsia. -#if !SANITIZER_FUCHSIA +// sanitizer_symbolizer_markup.cc implements these differently. +#if !SANITIZER_SYMBOLIZER_MARKUP  static const char *StripFunctionName(const char *function, const char *prefix) {    if (!function) return nullptr; @@ -228,7 +228,7 @@ void RenderData(InternalScopedString *buffer, const char *format,    }  } -#endif  // !SANITIZER_FUCHSIA +#endif  // !SANITIZER_SYMBOLIZER_MARKUP  void RenderSourceLocation(InternalScopedString *buffer, const char *file,                            int line, int column, bool vs_style, diff --git a/lib/sanitizer_common/sanitizer_stacktrace_sparc.cc b/lib/sanitizer_common/sanitizer_stacktrace_sparc.cc new file mode 100644 index 0000000000000..9f9920ece80b8 --- /dev/null +++ b/lib/sanitizer_common/sanitizer_stacktrace_sparc.cc @@ -0,0 +1,58 @@ +//===-- sanitizer_stacktrace_sparc.cc -------------------------------------===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is shared between AddressSanitizer and ThreadSanitizer +// run-time libraries. +// +// Implemention of fast stack unwinding for Sparc. +//===----------------------------------------------------------------------===// + +// This file is ported to Sparc v8, but it should be easy to port to +// Sparc v9. +#if defined(__sparcv8__) + +#include "sanitizer_common.h" +#include "sanitizer_stacktrace.h" + +namespace __sanitizer { + +void BufferedStackTrace::FastUnwindStack(uptr pc, uptr bp, uptr stack_top, +                                         uptr stack_bottom, u32 max_depth) { +  const uptr kPageSize = GetPageSizeCached(); +  CHECK_GE(max_depth, 2); +  trace_buffer[0] = pc; +  size = 1; +  if (stack_top < 4096) return;  // Sanity check for stack top. +  // Flush register windows to memory +  asm volatile("ta 3" ::: "memory"); +  uhwptr *frame = (uhwptr*)bp; +  // Lowest possible address that makes sense as the next frame pointer. +  // Goes up as we walk the stack. +  uptr bottom = stack_bottom; +  // Avoid infinite loop when frame == frame[0] by using frame > prev_frame. +  while (IsValidFrame((uptr)frame, stack_top, bottom) && +         IsAligned((uptr)frame, sizeof(*frame)) && +         size < max_depth) { +    uhwptr pc1 = frame[15]; +    // Let's assume that any pointer in the 0th page is invalid and +    // stop unwinding here.  If we're adding support for a platform +    // where this isn't true, we need to reconsider this check. +    if (pc1 < kPageSize) +      break; +    if (pc1 != pc) { +      trace_buffer[size++] = (uptr) pc1; +    } +    bottom = (uptr)frame; +    frame = (uhwptr*)frame[14]; +  } +} + +}  // namespace __sanitizer + +#endif  // !defined(__sparcv8__) diff --git a/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc b/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc index 0f543d2d7c873..fe4fe86daedf6 100644 --- a/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc @@ -88,7 +88,7 @@ namespace __sanitizer {  class SuspendedThreadsListLinux : public SuspendedThreadsList {   public: -  SuspendedThreadsListLinux() : thread_ids_(1024) {} +  SuspendedThreadsListLinux() { thread_ids_.reserve(1024); }    tid_t GetThreadID(uptr index) const;    uptr ThreadCount() const; @@ -209,26 +209,26 @@ void ThreadSuspender::KillAllThreads() {  bool ThreadSuspender::SuspendAllThreads() {    ThreadLister thread_lister(pid_); -  bool added_threads; -  bool first_iteration = true; -  do { -    // Run through the directory entries once. -    added_threads = false; -    pid_t tid = thread_lister.GetNextTID(); -    while (tid >= 0) { -      if (SuspendThread(tid)) -        added_threads = true; -      tid = thread_lister.GetNextTID(); -    } -    if (thread_lister.error() || (first_iteration && !added_threads)) { -      // Detach threads and fail. -      ResumeAllThreads(); -      return false; +  bool retry = true; +  InternalMmapVector<tid_t> threads; +  threads.reserve(128); +  for (int i = 0; i < 30 && retry; ++i) { +    retry = false; +    switch (thread_lister.ListThreads(&threads)) { +      case ThreadLister::Error: +        ResumeAllThreads(); +        return false; +      case ThreadLister::Incomplete: +        retry = true; +        break; +      case ThreadLister::Ok: +        break;      } -    thread_lister.Reset(); -    first_iteration = false; -  } while (added_threads); -  return true; +    for (tid_t tid : threads) +      if (SuspendThread(tid)) +        retry = true; +  }; +  return suspended_threads_list_.ThreadCount();  }  // Pointer to the ThreadSuspender instance for use in signal handler. @@ -295,7 +295,7 @@ static int TracerThread(void* argument) {    thread_suspender_instance = &thread_suspender;    // Alternate stack for signal handling. -  InternalScopedBuffer<char> handler_stack_memory(kHandlerStackSize); +  InternalMmapVector<char> handler_stack_memory(kHandlerStackSize);    stack_t handler_stack;    internal_memset(&handler_stack, 0, sizeof(handler_stack));    handler_stack.ss_sp = handler_stack_memory.data(); diff --git a/lib/sanitizer_common/sanitizer_suppressions.cc b/lib/sanitizer_common/sanitizer_suppressions.cc index 89ddfddd1108f..232171ed5b673 100644 --- a/lib/sanitizer_common/sanitizer_suppressions.cc +++ b/lib/sanitizer_common/sanitizer_suppressions.cc @@ -25,7 +25,7 @@ namespace __sanitizer {  SuppressionContext::SuppressionContext(const char *suppression_types[],                                         int suppression_types_num)      : suppression_types_(suppression_types), -      suppression_types_num_(suppression_types_num), suppressions_(1), +      suppression_types_num_(suppression_types_num),        can_parse_(true) {    CHECK_LE(suppression_types_num_, kMaxSuppressionTypes);    internal_memset(has_suppression_type_, 0, suppression_types_num_); diff --git a/lib/sanitizer_common/sanitizer_symbolizer.h b/lib/sanitizer_common/sanitizer_symbolizer.h index 208362d2f4781..e08eb0d660d5a 100644 --- a/lib/sanitizer_common/sanitizer_symbolizer.h +++ b/lib/sanitizer_common/sanitizer_symbolizer.h @@ -107,7 +107,6 @@ class Symbolizer final {    void Flush();    // Attempts to demangle the provided C++ mangled name.    const char *Demangle(const char *name); -  void PrepareForSandboxing();    // Allow user to install hooks that would be called before/after Symbolizer    // does the actual file/line info fetching. Specific sanitizers may need this @@ -133,8 +132,9 @@ class Symbolizer final {    class ModuleNameOwner {     public:      explicit ModuleNameOwner(BlockingMutex *synchronized_by) -        : storage_(kInitialCapacity), last_match_(nullptr), -          mu_(synchronized_by) {} +        : last_match_(nullptr), mu_(synchronized_by) { +      storage_.reserve(kInitialCapacity); +    }      const char *GetOwnedCopy(const char *str);     private: @@ -158,7 +158,6 @@ class Symbolizer final {    // Platform-specific default demangler, must not return nullptr.    const char *PlatformDemangle(const char *name); -  void PlatformPrepareForSandboxing();    static Symbolizer *symbolizer_;    static StaticSpinMutex init_mu_; diff --git a/lib/sanitizer_common/sanitizer_symbolizer_fuchsia.h b/lib/sanitizer_common/sanitizer_symbolizer_fuchsia.h new file mode 100644 index 0000000000000..3c1c864c0615f --- /dev/null +++ b/lib/sanitizer_common/sanitizer_symbolizer_fuchsia.h @@ -0,0 +1,40 @@ +//===-- sanitizer_symbolizer_fuchsia.h -----------------------------------===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is shared between various sanitizers' runtime libraries. +// +// Define Fuchsia's string formats and limits for the markup symbolizer. +//===----------------------------------------------------------------------===// +#ifndef SANITIZER_SYMBOLIZER_FUCHSIA_H +#define SANITIZER_SYMBOLIZER_FUCHSIA_H + +#include "sanitizer_internal_defs.h" + +namespace __sanitizer { + +// See the spec at: +// https://fuchsia.googlesource.com/zircon/+/master/docs/symbolizer_markup.md + +// This is used by UBSan for type names, and by ASan for global variable names. +constexpr const char *kFormatDemangle = "{{{symbol:%s}}}"; +constexpr uptr kFormatDemangleMax = 1024;  // Arbitrary. + +// Function name or equivalent from PC location. +constexpr const char *kFormatFunction = "{{{pc:%p}}}"; +constexpr uptr kFormatFunctionMax = 64;  // More than big enough for 64-bit hex. + +// Global variable name or equivalent from data memory address. +constexpr const char *kFormatData = "{{{data:%p}}}"; + +// One frame in a backtrace (printed on a line by itself). +constexpr const char *kFormatFrame = "{{{bt:%u:%p}}}"; + +}  // namespace __sanitizer + +#endif  // SANITIZER_SYMBOLIZER_FUCHSIA_H diff --git a/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc b/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc index a4bab668b27af..f2ee7baad837e 100644 --- a/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc @@ -26,8 +26,8 @@ Symbolizer *Symbolizer::GetOrInit() {    return symbolizer_;  } -// See sanitizer_symbolizer_fuchsia.cc. -#if !SANITIZER_FUCHSIA +// See sanitizer_symbolizer_markup.cc. +#if !SANITIZER_SYMBOLIZER_MARKUP  const char *ExtractToken(const char *str, const char *delims, char **result) {    uptr prefix_len = internal_strcspn(str, delims); @@ -145,11 +145,6 @@ const char *Symbolizer::Demangle(const char *name) {    return PlatformDemangle(name);  } -void Symbolizer::PrepareForSandboxing() { -  BlockingMutexLock l(&mu_); -  PlatformPrepareForSandboxing(); -} -  bool Symbolizer::FindModuleNameAndOffsetForAddress(uptr address,                                                     const char **module_name,                                                     uptr *module_offset, @@ -494,6 +489,6 @@ bool SymbolizerProcess::WriteToSymbolizer(const char *buffer, uptr length) {    return true;  } -#endif  // !SANITIZER_FUCHSIA +#endif  // !SANITIZER_SYMBOLIZER_MARKUP  }  // namespace __sanitizer diff --git a/lib/sanitizer_common/sanitizer_symbolizer_fuchsia.cc b/lib/sanitizer_common/sanitizer_symbolizer_markup.cc index 3d1117d9d3cae..c62dc90fabbad 100644 --- a/lib/sanitizer_common/sanitizer_symbolizer_fuchsia.cc +++ b/lib/sanitizer_common/sanitizer_symbolizer_markup.cc @@ -1,4 +1,4 @@ -//===-- sanitizer_symbolizer_fuchsia.cc -----------------------------------===// +//===-- sanitizer_symbolizer_markup.cc ------------------------------------===//  //  //                     The LLVM Compiler Infrastructure  // @@ -9,18 +9,27 @@  //  // This file is shared between various sanitizers' runtime libraries.  // -// Implementation of Fuchsia-specific symbolizer. +// Implementation of offline markup symbolizer.  //===----------------------------------------------------------------------===//  #include "sanitizer_platform.h" -#if SANITIZER_FUCHSIA +#if SANITIZER_SYMBOLIZER_MARKUP -#include "sanitizer_fuchsia.h" +#if SANITIZER_FUCHSIA +#include "sanitizer_symbolizer_fuchsia.h" +#elif SANITIZER_RTEMS +#include "sanitizer_symbolizer_rtems.h" +#endif +#include "sanitizer_stacktrace.h"  #include "sanitizer_symbolizer.h" +#include <limits.h> +#include <unwind.h> +  namespace __sanitizer { -// For Fuchsia we don't do any actual symbolization per se. +// This generic support for offline symbolizing is based on the +// Fuchsia port.  We don't do any actual symbolization per se.  // Instead, we emit text containing raw addresses and raw linkage  // symbol names, embedded in Fuchsia's symbolization markup format.  // Fuchsia's logging infrastructure emits enough information about @@ -29,20 +38,6 @@ namespace __sanitizer {  // https://fuchsia.googlesource.com/zircon/+/master/docs/symbolizer_markup.md  // This is used by UBSan for type names, and by ASan for global variable names. -constexpr const char *kFormatDemangle = "{{{symbol:%s}}}"; -constexpr uptr kFormatDemangleMax = 1024;  // Arbitrary. - -// Function name or equivalent from PC location. -constexpr const char *kFormatFunction = "{{{pc:%p}}}"; -constexpr uptr kFormatFunctionMax = 64;  // More than big enough for 64-bit hex. - -// Global variable name or equivalent from data memory address. -constexpr const char *kFormatData = "{{{data:%p}}}"; - -// One frame in a backtrace (printed on a line by itself). -constexpr const char *kFormatFrame = "{{{bt:%u:%p}}}"; - -// This is used by UBSan for type names, and by ASan for global variable names.  // It's expected to return a static buffer that will be reused on each call.  const char *Symbolizer::Demangle(const char *name) {    static char buffer[kFormatDemangleMax]; @@ -102,6 +97,49 @@ Symbolizer *Symbolizer::PlatformInit() {  void Symbolizer::LateInitialize() { Symbolizer::GetOrInit(); } +void StartReportDeadlySignal() {} +void ReportDeadlySignal(const SignalContext &sig, u32 tid, +                        UnwindSignalStackCallbackType unwind, +                        const void *unwind_context) {} + +#if SANITIZER_CAN_SLOW_UNWIND +struct UnwindTraceArg { +  BufferedStackTrace *stack; +  u32 max_depth; +}; + +_Unwind_Reason_Code Unwind_Trace(struct _Unwind_Context *ctx, void *param) { +  UnwindTraceArg *arg = static_cast<UnwindTraceArg *>(param); +  CHECK_LT(arg->stack->size, arg->max_depth); +  uptr pc = _Unwind_GetIP(ctx); +  if (pc < PAGE_SIZE) return _URC_NORMAL_STOP; +  arg->stack->trace_buffer[arg->stack->size++] = pc; +  return (arg->stack->size == arg->max_depth ? _URC_NORMAL_STOP +                                             : _URC_NO_REASON); +} + +void BufferedStackTrace::SlowUnwindStack(uptr pc, u32 max_depth) { +  CHECK_GE(max_depth, 2); +  size = 0; +  UnwindTraceArg arg = {this, Min(max_depth + 1, kStackTraceMax)}; +  _Unwind_Backtrace(Unwind_Trace, &arg); +  CHECK_GT(size, 0); +  // We need to pop a few frames so that pc is on top. +  uptr to_pop = LocatePcInTrace(pc); +  // trace_buffer[0] belongs to the current function so we always pop it, +  // unless there is only 1 frame in the stack trace (1 frame is always better +  // than 0!). +  PopStackFrames(Min(to_pop, static_cast<uptr>(1))); +  trace_buffer[0] = pc; +} + +void BufferedStackTrace::SlowUnwindStackWithContext(uptr pc, void *context, +                                                    u32 max_depth) { +  CHECK_NE(context, nullptr); +  UNREACHABLE("signal context doesn't exist"); +} +#endif  // SANITIZER_CAN_SLOW_UNWIND +  }  // namespace __sanitizer -#endif  // SANITIZER_FUCHSIA +#endif  // SANITIZER_SYMBOLIZER_MARKUP diff --git a/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc b/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc index 71d748d0515fe..d74a6f44ee6bf 100644 --- a/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc @@ -315,8 +315,9 @@ class Addr2LinePool : public SymbolizerTool {   public:    explicit Addr2LinePool(const char *addr2line_path,                           LowLevelAllocator *allocator) -      : addr2line_path_(addr2line_path), allocator_(allocator), -        addr2line_pool_(16) {} +      : addr2line_path_(addr2line_path), allocator_(allocator) { +    addr2line_pool_.reserve(16); +  }    bool SymbolizePC(uptr addr, SymbolizedStack *stack) override {      if (const char *buf = @@ -445,8 +446,6 @@ const char *Symbolizer::PlatformDemangle(const char *name) {    return DemangleSwiftAndCXX(name);  } -void Symbolizer::PlatformPrepareForSandboxing() {} -  static SymbolizerTool *ChooseExternalSymbolizer(LowLevelAllocator *allocator) {    const char *path = common_flags()->external_symbolizer_path;    const char *binary_name = path ? StripModuleName(path) : ""; diff --git a/lib/sanitizer_common/sanitizer_symbolizer_report.cc b/lib/sanitizer_common/sanitizer_symbolizer_report.cc new file mode 100644 index 0000000000000..fd26d4cfa0795 --- /dev/null +++ b/lib/sanitizer_common/sanitizer_symbolizer_report.cc @@ -0,0 +1,282 @@ +//===-- sanitizer_symbolizer_report.cc ------------------------------------===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// This file is shared between AddressSanitizer and other sanitizer run-time +/// libraries and implements symbolized reports related functions. +/// +//===----------------------------------------------------------------------===// + +#include "sanitizer_common.h" +#include "sanitizer_file.h" +#include "sanitizer_flags.h" +#include "sanitizer_procmaps.h" +#include "sanitizer_report_decorator.h" +#include "sanitizer_stacktrace.h" +#include "sanitizer_stacktrace_printer.h" +#include "sanitizer_symbolizer.h" + +#if SANITIZER_POSIX +# include "sanitizer_posix.h" +# include <sys/mman.h> +#endif + +namespace __sanitizer { + +#if !SANITIZER_GO +void ReportErrorSummary(const char *error_type, const AddressInfo &info, +                        const char *alt_tool_name) { +  if (!common_flags()->print_summary) return; +  InternalScopedString buff(kMaxSummaryLength); +  buff.append("%s ", error_type); +  RenderFrame(&buff, "%L %F", 0, info, common_flags()->symbolize_vs_style, +              common_flags()->strip_path_prefix); +  ReportErrorSummary(buff.data(), alt_tool_name); +} +#endif + +#if !SANITIZER_FUCHSIA + +bool ReportFile::SupportsColors() { +  SpinMutexLock l(mu); +  ReopenIfNecessary(); +  return SupportsColoredOutput(fd); +} + +static INLINE bool ReportSupportsColors() { +  return report_file.SupportsColors(); +} + +#else  // SANITIZER_FUCHSIA + +// Fuchsia's logs always go through post-processing that handles colorization. +static INLINE bool ReportSupportsColors() { return true; } + +#endif  // !SANITIZER_FUCHSIA + +bool ColorizeReports() { +  // FIXME: Add proper Windows support to AnsiColorDecorator and re-enable color +  // printing on Windows. +  if (SANITIZER_WINDOWS) +    return false; + +  const char *flag = common_flags()->color; +  return internal_strcmp(flag, "always") == 0 || +         (internal_strcmp(flag, "auto") == 0 && ReportSupportsColors()); +} + +void ReportErrorSummary(const char *error_type, const StackTrace *stack, +                        const char *alt_tool_name) { +#if !SANITIZER_GO +  if (!common_flags()->print_summary) +    return; +  if (stack->size == 0) { +    ReportErrorSummary(error_type); +    return; +  } +  // Currently, we include the first stack frame into the report summary. +  // Maybe sometimes we need to choose another frame (e.g. skip memcpy/etc). +  uptr pc = StackTrace::GetPreviousInstructionPc(stack->trace[0]); +  SymbolizedStack *frame = Symbolizer::GetOrInit()->SymbolizePC(pc); +  ReportErrorSummary(error_type, frame->info, alt_tool_name); +  frame->ClearAll(); +#endif +} + +void ReportMmapWriteExec(int prot) { +#if SANITIZER_POSIX && (!SANITIZER_GO && !SANITIZER_ANDROID) +  if ((prot & (PROT_WRITE | PROT_EXEC)) != (PROT_WRITE | PROT_EXEC)) +    return; + +  ScopedErrorReportLock l; +  SanitizerCommonDecorator d; + +  InternalMmapVector<BufferedStackTrace> stack_buffer(1); +  BufferedStackTrace *stack = stack_buffer.data(); +  stack->Reset(); +  uptr top = 0; +  uptr bottom = 0; +  GET_CALLER_PC_BP_SP; +  (void)sp; +  bool fast = common_flags()->fast_unwind_on_fatal; +  if (fast) +    GetThreadStackTopAndBottom(false, &top, &bottom); +  stack->Unwind(kStackTraceMax, pc, bp, nullptr, top, bottom, fast); + +  Printf("%s", d.Warning()); +  Report("WARNING: %s: writable-executable page usage\n", SanitizerToolName); +  Printf("%s", d.Default()); + +  stack->Print(); +  ReportErrorSummary("w-and-x-usage", stack); +#endif +} + +#if !SANITIZER_FUCHSIA && !SANITIZER_RTEMS && !SANITIZER_GO +void StartReportDeadlySignal() { +  // Write the first message using fd=2, just in case. +  // It may actually fail to write in case stderr is closed. +  CatastrophicErrorWrite(SanitizerToolName, internal_strlen(SanitizerToolName)); +  static const char kDeadlySignal[] = ":DEADLYSIGNAL\n"; +  CatastrophicErrorWrite(kDeadlySignal, sizeof(kDeadlySignal) - 1); +} + +static void MaybeReportNonExecRegion(uptr pc) { +#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD +  MemoryMappingLayout proc_maps(/*cache_enabled*/ true); +  MemoryMappedSegment segment; +  while (proc_maps.Next(&segment)) { +    if (pc >= segment.start && pc < segment.end && !segment.IsExecutable()) +      Report("Hint: PC is at a non-executable region. Maybe a wild jump?\n"); +  } +#endif +} + +static void PrintMemoryByte(InternalScopedString *str, const char *before, +                            u8 byte) { +  SanitizerCommonDecorator d; +  str->append("%s%s%x%x%s ", before, d.MemoryByte(), byte >> 4, byte & 15, +              d.Default()); +} + +static void MaybeDumpInstructionBytes(uptr pc) { +  if (!common_flags()->dump_instruction_bytes || (pc < GetPageSizeCached())) +    return; +  InternalScopedString str(1024); +  str.append("First 16 instruction bytes at pc: "); +  if (IsAccessibleMemoryRange(pc, 16)) { +    for (int i = 0; i < 16; ++i) { +      PrintMemoryByte(&str, "", ((u8 *)pc)[i]); +    } +    str.append("\n"); +  } else { +    str.append("unaccessible\n"); +  } +  Report("%s", str.data()); +} + +static void MaybeDumpRegisters(void *context) { +  if (!common_flags()->dump_registers) return; +  SignalContext::DumpAllRegisters(context); +} + +static void ReportStackOverflowImpl(const SignalContext &sig, u32 tid, +                                    UnwindSignalStackCallbackType unwind, +                                    const void *unwind_context) { +  SanitizerCommonDecorator d; +  Printf("%s", d.Warning()); +  static const char kDescription[] = "stack-overflow"; +  Report("ERROR: %s: %s on address %p (pc %p bp %p sp %p T%d)\n", +         SanitizerToolName, kDescription, (void *)sig.addr, (void *)sig.pc, +         (void *)sig.bp, (void *)sig.sp, tid); +  Printf("%s", d.Default()); +  InternalMmapVector<BufferedStackTrace> stack_buffer(1); +  BufferedStackTrace *stack = stack_buffer.data(); +  stack->Reset(); +  unwind(sig, unwind_context, stack); +  stack->Print(); +  ReportErrorSummary(kDescription, stack); +} + +static void ReportDeadlySignalImpl(const SignalContext &sig, u32 tid, +                                   UnwindSignalStackCallbackType unwind, +                                   const void *unwind_context) { +  SanitizerCommonDecorator d; +  Printf("%s", d.Warning()); +  const char *description = sig.Describe(); +  Report("ERROR: %s: %s on unknown address %p (pc %p bp %p sp %p T%d)\n", +         SanitizerToolName, description, (void *)sig.addr, (void *)sig.pc, +         (void *)sig.bp, (void *)sig.sp, tid); +  Printf("%s", d.Default()); +  if (sig.pc < GetPageSizeCached()) +    Report("Hint: pc points to the zero page.\n"); +  if (sig.is_memory_access) { +    const char *access_type = +        sig.write_flag == SignalContext::WRITE +            ? "WRITE" +            : (sig.write_flag == SignalContext::READ ? "READ" : "UNKNOWN"); +    Report("The signal is caused by a %s memory access.\n", access_type); +    if (sig.addr < GetPageSizeCached()) +      Report("Hint: address points to the zero page.\n"); +  } +  MaybeReportNonExecRegion(sig.pc); +  InternalMmapVector<BufferedStackTrace> stack_buffer(1); +  BufferedStackTrace *stack = stack_buffer.data(); +  stack->Reset(); +  unwind(sig, unwind_context, stack); +  stack->Print(); +  MaybeDumpInstructionBytes(sig.pc); +  MaybeDumpRegisters(sig.context); +  Printf("%s can not provide additional info.\n", SanitizerToolName); +  ReportErrorSummary(description, stack); +} + +void ReportDeadlySignal(const SignalContext &sig, u32 tid, +                        UnwindSignalStackCallbackType unwind, +                        const void *unwind_context) { +  if (sig.IsStackOverflow()) +    ReportStackOverflowImpl(sig, tid, unwind, unwind_context); +  else +    ReportDeadlySignalImpl(sig, tid, unwind, unwind_context); +} + +void HandleDeadlySignal(void *siginfo, void *context, u32 tid, +                        UnwindSignalStackCallbackType unwind, +                        const void *unwind_context) { +  StartReportDeadlySignal(); +  ScopedErrorReportLock rl; +  SignalContext sig(siginfo, context); +  ReportDeadlySignal(sig, tid, unwind, unwind_context); +  Report("ABORTING\n"); +  Die(); +} + +#endif  // !SANITIZER_FUCHSIA && !SANITIZER_GO + +static atomic_uintptr_t reporting_thread = {0}; +static StaticSpinMutex CommonSanitizerReportMutex; + +ScopedErrorReportLock::ScopedErrorReportLock() { +  uptr current = GetThreadSelf(); +  for (;;) { +    uptr expected = 0; +    if (atomic_compare_exchange_strong(&reporting_thread, &expected, current, +                                       memory_order_relaxed)) { +      // We've claimed reporting_thread so proceed. +      CommonSanitizerReportMutex.Lock(); +      return; +    } + +    if (expected == current) { +      // This is either asynch signal or nested error during error reporting. +      // Fail simple to avoid deadlocks in Report(). + +      // Can't use Report() here because of potential deadlocks in nested +      // signal handlers. +      CatastrophicErrorWrite(SanitizerToolName, +                             internal_strlen(SanitizerToolName)); +      static const char msg[] = ": nested bug in the same thread, aborting.\n"; +      CatastrophicErrorWrite(msg, sizeof(msg) - 1); + +      internal__exit(common_flags()->exitcode); +    } + +    internal_sched_yield(); +  } +} + +ScopedErrorReportLock::~ScopedErrorReportLock() { +  CommonSanitizerReportMutex.Unlock(); +  atomic_store_relaxed(&reporting_thread, 0); +} + +void ScopedErrorReportLock::CheckLocked() { +  CommonSanitizerReportMutex.CheckLocked(); +} + +}  // namespace __sanitizer diff --git a/lib/sanitizer_common/sanitizer_symbolizer_rtems.h b/lib/sanitizer_common/sanitizer_symbolizer_rtems.h new file mode 100644 index 0000000000000..62356ef6ef734 --- /dev/null +++ b/lib/sanitizer_common/sanitizer_symbolizer_rtems.h @@ -0,0 +1,41 @@ +//===-- sanitizer_symbolizer_rtems.h -----------------------------------===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is shared between various sanitizers' runtime libraries. +// +// Define RTEMS's string formats and limits for the markup symbolizer. +//===----------------------------------------------------------------------===// +#ifndef SANITIZER_SYMBOLIZER_RTEMS_H +#define SANITIZER_SYMBOLIZER_RTEMS_H + +#include "sanitizer_internal_defs.h" + +namespace __sanitizer { + +// The Myriad RTEMS symbolizer currently only parses backtrace lines, +// so use a format that the symbolizer understands.  For other +// markups, keep them the same as the Fuchsia's. + +// This is used by UBSan for type names, and by ASan for global variable names. +constexpr const char *kFormatDemangle = "{{{symbol:%s}}}"; +constexpr uptr kFormatDemangleMax = 1024;  // Arbitrary. + +// Function name or equivalent from PC location. +constexpr const char *kFormatFunction = "{{{pc:%p}}}"; +constexpr uptr kFormatFunctionMax = 64;  // More than big enough for 64-bit hex. + +// Global variable name or equivalent from data memory address. +constexpr const char *kFormatData = "{{{data:%p}}}"; + +// One frame in a backtrace (printed on a line by itself). +constexpr const char *kFormatFrame = "    [%u] IP: %p"; + +}  // namespace __sanitizer + +#endif  // SANITIZER_SYMBOLIZER_RTEMS_H diff --git a/lib/sanitizer_common/sanitizer_symbolizer_win.cc b/lib/sanitizer_common/sanitizer_symbolizer_win.cc index 135823b157de6..6ec75831a6335 100644 --- a/lib/sanitizer_common/sanitizer_symbolizer_win.cc +++ b/lib/sanitizer_common/sanitizer_symbolizer_win.cc @@ -176,10 +176,6 @@ const char *Symbolizer::PlatformDemangle(const char *name) {    return name;  } -void Symbolizer::PlatformPrepareForSandboxing() { -  // Do nothing. -} -  namespace {  struct ScopedHandle {    ScopedHandle() : h_(nullptr) {} diff --git a/lib/sanitizer_common/sanitizer_syscall_generic.inc b/lib/sanitizer_common/sanitizer_syscall_generic.inc index 3c8e77867ce58..e4ed1b4deee04 100644 --- a/lib/sanitizer_common/sanitizer_syscall_generic.inc +++ b/lib/sanitizer_common/sanitizer_syscall_generic.inc @@ -11,7 +11,8 @@  //  //===----------------------------------------------------------------------===// -#if SANITIZER_FREEBSD || SANITIZER_MAC || SANITIZER_NETBSD || SANITIZER_SOLARIS +#if SANITIZER_FREEBSD || SANITIZER_MAC || SANITIZER_NETBSD || \ +  SANITIZER_OPENBSD || SANITIZER_SOLARIS  # define SYSCALL(name) SYS_ ## name  #else  # define SYSCALL(name) __NR_ ## name diff --git a/lib/sanitizer_common/sanitizer_syscalls_netbsd.inc b/lib/sanitizer_common/sanitizer_syscalls_netbsd.inc new file mode 100644 index 0000000000000..4f766100813d3 --- /dev/null +++ b/lib/sanitizer_common/sanitizer_syscalls_netbsd.inc @@ -0,0 +1,3786 @@ +//===-- sanitizer_syscalls_netbsd.inc ---------------------------*- C++ -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Common syscalls handlers for tools like AddressSanitizer, +// ThreadSanitizer, MemorySanitizer, etc. +// +// This file should be included into the tool's interceptor file, +// which has to define it's own macros: +//   COMMON_SYSCALL_PRE_READ_RANGE +//          Called in prehook for regions that will be read by the kernel and +//          must be initialized. +//   COMMON_SYSCALL_PRE_WRITE_RANGE +//          Called in prehook for regions that will be written to by the kernel +//          and must be addressable. The actual write range may be smaller than +//          reported in the prehook. See POST_WRITE_RANGE. +//   COMMON_SYSCALL_POST_READ_RANGE +//          Called in posthook for regions that were read by the kernel. Does +//          not make much sense. +//   COMMON_SYSCALL_POST_WRITE_RANGE +//          Called in posthook for regions that were written to by the kernel +//          and are now initialized. +//   COMMON_SYSCALL_ACQUIRE(addr) +//          Acquire memory visibility from addr. +//   COMMON_SYSCALL_RELEASE(addr) +//          Release memory visibility to addr. +//   COMMON_SYSCALL_FD_CLOSE(fd) +//          Called before closing file descriptor fd. +//   COMMON_SYSCALL_FD_ACQUIRE(fd) +//          Acquire memory visibility from fd. +//   COMMON_SYSCALL_FD_RELEASE(fd) +//          Release memory visibility to fd. +//   COMMON_SYSCALL_PRE_FORK() +//          Called before fork syscall. +//   COMMON_SYSCALL_POST_FORK(long long res) +//          Called after fork syscall. +// +// DO NOT EDIT! THIS FILE HAS BEEN GENERATED! +// +// Generated with: generate_netbsd_syscalls.awk +// Generated date: 2018-03-03 +// Generated from: syscalls.master,v 1.291 2018/01/06 16:41:23 kamil Exp +// +//===----------------------------------------------------------------------===// + +#include "sanitizer_platform.h" +#if SANITIZER_NETBSD + +#include "sanitizer_libc.h" + +#define PRE_SYSCALL(name)                                                      \ +  SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_syscall_pre_impl_##name +#define PRE_READ(p, s) COMMON_SYSCALL_PRE_READ_RANGE(p, s) +#define PRE_WRITE(p, s) COMMON_SYSCALL_PRE_WRITE_RANGE(p, s) + +#define POST_SYSCALL(name)                                                     \ +  SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_syscall_post_impl_##name +#define POST_READ(p, s) COMMON_SYSCALL_POST_READ_RANGE(p, s) +#define POST_WRITE(p, s) COMMON_SYSCALL_POST_WRITE_RANGE(p, s) + +#ifndef COMMON_SYSCALL_ACQUIRE +#define COMMON_SYSCALL_ACQUIRE(addr) ((void)(addr)) +#endif + +#ifndef COMMON_SYSCALL_RELEASE +#define COMMON_SYSCALL_RELEASE(addr) ((void)(addr)) +#endif + +#ifndef COMMON_SYSCALL_FD_CLOSE +#define COMMON_SYSCALL_FD_CLOSE(fd) ((void)(fd)) +#endif + +#ifndef COMMON_SYSCALL_FD_ACQUIRE +#define COMMON_SYSCALL_FD_ACQUIRE(fd) ((void)(fd)) +#endif + +#ifndef COMMON_SYSCALL_FD_RELEASE +#define COMMON_SYSCALL_FD_RELEASE(fd) ((void)(fd)) +#endif + +#ifndef COMMON_SYSCALL_PRE_FORK +#define COMMON_SYSCALL_PRE_FORK()                                              \ +  {} +#endif + +#ifndef COMMON_SYSCALL_POST_FORK +#define COMMON_SYSCALL_POST_FORK(res)                                          \ +  {} +#endif + +// FIXME: do some kind of PRE_READ for all syscall arguments (int(s) and such). + +extern "C" { +#define SYS_MAXSYSARGS 8 +PRE_SYSCALL(syscall)(long long code_, long long args_[SYS_MAXSYSARGS]) { +  /* Nothing to do */ +} +POST_SYSCALL(syscall) +(long long res, long long code_, long long args_[SYS_MAXSYSARGS]) { +  /* Nothing to do */ +} +PRE_SYSCALL(exit)(long long rval_) { /* Nothing to do */ } +POST_SYSCALL(exit)(long long res, long long rval_) { /* Nothing to do */ } +PRE_SYSCALL(fork)(void) { COMMON_SYSCALL_PRE_FORK(); } +POST_SYSCALL(fork)(long long res) { COMMON_SYSCALL_POST_FORK(res); } +PRE_SYSCALL(read)(long long fd_, void *buf_, long long nbyte_) { +  if (buf_) { +    PRE_WRITE(buf_, nbyte_); +  } +} +POST_SYSCALL(read)(long long res, long long fd_, void *buf_, long long nbyte_) { +  if (res > 0) { +    POST_WRITE(buf_, res); +  } +} +PRE_SYSCALL(write)(long long fd_, void *buf_, long long nbyte_) { +  if (buf_) { +    PRE_READ(buf_, nbyte_); +  } +} +POST_SYSCALL(write) +(long long res, long long fd_, void *buf_, long long nbyte_) { +  if (res > 0) { +    POST_READ(buf_, res); +  } +} +PRE_SYSCALL(open)(void *path_, long long flags_, long long mode_) { +  const char *path = (const char *)path_; +  if (path) { +    PRE_READ(path, __sanitizer::internal_strlen(path) + 1); +  } +} +POST_SYSCALL(open) +(long long res, void *path_, long long flags_, long long mode_) { +  if (res > 0) { +    const char *path = (const char *)path_; +    if (path) { +      POST_READ(path, __sanitizer::internal_strlen(path) + 1); +    } +  } +} +PRE_SYSCALL(close)(long long fd_) { COMMON_SYSCALL_FD_CLOSE((int)fd_); } +POST_SYSCALL(close)(long long res, long long fd_) { /* Nothing to do */ } +PRE_SYSCALL(compat_50_wait4) +(long long pid_, void *status_, long long options_, void *rusage_) { +  /* TODO */ +} +POST_SYSCALL(compat_50_wait4) +(long long res, long long pid_, void *status_, long long options_, +  void *rusage_) { +  /* TODO */ +} +PRE_SYSCALL(compat_43_ocreat)(void *path_, long long mode_) { /* TODO */ } +POST_SYSCALL(compat_43_ocreat)(long long res, void *path_, long long mode_) { +  /* TODO */ +} +PRE_SYSCALL(link)(void *path_, void *link_) { +  const char *path = (const char *)path_; +  const char *link = (const char *)link_; +  if (path) { +    PRE_READ(path, __sanitizer::internal_strlen(path) + 1); +  } +  if (link) { +    PRE_READ(path, __sanitizer::internal_strlen(link) + 1); +  } +} +POST_SYSCALL(link)(long long res, void *path_, void *link_) { +  if (res == 0) { +    const char *path = (const char *)path_; +    const char *link = (const char *)link_; +    if (path) { +      POST_READ(path, __sanitizer::internal_strlen(path) + 1); +    } +    if (link) { +      POST_READ(path, __sanitizer::internal_strlen(link) + 1); +    } +  } +} +PRE_SYSCALL(unlink)(void *path_) { +  const char *path = (const char *)path_; +  if (path) { +    PRE_READ(path, __sanitizer::internal_strlen(path) + 1); +  } +} +POST_SYSCALL(unlink)(long long res, void *path_) { +  if (res == 0) { +    const char *path = (const char *)path_; +    if (path) { +      POST_READ(path, __sanitizer::internal_strlen(path) + 1); +    } +  } +} +/* syscall 11 has been skipped */ +PRE_SYSCALL(chdir)(void *path_) { +  const char *path = (const char *)path_; +  if (path) { +    PRE_READ(path, __sanitizer::internal_strlen(path) + 1); +  } +} +POST_SYSCALL(chdir)(long long res, void *path_) { +  if (res == 0) { +    const char *path = (const char *)path_; +    if (path) { +      POST_READ(path, __sanitizer::internal_strlen(path) + 1); +    } +  } +} +PRE_SYSCALL(fchdir)(long long fd_) { /* Nothing to do */ } +POST_SYSCALL(fchdir)(long long res, long long fd_) { /* Nothing to do */ } +PRE_SYSCALL(compat_50_mknod)(void *path_, long long mode_, long long dev_) { +  /* TODO */ +} +POST_SYSCALL(compat_50_mknod) +(long long res, void *path_, long long mode_, long long dev_) { +  /* TODO */ +} +PRE_SYSCALL(chmod)(void *path_, long long mode_) { +  const char *path = (const char *)path_; +  if (path) { +    PRE_READ(path, __sanitizer::internal_strlen(path) + 1); +  } +} +POST_SYSCALL(chmod)(long long res, void *path_, long long mode_) { +  if (res == 0) { +    const char *path = (const char *)path_; +    if (path) { +      POST_READ(path, __sanitizer::internal_strlen(path) + 1); +    } +  } +} +PRE_SYSCALL(chown)(void *path_, long long uid_, long long gid_) { +  const char *path = (const char *)path_; +  if (path) { +    PRE_READ(path, __sanitizer::internal_strlen(path) + 1); +  } +} +POST_SYSCALL(chown) +(long long res, void *path_, long long uid_, long long gid_) { +  if (res == 0) { +    const char *path = (const char *)path_; +    if (path) { +      POST_READ(path, __sanitizer::internal_strlen(path) + 1); +    } +  } +} +PRE_SYSCALL(break)(void *nsize_) { /* Nothing to do */ } +POST_SYSCALL(break)(long long res, void *nsize_) { /* Nothing to do */ } +PRE_SYSCALL(compat_20_getfsstat) +(void *buf_, long long bufsize_, long long flags_) { +  /* TODO */ +} +POST_SYSCALL(compat_20_getfsstat) +(long long res, void *buf_, long long bufsize_, long long flags_) { +  /* TODO */ +} +PRE_SYSCALL(compat_43_olseek) +(long long fd_, long long offset_, long long whence_) { +  /* TODO */ +} +POST_SYSCALL(compat_43_olseek) +(long long res, long long fd_, long long offset_, long long whence_) { +  /* TODO */ +} +PRE_SYSCALL(getpid)(void) { /* Nothing to do */ } +POST_SYSCALL(getpid)(long long res) { /* Nothing to do */ } +PRE_SYSCALL(compat_40_mount) +(void *type_, void *path_, long long flags_, void *data_) { +  /* TODO */ +} +POST_SYSCALL(compat_40_mount) +(long long res, void *type_, void *path_, long long flags_, void *data_) { +  /* TODO */ +} +PRE_SYSCALL(unmount)(void *path_, long long flags_) { +  const char *path = (const char *)path_; +  if (path) { +    PRE_READ(path, __sanitizer::internal_strlen(path) + 1); +  } +} +POST_SYSCALL(unmount)(long long res, void *path_, long long flags_) { +  if (res == 0) { +    const char *path = (const char *)path_; +    if (path) { +      POST_READ(path, __sanitizer::internal_strlen(path) + 1); +    } +  } +} +PRE_SYSCALL(setuid)(long long uid_) { /* Nothing to do */ } +POST_SYSCALL(setuid)(long long res, long long uid_) { /* Nothing to do */ } +PRE_SYSCALL(getuid)(void) { /* Nothing to do */ } +POST_SYSCALL(getuid)(long long res) { /* Nothing to do */ } +PRE_SYSCALL(geteuid)(void) { /* Nothing to do */ } +POST_SYSCALL(geteuid)(long long res) { /* Nothing to do */ } +PRE_SYSCALL(ptrace) +(long long req_, long long pid_, void *addr_, long long data_) { +  if (req_ == ptrace_pt_io) { +    struct __sanitizer_ptrace_io_desc *addr = +        (struct __sanitizer_ptrace_io_desc *)addr_; +    PRE_READ(addr, struct_ptrace_ptrace_io_desc_struct_sz); +    if (addr->piod_op == ptrace_piod_write_d || +        addr->piod_op == ptrace_piod_write_i) { +      PRE_READ(addr->piod_addr, addr->piod_len); +    } +    if (addr->piod_op == ptrace_piod_read_d || +        addr->piod_op == ptrace_piod_read_i || +        addr->piod_op == ptrace_piod_read_auxv) { +      PRE_WRITE(addr->piod_addr, addr->piod_len); +    } +  } else if (req_ == ptrace_pt_lwpinfo) { +    struct __sanitizer_ptrace_lwpinfo *addr = +        (struct __sanitizer_ptrace_lwpinfo *)addr_; +    PRE_READ(&addr->pl_lwpid, sizeof(__sanitizer_lwpid_t)); +    PRE_WRITE(addr, struct_ptrace_ptrace_lwpinfo_struct_sz); +  } else if (req_ == ptrace_pt_set_event_mask) { +    PRE_READ(addr_, struct_ptrace_ptrace_event_struct_sz); +  } else if (req_ == ptrace_pt_get_event_mask) { +    PRE_WRITE(addr_, struct_ptrace_ptrace_event_struct_sz); +  } else if (req_ == ptrace_pt_set_siginfo) { +    PRE_READ(addr_, struct_ptrace_ptrace_siginfo_struct_sz); +  } else if (req_ == ptrace_pt_get_siginfo) { +    PRE_WRITE(addr_, struct_ptrace_ptrace_siginfo_struct_sz); +  } else if (req_ == ptrace_pt_setregs) { +    PRE_READ(addr_, struct_ptrace_reg_struct_sz); +  } else if (req_ == ptrace_pt_getregs) { +    PRE_WRITE(addr_, struct_ptrace_reg_struct_sz); +  } else if (req_ == ptrace_pt_setfpregs) { +    PRE_READ(addr_, struct_ptrace_fpreg_struct_sz); +  } else if (req_ == ptrace_pt_getfpregs) { +    PRE_WRITE(addr_, struct_ptrace_fpreg_struct_sz); +  } else if (req_ == ptrace_pt_setdbregs) { +    PRE_READ(addr_, struct_ptrace_dbreg_struct_sz); +  } else if (req_ == ptrace_pt_getdbregs) { +    PRE_WRITE(addr_, struct_ptrace_dbreg_struct_sz); +  } +} +POST_SYSCALL(ptrace) +(long long res, long long req_, long long pid_, void *addr_, long long data_) { +  if (res == 0) { +    if (req_ == ptrace_pt_io) { +      struct __sanitizer_ptrace_io_desc *addr = +          (struct __sanitizer_ptrace_io_desc *)addr_; +      POST_READ(addr, struct_ptrace_ptrace_io_desc_struct_sz); +      if (addr->piod_op == ptrace_piod_write_d || +          addr->piod_op == ptrace_piod_write_i) { +        POST_READ(addr->piod_addr, addr->piod_len); +      } +      if (addr->piod_op == ptrace_piod_read_d || +          addr->piod_op == ptrace_piod_read_i || +          addr->piod_op == ptrace_piod_read_auxv) { +        POST_WRITE(addr->piod_addr, addr->piod_len); +      } +    } else if (req_ == ptrace_pt_lwpinfo) { +      struct __sanitizer_ptrace_lwpinfo *addr = +          (struct __sanitizer_ptrace_lwpinfo *)addr_; +      POST_READ(&addr->pl_lwpid, sizeof(__sanitizer_lwpid_t)); +      POST_WRITE(addr, struct_ptrace_ptrace_lwpinfo_struct_sz); +    } else if (req_ == ptrace_pt_set_event_mask) { +      POST_READ(addr_, struct_ptrace_ptrace_event_struct_sz); +    } else if (req_ == ptrace_pt_get_event_mask) { +      POST_WRITE(addr_, struct_ptrace_ptrace_event_struct_sz); +    } else if (req_ == ptrace_pt_set_siginfo) { +      POST_READ(addr_, struct_ptrace_ptrace_siginfo_struct_sz); +    } else if (req_ == ptrace_pt_get_siginfo) { +      POST_WRITE(addr_, struct_ptrace_ptrace_siginfo_struct_sz); +    } else if (req_ == ptrace_pt_setregs) { +      POST_READ(addr_, struct_ptrace_reg_struct_sz); +    } else if (req_ == ptrace_pt_getregs) { +      POST_WRITE(addr_, struct_ptrace_reg_struct_sz); +    } else if (req_ == ptrace_pt_setfpregs) { +      POST_READ(addr_, struct_ptrace_fpreg_struct_sz); +    } else if (req_ == ptrace_pt_getfpregs) { +      POST_WRITE(addr_, struct_ptrace_fpreg_struct_sz); +    } else if (req_ == ptrace_pt_setdbregs) { +      POST_READ(addr_, struct_ptrace_dbreg_struct_sz); +    } else if (req_ == ptrace_pt_getdbregs) { +      POST_WRITE(addr_, struct_ptrace_dbreg_struct_sz); +    } +  } +} +PRE_SYSCALL(recvmsg)(long long s_, void *msg_, long long flags_) { +  PRE_WRITE(msg_, sizeof(__sanitizer_msghdr)); +} +POST_SYSCALL(recvmsg) +(long long res, long long s_, void *msg_, long long flags_) { +  if (res > 0) { +    POST_WRITE(msg_, sizeof(__sanitizer_msghdr)); +  } +} +PRE_SYSCALL(sendmsg)(long long s_, void *msg_, long long flags_) { +  PRE_READ(msg_, sizeof(__sanitizer_msghdr)); +} +POST_SYSCALL(sendmsg) +(long long res, long long s_, void *msg_, long long flags_) { +  if (res > 0) { +    POST_READ(msg_, sizeof(__sanitizer_msghdr)); +  } +} +PRE_SYSCALL(recvfrom) +(long long s_, void *buf_, long long len_, long long flags_, void *from_, +  void *fromlenaddr_) { +  PRE_WRITE(buf_, len_); +  PRE_WRITE(from_, struct_sockaddr_sz); +  PRE_WRITE(fromlenaddr_, sizeof(__sanitizer_socklen_t)); +} +POST_SYSCALL(recvfrom) +(long long res, long long s_, void *buf_, long long len_, long long flags_, +  void *from_, void *fromlenaddr_) { +  if (res >= 0) { +    POST_WRITE(buf_, res); +    POST_WRITE(from_, struct_sockaddr_sz); +    POST_WRITE(fromlenaddr_, sizeof(__sanitizer_socklen_t)); +  } +} +PRE_SYSCALL(accept)(long long s_, void *name_, void *anamelen_) { +  PRE_WRITE(name_, struct_sockaddr_sz); +  PRE_WRITE(anamelen_, sizeof(__sanitizer_socklen_t)); +} +POST_SYSCALL(accept) +(long long res, long long s_, void *name_, void *anamelen_) { +  if (res == 0) { +    POST_WRITE(name_, struct_sockaddr_sz); +    POST_WRITE(anamelen_, sizeof(__sanitizer_socklen_t)); +  } +} +PRE_SYSCALL(getpeername)(long long fdes_, void *asa_, void *alen_) { +  PRE_WRITE(asa_, struct_sockaddr_sz); +  PRE_WRITE(alen_, sizeof(__sanitizer_socklen_t)); +} +POST_SYSCALL(getpeername) +(long long res, long long fdes_, void *asa_, void *alen_) { +  if (res == 0) { +    POST_WRITE(asa_, struct_sockaddr_sz); +    POST_WRITE(alen_, sizeof(__sanitizer_socklen_t)); +  } +} +PRE_SYSCALL(getsockname)(long long fdes_, void *asa_, void *alen_) { +  PRE_WRITE(asa_, struct_sockaddr_sz); +  PRE_WRITE(alen_, sizeof(__sanitizer_socklen_t)); +} +POST_SYSCALL(getsockname) +(long long res, long long fdes_, void *asa_, void *alen_) { +  if (res == 0) { +    POST_WRITE(asa_, struct_sockaddr_sz); +    POST_WRITE(alen_, sizeof(__sanitizer_socklen_t)); +  } +} +PRE_SYSCALL(access)(void *path_, long long flags_) { +  const char *path = (const char *)path_; +  if (path) { +    PRE_READ(path, __sanitizer::internal_strlen(path) + 1); +  } +} +POST_SYSCALL(access)(long long res, void *path_, long long flags_) { +  if (res == 0) { +    const char *path = (const char *)path_; +    if (path) { +      POST_READ(path, __sanitizer::internal_strlen(path) + 1); +    } +  } +} +PRE_SYSCALL(chflags)(void *path_, long long flags_) { +  const char *path = (const char *)path_; +  if (path) { +    PRE_READ(path, __sanitizer::internal_strlen(path) + 1); +  } +} +POST_SYSCALL(chflags)(long long res, void *path_, long long flags_) { +  if (res == 0) { +    const char *path = (const char *)path_; +    if (path) { +      POST_READ(path, __sanitizer::internal_strlen(path) + 1); +    } +  } +} +PRE_SYSCALL(fchflags)(long long fd_, long long flags_) { /* Nothing to do */ } +POST_SYSCALL(fchflags)(long long res, long long fd_, long long flags_) { +  /* Nothing to do */ +} +PRE_SYSCALL(sync)(void) { /* Nothing to do */ } +POST_SYSCALL(sync)(long long res) { /* Nothing to do */ } +PRE_SYSCALL(kill)(long long pid_, long long signum_) { /* Nothing to do */ } +POST_SYSCALL(kill)(long long res, long long pid_, long long signum_) { +  /* Nothing to do */ +} +PRE_SYSCALL(compat_43_stat43)(void *path_, void *ub_) { /* TODO */ } +POST_SYSCALL(compat_43_stat43)(long long res, void *path_, void *ub_) { +  /* TODO */ +} +PRE_SYSCALL(getppid)(void) { /* Nothing to do */ } +POST_SYSCALL(getppid)(long long res) { /* Nothing to do */ } +PRE_SYSCALL(compat_43_lstat43)(void *path_, void *ub_) { /* TODO */ } +POST_SYSCALL(compat_43_lstat43)(long long res, void *path_, void *ub_) { +  /* TODO */ +} +PRE_SYSCALL(dup)(long long fd_) { /* Nothing to do */ } +POST_SYSCALL(dup)(long long res, long long fd_) { /* Nothing to do */ } +PRE_SYSCALL(pipe)(void) { +  /* pipe returns two descriptors through two returned values */ +} +POST_SYSCALL(pipe)(long long res) { +  /* pipe returns two descriptors through two returned values */ +} +PRE_SYSCALL(getegid)(void) { /* Nothing to do */ } +POST_SYSCALL(getegid)(long long res) { /* Nothing to do */ } +PRE_SYSCALL(profil) +(void *samples_, long long size_, long long offset_, long long scale_) { +  if (samples_) { +    PRE_WRITE(samples_, size_); +  } +} +POST_SYSCALL(profil) +(long long res, void *samples_, long long size_, long long offset_, +  long long scale_) { +  if (res == 0) { +    if (samples_) { +      POST_WRITE(samples_, size_); +    } +  } +} +PRE_SYSCALL(ktrace) +(void *fname_, long long ops_, long long facs_, long long pid_) { +  const char *fname = (const char *)fname_; +  if (fname) { +    PRE_READ(fname, __sanitizer::internal_strlen(fname) + 1); +  } +} +POST_SYSCALL(ktrace) +(long long res, void *fname_, long long ops_, long long facs_, long long pid_) { +  const char *fname = (const char *)fname_; +  if (res == 0) { +    if (fname) { +      POST_READ(fname, __sanitizer::internal_strlen(fname) + 1); +    } +  } +} +PRE_SYSCALL(compat_13_sigaction13)(long long signum_, void *nsa_, void *osa_) { +  /* TODO */ +} +POST_SYSCALL(compat_13_sigaction13) +(long long res, long long signum_, void *nsa_, void *osa_) { +  /* TODO */ +} +PRE_SYSCALL(getgid)(void) { /* Nothing to do */ } +POST_SYSCALL(getgid)(long long res) { /* Nothing to do */ } +PRE_SYSCALL(compat_13_sigprocmask13)(long long how_, long long mask_) { +  /* TODO */ +} +POST_SYSCALL(compat_13_sigprocmask13) +(long long res, long long how_, long long mask_) { +  /* TODO */ +} +PRE_SYSCALL(__getlogin)(void *namebuf_, long long namelen_) { +  if (namebuf_) { +    PRE_WRITE(namebuf_, namelen_); +  } +} +POST_SYSCALL(__getlogin)(long long res, void *namebuf_, long long namelen_) { +  if (res == 0) { +    if (namebuf_) { +      POST_WRITE(namebuf_, namelen_); +    } +  } +} +PRE_SYSCALL(__setlogin)(void *namebuf_) { +  const char *namebuf = (const char *)namebuf_; +  if (namebuf) { +    PRE_READ(namebuf, __sanitizer::internal_strlen(namebuf) + 1); +  } +} +POST_SYSCALL(__setlogin)(long long res, void *namebuf_) { +  if (res == 0) { +    const char *namebuf = (const char *)namebuf_; +    if (namebuf) { +      POST_READ(namebuf, __sanitizer::internal_strlen(namebuf) + 1); +    } +  } +} +PRE_SYSCALL(acct)(void *path_) { +  const char *path = (const char *)path_; +  if (path) { +    PRE_READ(path, __sanitizer::internal_strlen(path) + 1); +  } +} +POST_SYSCALL(acct)(long long res, void *path_) { +  if (res == 0) { +    const char *path = (const char *)path_; +    if (path) { +      POST_READ(path, __sanitizer::internal_strlen(path) + 1); +    } +  } +} +PRE_SYSCALL(compat_13_sigpending13)(void) { /* TODO */ } +POST_SYSCALL(compat_13_sigpending13)(long long res) { /* TODO */ } +PRE_SYSCALL(compat_13_sigaltstack13)(void *nss_, void *oss_) { /* TODO */ } +POST_SYSCALL(compat_13_sigaltstack13)(long long res, void *nss_, void *oss_) { +  /* TODO */ +} +PRE_SYSCALL(ioctl)(long long fd_, long long com_, void *data_) { +  /* Nothing to do */ +} +POST_SYSCALL(ioctl)(long long res, long long fd_, long long com_, void *data_) { +  /* Nothing to do */ +} +PRE_SYSCALL(compat_12_oreboot)(long long opt_) { /* TODO */ } +POST_SYSCALL(compat_12_oreboot)(long long res, long long opt_) { /* TODO */ } +PRE_SYSCALL(revoke)(void *path_) { +  const char *path = (const char *)path_; +  if (path) { +    PRE_READ(path, __sanitizer::internal_strlen(path) + 1); +  } +} +POST_SYSCALL(revoke)(long long res, void *path_) { +  if (res == 0) { +    const char *path = (const char *)path_; +    if (path) { +      POST_READ(path, __sanitizer::internal_strlen(path) + 1); +    } +  } +} +PRE_SYSCALL(symlink)(void *path_, void *link_) { +  const char *path = (const char *)path_; +  const char *link = (const char *)link_; +  if (path) { +    PRE_READ(path, __sanitizer::internal_strlen(path) + 1); +  } +  if (link) { +    PRE_READ(link, __sanitizer::internal_strlen(link) + 1); +  } +} +POST_SYSCALL(symlink)(long long res, void *path_, void *link_) { +  if (res == 0) { +    const char *path = (const char *)path_; +    const char *link = (const char *)link_; +    if (path) { +      POST_READ(path, __sanitizer::internal_strlen(path) + 1); +    } +    if (link) { +      POST_READ(link, __sanitizer::internal_strlen(link) + 1); +    } +  } +} +PRE_SYSCALL(readlink)(void *path_, void *buf_, long long count_) { +  const char *path = (const char *)path_; +  if (path) { +    PRE_READ(path, __sanitizer::internal_strlen(path) + 1); +  } +  if (buf_) { +    PRE_WRITE(buf_, count_); +  } +} +POST_SYSCALL(readlink) +(long long res, void *path_, void *buf_, long long count_) { +  if (res > 0) { +    const char *path = (const char *)path_; +    if (path) { +      POST_READ(path, __sanitizer::internal_strlen(path) + 1); +    } +    if (buf_) { +      PRE_WRITE(buf_, res); +    } +  } +} +PRE_SYSCALL(execve)(void *path_, void *argp_, void *envp_) { +  const char *path = (const char *)path_; +  char **argp = (char **)argp_; +  char **envp = (char **)envp_; +  if (path) { +    PRE_READ(path, __sanitizer::internal_strlen(path) + 1); +  } +  if (argp && argp[0]) { +    char *a = argp[0]; +    while (a++) { +      PRE_READ(a, __sanitizer::internal_strlen(a) + 1); +    } +  } +  if (envp && envp[0]) { +    char *e = envp[0]; +    while (e++) { +      PRE_READ(e, __sanitizer::internal_strlen(e) + 1); +    } +  } +} +POST_SYSCALL(execve)(long long res, void *path_, void *argp_, void *envp_) { +  /* If we are here, something went wrong */ +  const char *path = (const char *)path_; +  char **argp = (char **)argp_; +  char **envp = (char **)envp_; +  if (path) { +    POST_READ(path, __sanitizer::internal_strlen(path) + 1); +  } +  if (argp && argp[0]) { +    char *a = argp[0]; +    while (a++) { +      POST_READ(a, __sanitizer::internal_strlen(a) + 1); +    } +  } +  if (envp && envp[0]) { +    char *e = envp[0]; +    while (e++) { +      POST_READ(e, __sanitizer::internal_strlen(e) + 1); +    } +  } +} +PRE_SYSCALL(umask)(long long newmask_) { /* Nothing to do */ } +POST_SYSCALL(umask)(long long res, long long newmask_) { /* Nothing to do */ } +PRE_SYSCALL(chroot)(void *path_) { +  const char *path = (const char *)path_; +  if (path) { +    PRE_READ(path, __sanitizer::internal_strlen(path) + 1); +  } +} +POST_SYSCALL(chroot)(long long res, void *path_) { +  if (res == 0) { +    const char *path = (const char *)path_; +    if (path) { +      POST_READ(path, __sanitizer::internal_strlen(path) + 1); +    } +  } +} +PRE_SYSCALL(compat_43_fstat43)(long long fd_, void *sb_) { /* TODO */ } +POST_SYSCALL(compat_43_fstat43)(long long res, long long fd_, void *sb_) { +  /* TODO */ +} +PRE_SYSCALL(compat_43_ogetkerninfo) +(long long op_, void *where_, void *size_, long long arg_) { +  /* TODO */ +} +POST_SYSCALL(compat_43_ogetkerninfo) +(long long res, long long op_, void *where_, void *size_, long long arg_) { +  /* TODO */ +} +PRE_SYSCALL(compat_43_ogetpagesize)(void) { /* TODO */ } +POST_SYSCALL(compat_43_ogetpagesize)(long long res) { /* TODO */ } +PRE_SYSCALL(compat_12_msync)(void *addr_, long long len_) { /* TODO */ } +POST_SYSCALL(compat_12_msync)(long long res, void *addr_, long long len_) { +  /* TODO */ +} +PRE_SYSCALL(vfork)(void) { /* Nothing to do */ } +POST_SYSCALL(vfork)(long long res) { /* Nothing to do */ } +/* syscall 67 has been skipped */ +/* syscall 68 has been skipped */ +/* syscall 69 has been skipped */ +/* syscall 70 has been skipped */ +PRE_SYSCALL(compat_43_ommap) +(void *addr_, long long len_, long long prot_, long long flags_, long long fd_, +  long long pos_) { +  /* TODO */ +} +POST_SYSCALL(compat_43_ommap) +(long long res, void *addr_, long long len_, long long prot_, long long flags_, +  long long fd_, long long pos_) { +  /* TODO */ +} +PRE_SYSCALL(vadvise)(long long anom_) { /* Nothing to do */ } +POST_SYSCALL(vadvise)(long long res, long long anom_) { /* Nothing to do */ } +PRE_SYSCALL(munmap)(void *addr_, long long len_) { /* Nothing to do */ } +POST_SYSCALL(munmap)(long long res, void *addr_, long long len_) { +  /* Nothing to do */ +} +PRE_SYSCALL(mprotect)(void *addr_, long long len_, long long prot_) { +  /* Nothing to do */ +} +POST_SYSCALL(mprotect) +(long long res, void *addr_, long long len_, long long prot_) { +  /* Nothing to do */ +} +PRE_SYSCALL(madvise)(void *addr_, long long len_, long long behav_) { +  /* Nothing to do */ +} +POST_SYSCALL(madvise) +(long long res, void *addr_, long long len_, long long behav_) { +  /* Nothing to do */ +} +/* syscall 76 has been skipped */ +/* syscall 77 has been skipped */ +PRE_SYSCALL(mincore)(void *addr_, long long len_, void *vec_) { +  /* Nothing to do */ +} +POST_SYSCALL(mincore)(long long res, void *addr_, long long len_, void *vec_) { +  /* Nothing to do */ +} +PRE_SYSCALL(getgroups)(long long gidsetsize_, void *gidset_) { +  unsigned int *gidset = (unsigned int *)gidset_; +  if (gidset) { +    PRE_WRITE(gidset, sizeof(*gidset) * gidsetsize_); +  } +} +POST_SYSCALL(getgroups)(long long res, long long gidsetsize_, void *gidset_) { +  if (res == 0) { +    unsigned int *gidset = (unsigned int *)gidset_; +    if (gidset) { +      POST_WRITE(gidset, sizeof(*gidset) * gidsetsize_); +    } +  } +} +PRE_SYSCALL(setgroups)(long long gidsetsize_, void *gidset_) { +  unsigned int *gidset = (unsigned int *)gidset_; +  if (gidset) { +    PRE_READ(gidset, sizeof(*gidset) * gidsetsize_); +  } +} +POST_SYSCALL(setgroups)(long long res, long long gidsetsize_, void *gidset_) { +  if (res == 0) { +    unsigned int *gidset = (unsigned int *)gidset_; +    if (gidset) { +      POST_READ(gidset, sizeof(*gidset) * gidsetsize_); +    } +  } +} +PRE_SYSCALL(getpgrp)(void) { /* Nothing to do */ } +POST_SYSCALL(getpgrp)(long long res) { /* Nothing to do */ } +PRE_SYSCALL(setpgid)(long long pid_, long long pgid_) { /* Nothing to do */ } +POST_SYSCALL(setpgid)(long long res, long long pid_, long long pgid_) { +  /* Nothing to do */ +} +PRE_SYSCALL(compat_50_setitimer)(long long which_, void *itv_, void *oitv_) { +  /* TODO */ +} +POST_SYSCALL(compat_50_setitimer) +(long long res, long long which_, void *itv_, void *oitv_) { +  /* TODO */ +} +PRE_SYSCALL(compat_43_owait)(void) { /* TODO */ } +POST_SYSCALL(compat_43_owait)(long long res) { /* TODO */ } +PRE_SYSCALL(compat_12_oswapon)(void *name_) { /* TODO */ } +POST_SYSCALL(compat_12_oswapon)(long long res, void *name_) { /* TODO */ } +PRE_SYSCALL(compat_50_getitimer)(long long which_, void *itv_) { /* TODO */ } +POST_SYSCALL(compat_50_getitimer)(long long res, long long which_, void *itv_) { +  /* TODO */ +} +PRE_SYSCALL(compat_43_ogethostname)(void *hostname_, long long len_) { +  /* TODO */ +} +POST_SYSCALL(compat_43_ogethostname) +(long long res, void *hostname_, long long len_) { +  /* TODO */ +} +PRE_SYSCALL(compat_43_osethostname)(void *hostname_, long long len_) { +  /* TODO */ +} +POST_SYSCALL(compat_43_osethostname) +(long long res, void *hostname_, long long len_) { +  /* TODO */ +} +PRE_SYSCALL(compat_43_ogetdtablesize)(void) { /* TODO */ } +POST_SYSCALL(compat_43_ogetdtablesize)(long long res) { /* TODO */ } +PRE_SYSCALL(dup2)(long long from_, long long to_) { /* Nothing to do */ } +POST_SYSCALL(dup2)(long long res, long long from_, long long to_) { +  /* Nothing to do */ +} +/* syscall 91 has been skipped */ +PRE_SYSCALL(fcntl)(long long fd_, long long cmd_, void *arg_) { +  /* Nothing to do */ +} +POST_SYSCALL(fcntl)(long long res, long long fd_, long long cmd_, void *arg_) { +  /* Nothing to do */ +} +PRE_SYSCALL(compat_50_select) +(long long nd_, void *in_, void *ou_, void *ex_, void *tv_) { +  /* TODO */ +} +POST_SYSCALL(compat_50_select) +(long long res, long long nd_, void *in_, void *ou_, void *ex_, void *tv_) { +  /* TODO */ +} +/* syscall 94 has been skipped */ +PRE_SYSCALL(fsync)(long long fd_) { /* Nothing to do */ } +POST_SYSCALL(fsync)(long long res, long long fd_) { /* Nothing to do */ } +PRE_SYSCALL(setpriority)(long long which_, long long who_, long long prio_) { +  /* Nothing to do */ +} +POST_SYSCALL(setpriority) +(long long res, long long which_, long long who_, long long prio_) { +  /* Nothing to do */ +} +PRE_SYSCALL(compat_30_socket) +(long long domain_, long long type_, long long protocol_) { +  /* TODO */ +} +POST_SYSCALL(compat_30_socket) +(long long res, long long domain_, long long type_, long long protocol_) { +  /* TODO */ +} +PRE_SYSCALL(connect)(long long s_, void *name_, long long namelen_) { +  PRE_READ(name_, namelen_); +} +POST_SYSCALL(connect) +(long long res, long long s_, void *name_, long long namelen_) { +  if (res == 0) { +    POST_READ(name_, namelen_); +  } +} +PRE_SYSCALL(compat_43_oaccept)(long long s_, void *name_, void *anamelen_) { +  /* TODO */ +} +POST_SYSCALL(compat_43_oaccept) +(long long res, long long s_, void *name_, void *anamelen_) { +  /* TODO */ +} +PRE_SYSCALL(getpriority)(long long which_, long long who_) { +  /* Nothing to do */ +} +POST_SYSCALL(getpriority)(long long res, long long which_, long long who_) { +  /* Nothing to do */ +} +PRE_SYSCALL(compat_43_osend) +(long long s_, void *buf_, long long len_, long long flags_) { +  /* TODO */ +} +POST_SYSCALL(compat_43_osend) +(long long res, long long s_, void *buf_, long long len_, long long flags_) { +  /* TODO */ +} +PRE_SYSCALL(compat_43_orecv) +(long long s_, void *buf_, long long len_, long long flags_) { +  /* TODO */ +} +POST_SYSCALL(compat_43_orecv) +(long long res, long long s_, void *buf_, long long len_, long long flags_) { +  /* TODO */ +} +PRE_SYSCALL(compat_13_sigreturn13)(void *sigcntxp_) { /* TODO */ } +POST_SYSCALL(compat_13_sigreturn13)(long long res, void *sigcntxp_) { +  /* TODO */ +} +PRE_SYSCALL(bind)(long long s_, void *name_, long long namelen_) { +  PRE_READ(name_, namelen_); +} +POST_SYSCALL(bind) +(long long res, long long s_, void *name_, long long namelen_) { +  if (res == 0) { +    PRE_READ(name_, namelen_); +  } +} +PRE_SYSCALL(setsockopt) +(long long s_, long long level_, long long name_, void *val_, +  long long valsize_) { +  if (val_) { +    PRE_READ(val_, valsize_); +  } +} +POST_SYSCALL(setsockopt) +(long long res, long long s_, long long level_, long long name_, void *val_, +  long long valsize_) { +  if (res == 0) { +    if (val_) { +      POST_READ(val_, valsize_); +    } +  } +} +PRE_SYSCALL(listen)(long long s_, long long backlog_) { /* Nothing to do */ } +POST_SYSCALL(listen)(long long res, long long s_, long long backlog_) { +  /* Nothing to do */ +} +/* syscall 107 has been skipped */ +PRE_SYSCALL(compat_43_osigvec)(long long signum_, void *nsv_, void *osv_) { +  /* TODO */ +} +POST_SYSCALL(compat_43_osigvec) +(long long res, long long signum_, void *nsv_, void *osv_) { +  /* TODO */ +} +PRE_SYSCALL(compat_43_osigblock)(long long mask_) { /* TODO */ } +POST_SYSCALL(compat_43_osigblock)(long long res, long long mask_) { /* TODO */ } +PRE_SYSCALL(compat_43_osigsetmask)(long long mask_) { /* TODO */ } +POST_SYSCALL(compat_43_osigsetmask)(long long res, long long mask_) { +  /* TODO */ +} +PRE_SYSCALL(compat_13_sigsuspend13)(long long mask_) { /* TODO */ } +POST_SYSCALL(compat_13_sigsuspend13)(long long res, long long mask_) { +  /* TODO */ +} +PRE_SYSCALL(compat_43_osigstack)(void *nss_, void *oss_) { /* TODO */ } +POST_SYSCALL(compat_43_osigstack)(long long res, void *nss_, void *oss_) { +  /* TODO */ +} +PRE_SYSCALL(compat_43_orecvmsg)(long long s_, void *msg_, long long flags_) { +  /* TODO */ +} +POST_SYSCALL(compat_43_orecvmsg) +(long long res, long long s_, void *msg_, long long flags_) { +  /* TODO */ +} +PRE_SYSCALL(compat_43_osendmsg)(long long s_, void *msg_, long long flags_) { +  /* TODO */ +} +POST_SYSCALL(compat_43_osendmsg) +(long long res, long long s_, void *msg_, long long flags_) { +  /* TODO */ +} +/* syscall 115 has been skipped */ +PRE_SYSCALL(compat_50_gettimeofday)(void *tp_, void *tzp_) { /* TODO */ } +POST_SYSCALL(compat_50_gettimeofday)(long long res, void *tp_, void *tzp_) { +  /* TODO */ +} +PRE_SYSCALL(compat_50_getrusage)(long long who_, void *rusage_) { /* TODO */ } +POST_SYSCALL(compat_50_getrusage) +(long long res, long long who_, void *rusage_) { +  /* TODO */ +} +PRE_SYSCALL(getsockopt) +(long long s_, long long level_, long long name_, void *val_, void *avalsize_) { +  /* TODO */ +} +POST_SYSCALL(getsockopt) +(long long res, long long s_, long long level_, long long name_, void *val_, +  void *avalsize_) { +  /* TODO */ +} +/* syscall 119 has been skipped */ +PRE_SYSCALL(readv)(long long fd_, void *iovp_, long long iovcnt_) { +  struct __sanitizer_iovec *iovp = (struct __sanitizer_iovec *)iovp_; +  int i; +  if (iovp) { +    PRE_READ(iovp, sizeof(struct __sanitizer_iovec) * iovcnt_); +    for (i = 0; i < iovcnt_; i++) { +      PRE_WRITE(iovp[i].iov_base, iovp[i].iov_len); +    } +  } +} +POST_SYSCALL(readv) +(long long res, long long fd_, void *iovp_, long long iovcnt_) { +  struct __sanitizer_iovec *iovp = (struct __sanitizer_iovec *)iovp_; +  int i; +  uptr m, n = res; +  if (res > 0) { +    if (iovp) { +      POST_READ(iovp, sizeof(struct __sanitizer_iovec) * iovcnt_); +      for (i = 0; i < iovcnt_ && n > 0; i++) { +        m = n > iovp[i].iov_len ? iovp[i].iov_len : n; +        POST_WRITE(iovp[i].iov_base, m); +        n -= m; +      } +    } +  } +} +PRE_SYSCALL(writev)(long long fd_, void *iovp_, long long iovcnt_) { +  struct __sanitizer_iovec *iovp = (struct __sanitizer_iovec *)iovp_; +  int i; +  if (iovp) { +    PRE_READ(iovp, sizeof(struct __sanitizer_iovec) * iovcnt_); +    for (i = 0; i < iovcnt_; i++) { +      PRE_READ(iovp[i].iov_base, iovp[i].iov_len); +    } +  } +} +POST_SYSCALL(writev) +(long long res, long long fd_, void *iovp_, long long iovcnt_) { +  struct __sanitizer_iovec *iovp = (struct __sanitizer_iovec *)iovp_; +  int i; +  uptr m, n = res; +  if (res > 0) { +    if (iovp) { +      POST_READ(iovp, sizeof(struct __sanitizer_iovec) * iovcnt_); +      for (i = 0; i < iovcnt_ && n > 0; i++) { +        m = n > iovp[i].iov_len ? iovp[i].iov_len : n; +        POST_READ(iovp[i].iov_base, m); +        n -= m; +      } +    } +  } +} +PRE_SYSCALL(compat_50_settimeofday)(void *tv_, void *tzp_) { /* TODO */ } +POST_SYSCALL(compat_50_settimeofday)(long long res, void *tv_, void *tzp_) { +  /* TODO */ +} +PRE_SYSCALL(fchown)(long long fd_, long long uid_, long long gid_) { +  /* Nothing to do */ +} +POST_SYSCALL(fchown) +(long long res, long long fd_, long long uid_, long long gid_) { +  /* Nothing to do */ +} +PRE_SYSCALL(fchmod)(long long fd_, long long mode_) { /* Nothing to do */ } +POST_SYSCALL(fchmod)(long long res, long long fd_, long long mode_) { +  /* Nothing to do */ +} +PRE_SYSCALL(compat_43_orecvfrom) +(long long s_, void *buf_, long long len_, long long flags_, void *from_, +  void *fromlenaddr_) { +  /* TODO */ +} +POST_SYSCALL(compat_43_orecvfrom) +(long long res, long long s_, void *buf_, long long len_, long long flags_, +  void *from_, void *fromlenaddr_) { +  /* TODO */ +} +PRE_SYSCALL(setreuid)(long long ruid_, long long euid_) { /* Nothing to do */ } +POST_SYSCALL(setreuid)(long long res, long long ruid_, long long euid_) { +  /* Nothing to do */ +} +PRE_SYSCALL(setregid)(long long rgid_, long long egid_) { /* Nothing to do */ } +POST_SYSCALL(setregid)(long long res, long long rgid_, long long egid_) { +  /* Nothing to do */ +} +PRE_SYSCALL(rename)(void *from_, void *to_) { +  const char *from = (const char *)from_; +  const char *to = (const char *)to_; +  if (from) { +    PRE_READ(from, __sanitizer::internal_strlen(from) + 1); +  } +  if (to) { +    PRE_READ(to, __sanitizer::internal_strlen(to) + 1); +  } +} +POST_SYSCALL(rename)(long long res, void *from_, void *to_) { +  if (res == 0) { +    const char *from = (const char *)from_; +    const char *to = (const char *)to_; +    if (from) { +      POST_READ(from, __sanitizer::internal_strlen(from) + 1); +    } +    if (to) { +      POST_READ(to, __sanitizer::internal_strlen(to) + 1); +    } +  } +} +PRE_SYSCALL(compat_43_otruncate)(void *path_, long long length_) { /* TODO */ } +POST_SYSCALL(compat_43_otruncate) +(long long res, void *path_, long long length_) { +  /* TODO */ +} +PRE_SYSCALL(compat_43_oftruncate)(long long fd_, long long length_) { +  /* TODO */ +} +POST_SYSCALL(compat_43_oftruncate) +(long long res, long long fd_, long long length_) { +  /* TODO */ +} +PRE_SYSCALL(flock)(long long fd_, long long how_) { /* Nothing to do */ } +POST_SYSCALL(flock)(long long res, long long fd_, long long how_) { +  /* Nothing to do */ +} +PRE_SYSCALL(mkfifo)(void *path_, long long mode_) { +  const char *path = (const char *)path_; +  if (path) { +    PRE_READ(path, __sanitizer::internal_strlen(path) + 1); +  } +} +POST_SYSCALL(mkfifo)(long long res, void *path_, long long mode_) { +  if (res == 0) { +    const char *path = (const char *)path_; +    if (path) { +      POST_READ(path, __sanitizer::internal_strlen(path) + 1); +    } +  } +} +PRE_SYSCALL(sendto) +(long long s_, void *buf_, long long len_, long long flags_, void *to_, +  long long tolen_) { +  PRE_READ(buf_, len_); +  PRE_READ(to_, tolen_); +} +POST_SYSCALL(sendto) +(long long res, long long s_, void *buf_, long long len_, long long flags_, +  void *to_, long long tolen_) { +  if (res >= 0) { +    POST_READ(buf_, len_); +    POST_READ(to_, tolen_); +  } +} +PRE_SYSCALL(shutdown)(long long s_, long long how_) { /* Nothing to do */ } +POST_SYSCALL(shutdown)(long long res, long long s_, long long how_) { +  /* Nothing to do */ +} +PRE_SYSCALL(socketpair) +(long long domain_, long long type_, long long protocol_, void *rsv_) { +  PRE_WRITE(rsv_, 2 * sizeof(int)); +} +POST_SYSCALL(socketpair) +(long long res, long long domain_, long long type_, long long protocol_, +  void *rsv_) { +  if (res == 0) { +    POST_WRITE(rsv_, 2 * sizeof(int)); +  } +} +PRE_SYSCALL(mkdir)(void *path_, long long mode_) { +  const char *path = (const char *)path_; +  if (path) { +    PRE_READ(path, __sanitizer::internal_strlen(path) + 1); +  } +} +POST_SYSCALL(mkdir)(long long res, void *path_, long long mode_) { +  if (res == 0) { +    const char *path = (const char *)path_; +    if (path) { +      POST_READ(path, __sanitizer::internal_strlen(path) + 1); +    } +  } +} +PRE_SYSCALL(rmdir)(void *path_) { +  const char *path = (const char *)path_; +  if (path) { +    PRE_READ(path, __sanitizer::internal_strlen(path) + 1); +  } +} +POST_SYSCALL(rmdir)(long long res, void *path_) { +  if (res == 0) { +    const char *path = (const char *)path_; +    if (path) { +      POST_READ(path, __sanitizer::internal_strlen(path) + 1); +    } +  } +} +PRE_SYSCALL(compat_50_utimes)(void *path_, void *tptr_) { /* TODO */ } +POST_SYSCALL(compat_50_utimes)(long long res, void *path_, void *tptr_) { +  /* TODO */ +} +/* syscall 139 has been skipped */ +PRE_SYSCALL(compat_50_adjtime)(void *delta_, void *olddelta_) { /* TODO */ } +POST_SYSCALL(compat_50_adjtime)(long long res, void *delta_, void *olddelta_) { +  /* TODO */ +} +PRE_SYSCALL(compat_43_ogetpeername)(long long fdes_, void *asa_, void *alen_) { +  /* TODO */ +} +POST_SYSCALL(compat_43_ogetpeername) +(long long res, long long fdes_, void *asa_, void *alen_) { +  /* TODO */ +} +PRE_SYSCALL(compat_43_ogethostid)(void) { /* TODO */ } +POST_SYSCALL(compat_43_ogethostid)(long long res) { /* TODO */ } +PRE_SYSCALL(compat_43_osethostid)(long long hostid_) { /* TODO */ } +POST_SYSCALL(compat_43_osethostid)(long long res, long long hostid_) { +  /* TODO */ +} +PRE_SYSCALL(compat_43_ogetrlimit)(long long which_, void *rlp_) { /* TODO */ } +POST_SYSCALL(compat_43_ogetrlimit) +(long long res, long long which_, void *rlp_) { +  /* TODO */ +} +PRE_SYSCALL(compat_43_osetrlimit)(long long which_, void *rlp_) { /* TODO */ } +POST_SYSCALL(compat_43_osetrlimit) +(long long res, long long which_, void *rlp_) { +  /* TODO */ +} +PRE_SYSCALL(compat_43_okillpg)(long long pgid_, long long signum_) { +  /* TODO */ +} +POST_SYSCALL(compat_43_okillpg) +(long long res, long long pgid_, long long signum_) { +  /* TODO */ +} +PRE_SYSCALL(setsid)(void) { /* Nothing to do */ } +POST_SYSCALL(setsid)(long long res) { /* Nothing to do */ } +PRE_SYSCALL(compat_50_quotactl) +(void *path_, long long cmd_, long long uid_, void *arg_) { +  /* TODO */ +} +POST_SYSCALL(compat_50_quotactl) +(long long res, void *path_, long long cmd_, long long uid_, void *arg_) { +  /* TODO */ +} +PRE_SYSCALL(compat_43_oquota)(void) { /* TODO */ } +POST_SYSCALL(compat_43_oquota)(long long res) { /* TODO */ } +PRE_SYSCALL(compat_43_ogetsockname)(long long fdec_, void *asa_, void *alen_) { +  /* TODO */ +} +POST_SYSCALL(compat_43_ogetsockname) +(long long res, long long fdec_, void *asa_, void *alen_) { +  /* TODO */ +} +/* syscall 151 has been skipped */ +/* syscall 152 has been skipped */ +/* syscall 153 has been skipped */ +/* syscall 154 has been skipped */ +PRE_SYSCALL(nfssvc)(long long flag_, void *argp_) { /* Nothing to do */ } +POST_SYSCALL(nfssvc)(long long res, long long flag_, void *argp_) { +  /* Nothing to do */ +} +PRE_SYSCALL(compat_43_ogetdirentries) +(long long fd_, void *buf_, long long count_, void *basep_) { +  /* TODO */ +} +POST_SYSCALL(compat_43_ogetdirentries) +(long long res, long long fd_, void *buf_, long long count_, void *basep_) { +  /* TODO */ +} +PRE_SYSCALL(compat_20_statfs)(void *path_, void *buf_) { /* TODO */ } +POST_SYSCALL(compat_20_statfs)(long long res, void *path_, void *buf_) { +  /* TODO */ +} +PRE_SYSCALL(compat_20_fstatfs)(long long fd_, void *buf_) { /* TODO */ } +POST_SYSCALL(compat_20_fstatfs)(long long res, long long fd_, void *buf_) { +  /* TODO */ +} +/* syscall 159 has been skipped */ +/* syscall 160 has been skipped */ +PRE_SYSCALL(compat_30_getfh)(void *fname_, void *fhp_) { /* TODO */ } +POST_SYSCALL(compat_30_getfh)(long long res, void *fname_, void *fhp_) { +  /* TODO */ +} +PRE_SYSCALL(compat_09_ogetdomainname)(void *domainname_, long long len_) { +  /* TODO */ +} +POST_SYSCALL(compat_09_ogetdomainname) +(long long res, void *domainname_, long long len_) { +  /* TODO */ +} +PRE_SYSCALL(compat_09_osetdomainname)(void *domainname_, long long len_) { +  /* TODO */ +} +POST_SYSCALL(compat_09_osetdomainname) +(long long res, void *domainname_, long long len_) { +  /* TODO */ +} +PRE_SYSCALL(compat_09_ouname)(void *name_) { /* TODO */ } +POST_SYSCALL(compat_09_ouname)(long long res, void *name_) { /* TODO */ } +PRE_SYSCALL(sysarch)(long long op_, void *parms_) { /* TODO */ } +POST_SYSCALL(sysarch)(long long res, long long op_, void *parms_) { /* TODO */ } +/* syscall 166 has been skipped */ +/* syscall 167 has been skipped */ +/* syscall 168 has been skipped */ +#if !defined(_LP64) +PRE_SYSCALL(compat_10_osemsys) +(long long which_, long long a2_, long long a3_, long long a4_, long long a5_) { +  /* TODO */ +} +POST_SYSCALL(compat_10_osemsys) +(long long res, long long which_, long long a2_, long long a3_, long long a4_, +  long long a5_) { +  /* TODO */ +} +#else +/* syscall 169 has been skipped */ +#endif +#if !defined(_LP64) +PRE_SYSCALL(compat_10_omsgsys) +(long long which_, long long a2_, long long a3_, long long a4_, long long a5_, +  long long a6_) { +  /* TODO */ +} +POST_SYSCALL(compat_10_omsgsys) +(long long res, long long which_, long long a2_, long long a3_, long long a4_, +  long long a5_, long long a6_) { +  /* TODO */ +} +#else +/* syscall 170 has been skipped */ +#endif +#if !defined(_LP64) +PRE_SYSCALL(compat_10_oshmsys) +(long long which_, long long a2_, long long a3_, long long a4_) { +  /* TODO */ +} +POST_SYSCALL(compat_10_oshmsys) +(long long res, long long which_, long long a2_, long long a3_, long long a4_) { +  /* TODO */ +} +#else +/* syscall 171 has been skipped */ +#endif +/* syscall 172 has been skipped */ +PRE_SYSCALL(pread) +(long long fd_, void *buf_, long long nbyte_, long long PAD_, +  long long offset_) { +  if (buf_) { +    PRE_WRITE(buf_, nbyte_); +  } +} +POST_SYSCALL(pread) +(long long res, long long fd_, void *buf_, long long nbyte_, long long PAD_, +  long long offset_) { +  if (res > 0) { +    POST_WRITE(buf_, res); +  } +} +PRE_SYSCALL(pwrite) +(long long fd_, void *buf_, long long nbyte_, long long PAD_, +  long long offset_) { +  if (buf_) { +    PRE_READ(buf_, nbyte_); +  } +} +POST_SYSCALL(pwrite) +(long long res, long long fd_, void *buf_, long long nbyte_, long long PAD_, +  long long offset_) { +  if (res > 0) { +    POST_READ(buf_, res); +  } +} +PRE_SYSCALL(compat_30_ntp_gettime)(void *ntvp_) { /* TODO */ } +POST_SYSCALL(compat_30_ntp_gettime)(long long res, void *ntvp_) { /* TODO */ } +#if defined(NTP) || !defined(_KERNEL_OPT) +PRE_SYSCALL(ntp_adjtime)(void *tp_) { /* Nothing to do */ } +POST_SYSCALL(ntp_adjtime)(long long res, void *tp_) { /* Nothing to do */ } +#else +/* syscall 176 has been skipped */ +#endif +/* syscall 177 has been skipped */ +/* syscall 178 has been skipped */ +/* syscall 179 has been skipped */ +/* syscall 180 has been skipped */ +PRE_SYSCALL(setgid)(long long gid_) { /* Nothing to do */ } +POST_SYSCALL(setgid)(long long res, long long gid_) { /* Nothing to do */ } +PRE_SYSCALL(setegid)(long long egid_) { /* Nothing to do */ } +POST_SYSCALL(setegid)(long long res, long long egid_) { /* Nothing to do */ } +PRE_SYSCALL(seteuid)(long long euid_) { /* Nothing to do */ } +POST_SYSCALL(seteuid)(long long res, long long euid_) { /* Nothing to do */ } +PRE_SYSCALL(lfs_bmapv)(void *fsidp_, void *blkiov_, long long blkcnt_) { +  /* TODO */ +} +POST_SYSCALL(lfs_bmapv) +(long long res, void *fsidp_, void *blkiov_, long long blkcnt_) { +  /* TODO */ +} +PRE_SYSCALL(lfs_markv)(void *fsidp_, void *blkiov_, long long blkcnt_) { +  /* TODO */ +} +POST_SYSCALL(lfs_markv) +(long long res, void *fsidp_, void *blkiov_, long long blkcnt_) { +  /* TODO */ +} +PRE_SYSCALL(lfs_segclean)(void *fsidp_, long long segment_) { /* TODO */ } +POST_SYSCALL(lfs_segclean)(long long res, void *fsidp_, long long segment_) { +  /* TODO */ +} +PRE_SYSCALL(compat_50_lfs_segwait)(void *fsidp_, void *tv_) { /* TODO */ } +POST_SYSCALL(compat_50_lfs_segwait)(long long res, void *fsidp_, void *tv_) { +  /* TODO */ +} +PRE_SYSCALL(compat_12_stat12)(void *path_, void *ub_) { /* TODO */ } +POST_SYSCALL(compat_12_stat12)(long long res, void *path_, void *ub_) { +  /* TODO */ +} +PRE_SYSCALL(compat_12_fstat12)(long long fd_, void *sb_) { /* TODO */ } +POST_SYSCALL(compat_12_fstat12)(long long res, long long fd_, void *sb_) { +  /* TODO */ +} +PRE_SYSCALL(compat_12_lstat12)(void *path_, void *ub_) { /* TODO */ } +POST_SYSCALL(compat_12_lstat12)(long long res, void *path_, void *ub_) { +  /* TODO */ +} +PRE_SYSCALL(pathconf)(void *path_, long long name_) { +  const char *path = (const char *)path_; +  if (path) { +    PRE_READ(path, __sanitizer::internal_strlen(path) + 1); +  } +} +POST_SYSCALL(pathconf)(long long res, void *path_, long long name_) { +  if (res != -1) { +    const char *path = (const char *)path_; +    if (path) { +      POST_READ(path, __sanitizer::internal_strlen(path) + 1); +    } +  } +} +PRE_SYSCALL(fpathconf)(long long fd_, long long name_) { /* Nothing to do */ } +POST_SYSCALL(fpathconf)(long long res, long long fd_, long long name_) { +  /* Nothing to do */ +} +/* syscall 193 has been skipped */ +PRE_SYSCALL(getrlimit)(long long which_, void *rlp_) { +  PRE_WRITE(rlp_, struct_rlimit_sz); +} +POST_SYSCALL(getrlimit)(long long res, long long which_, void *rlp_) { +  if (res == 0) { +    POST_WRITE(rlp_, struct_rlimit_sz); +  } +} +PRE_SYSCALL(setrlimit)(long long which_, void *rlp_) { +  PRE_READ(rlp_, struct_rlimit_sz); +} +POST_SYSCALL(setrlimit)(long long res, long long which_, void *rlp_) { +  if (res == 0) { +    POST_READ(rlp_, struct_rlimit_sz); +  } +} +PRE_SYSCALL(compat_12_getdirentries) +(long long fd_, void *buf_, long long count_, void *basep_) { +  /* TODO */ +} +POST_SYSCALL(compat_12_getdirentries) +(long long res, long long fd_, void *buf_, long long count_, void *basep_) { +  /* TODO */ +} +PRE_SYSCALL(mmap) +(void *addr_, long long len_, long long prot_, long long flags_, long long fd_, +  long long PAD_, long long pos_) { +  /* Nothing to do */ +} +POST_SYSCALL(mmap) +(long long res, void *addr_, long long len_, long long prot_, long long flags_, +  long long fd_, long long PAD_, long long pos_) { +  /* Nothing to do */ +} +PRE_SYSCALL(__syscall)(long long code_, long long args_[SYS_MAXSYSARGS]) { +  /* Nothing to do */ +} +POST_SYSCALL(__syscall) +(long long res, long long code_, long long args_[SYS_MAXSYSARGS]) { +  /* Nothing to do */ +} +PRE_SYSCALL(lseek) +(long long fd_, long long PAD_, long long offset_, long long whence_) { +  /* Nothing to do */ +} +POST_SYSCALL(lseek) +(long long res, long long fd_, long long PAD_, long long offset_, +  long long whence_) { +  /* Nothing to do */ +} +PRE_SYSCALL(truncate)(void *path_, long long PAD_, long long length_) { +  const char *path = (const char *)path_; +  if (path) { +    PRE_READ(path, __sanitizer::internal_strlen(path) + 1); +  } +} +POST_SYSCALL(truncate) +(long long res, void *path_, long long PAD_, long long length_) { +  if (res == 0) { +    const char *path = (const char *)path_; +    if (path) { +      POST_READ(path, __sanitizer::internal_strlen(path) + 1); +    } +  } +} +PRE_SYSCALL(ftruncate)(long long fd_, long long PAD_, long long length_) { +  /* Nothing to do */ +} +POST_SYSCALL(ftruncate) +(long long res, long long fd_, long long PAD_, long long length_) { +  /* Nothing to do */ +} +PRE_SYSCALL(__sysctl) +(void *name_, long long namelen_, void *oldv_, void *oldlenp_, void *newv_, +  long long newlen_) { +  const int *name = (const int *)name_; +  if (name) { +    PRE_READ(name, namelen_ * sizeof(*name)); +  } +  if (newv_) { +    PRE_READ(name, newlen_); +  } +} +POST_SYSCALL(__sysctl) +(long long res, void *name_, long long namelen_, void *oldv_, void *oldlenp_, +  void *newv_, long long newlen_) { +  if (res == 0) { +    const int *name = (const int *)name_; +    if (name) { +      POST_READ(name, namelen_ * sizeof(*name)); +    } +    if (newv_) { +      POST_READ(name, newlen_); +    } +  } +} +PRE_SYSCALL(mlock)(void *addr_, long long len_) { /* Nothing to do */ } +POST_SYSCALL(mlock)(long long res, void *addr_, long long len_) { +  /* Nothing to do */ +} +PRE_SYSCALL(munlock)(void *addr_, long long len_) { /* Nothing to do */ } +POST_SYSCALL(munlock)(long long res, void *addr_, long long len_) { +  /* Nothing to do */ +} +PRE_SYSCALL(undelete)(void *path_) { +  const char *path = (const char *)path_; +  if (path) { +    PRE_READ(path, __sanitizer::internal_strlen(path) + 1); +  } +} +POST_SYSCALL(undelete)(long long res, void *path_) { +  if (res == 0) { +    const char *path = (const char *)path_; +    if (path) { +      POST_READ(path, __sanitizer::internal_strlen(path) + 1); +    } +  } +} +PRE_SYSCALL(compat_50_futimes)(long long fd_, void *tptr_) { /* TODO */ } +POST_SYSCALL(compat_50_futimes)(long long res, long long fd_, void *tptr_) { +  /* TODO */ +} +PRE_SYSCALL(getpgid)(long long pid_) { /* Nothing to do */ } +POST_SYSCALL(getpgid)(long long res, long long pid_) { /* Nothing to do */ } +PRE_SYSCALL(reboot)(long long opt_, void *bootstr_) { +  const char *bootstr = (const char *)bootstr_; +  if (bootstr) { +    PRE_READ(bootstr, __sanitizer::internal_strlen(bootstr) + 1); +  } +} +POST_SYSCALL(reboot)(long long res, long long opt_, void *bootstr_) { +  /* This call should never return */ +  const char *bootstr = (const char *)bootstr_; +  if (bootstr) { +    POST_READ(bootstr, __sanitizer::internal_strlen(bootstr) + 1); +  } +} +PRE_SYSCALL(poll)(void *fds_, long long nfds_, long long timeout_) { +  /* Nothing to do */ +} +POST_SYSCALL(poll) +(long long res, void *fds_, long long nfds_, long long timeout_) { +  /* Nothing to do */ +} +PRE_SYSCALL(afssys) +(long long id_, long long a1_, long long a2_, long long a3_, long long a4_, +  long long a5_, long long a6_) { +  /* TODO */ +} +POST_SYSCALL(afssys) +(long long res, long long id_, long long a1_, long long a2_, long long a3_, +  long long a4_, long long a5_, long long a6_) { +  /* TODO */ +} +/* syscall 211 has been skipped */ +/* syscall 212 has been skipped */ +/* syscall 213 has been skipped */ +/* syscall 214 has been skipped */ +/* syscall 215 has been skipped */ +/* syscall 216 has been skipped */ +/* syscall 217 has been skipped */ +/* syscall 218 has been skipped */ +/* syscall 219 has been skipped */ +PRE_SYSCALL(compat_14___semctl) +(long long semid_, long long semnum_, long long cmd_, void *arg_) { +  /* TODO */ +} +POST_SYSCALL(compat_14___semctl) +(long long res, long long semid_, long long semnum_, long long cmd_, +  void *arg_) { +  /* TODO */ +} +PRE_SYSCALL(semget)(long long key_, long long nsems_, long long semflg_) { +  /* Nothing to do */ +} +POST_SYSCALL(semget) +(long long res, long long key_, long long nsems_, long long semflg_) { +  /* Nothing to do */ +} +PRE_SYSCALL(semop)(long long semid_, void *sops_, long long nsops_) { +  if (sops_) { +    PRE_READ(sops_, nsops_ * struct_sembuf_sz); +  } +} +POST_SYSCALL(semop) +(long long res, long long semid_, void *sops_, long long nsops_) { +  if (res == 0) { +    if (sops_) { +      POST_READ(sops_, nsops_ * struct_sembuf_sz); +    } +  } +} +PRE_SYSCALL(semconfig)(long long flag_) { /* Nothing to do */ } +POST_SYSCALL(semconfig)(long long res, long long flag_) { /* Nothing to do */ } +PRE_SYSCALL(compat_14_msgctl)(long long msqid_, long long cmd_, void *buf_) { +  /* TODO */ +} +POST_SYSCALL(compat_14_msgctl) +(long long res, long long msqid_, long long cmd_, void *buf_) { +  /* TODO */ +} +PRE_SYSCALL(msgget)(long long key_, long long msgflg_) { /* Nothing to do */ } +POST_SYSCALL(msgget)(long long res, long long key_, long long msgflg_) { +  /* Nothing to do */ +} +PRE_SYSCALL(msgsnd) +(long long msqid_, void *msgp_, long long msgsz_, long long msgflg_) { +  if (msgp_) { +    PRE_READ(msgp_, msgsz_); +  } +} +POST_SYSCALL(msgsnd) +(long long res, long long msqid_, void *msgp_, long long msgsz_, +  long long msgflg_) { +  if (res == 0) { +    if (msgp_) { +      POST_READ(msgp_, msgsz_); +    } +  } +} +PRE_SYSCALL(msgrcv) +(long long msqid_, void *msgp_, long long msgsz_, long long msgtyp_, +  long long msgflg_) { +  /* Nothing to do */ +} +POST_SYSCALL(msgrcv) +(long long res, long long msqid_, void *msgp_, long long msgsz_, +  long long msgtyp_, long long msgflg_) { +  /* Nothing to do */ +} +PRE_SYSCALL(shmat)(long long shmid_, void *shmaddr_, long long shmflg_) { +  /* Nothing to do */ +} +POST_SYSCALL(shmat) +(long long res, long long shmid_, void *shmaddr_, long long shmflg_) { +  /* Nothing to do */ +} +PRE_SYSCALL(compat_14_shmctl)(long long shmid_, long long cmd_, void *buf_) { +  /* TODO */ +} +POST_SYSCALL(compat_14_shmctl) +(long long res, long long shmid_, long long cmd_, void *buf_) { +  /* TODO */ +} +PRE_SYSCALL(shmdt)(void *shmaddr_) { /* Nothing to do */ } +POST_SYSCALL(shmdt)(long long res, void *shmaddr_) { /* Nothing to do */ } +PRE_SYSCALL(shmget)(long long key_, long long size_, long long shmflg_) { +  /* Nothing to do */ +} +POST_SYSCALL(shmget) +(long long res, long long key_, long long size_, long long shmflg_) { +  /* Nothing to do */ +} +PRE_SYSCALL(compat_50_clock_gettime)(long long clock_id_, void *tp_) { +  /* TODO */ +} +POST_SYSCALL(compat_50_clock_gettime) +(long long res, long long clock_id_, void *tp_) { +  /* TODO */ +} +PRE_SYSCALL(compat_50_clock_settime)(long long clock_id_, void *tp_) { +  /* TODO */ +} +POST_SYSCALL(compat_50_clock_settime) +(long long res, long long clock_id_, void *tp_) { +  /* TODO */ +} +PRE_SYSCALL(compat_50_clock_getres)(long long clock_id_, void *tp_) { +  /* TODO */ +} +POST_SYSCALL(compat_50_clock_getres) +(long long res, long long clock_id_, void *tp_) { +  /* TODO */ +} +PRE_SYSCALL(timer_create)(long long clock_id_, void *evp_, void *timerid_) { +  /* Nothing to do */ +} +POST_SYSCALL(timer_create) +(long long res, long long clock_id_, void *evp_, void *timerid_) { +  /* Nothing to do */ +} +PRE_SYSCALL(timer_delete)(long long timerid_) { /* Nothing to do */ } +POST_SYSCALL(timer_delete)(long long res, long long timerid_) { +  /* Nothing to do */ +} +PRE_SYSCALL(compat_50_timer_settime) +(long long timerid_, long long flags_, void *value_, void *ovalue_) { +  /* TODO */ +} +POST_SYSCALL(compat_50_timer_settime) +(long long res, long long timerid_, long long flags_, void *value_, +  void *ovalue_) { +  /* TODO */ +} +PRE_SYSCALL(compat_50_timer_gettime)(long long timerid_, void *value_) { +  /* TODO */ +} +POST_SYSCALL(compat_50_timer_gettime) +(long long res, long long timerid_, void *value_) { +  /* TODO */ +} +PRE_SYSCALL(timer_getoverrun)(long long timerid_) { /* Nothing to do */ } +POST_SYSCALL(timer_getoverrun)(long long res, long long timerid_) { +  /* Nothing to do */ +} +PRE_SYSCALL(compat_50_nanosleep)(void *rqtp_, void *rmtp_) { /* TODO */ } +POST_SYSCALL(compat_50_nanosleep)(long long res, void *rqtp_, void *rmtp_) { +  /* TODO */ +} +PRE_SYSCALL(fdatasync)(long long fd_) { /* Nothing to do */ } +POST_SYSCALL(fdatasync)(long long res, long long fd_) { /* Nothing to do */ } +PRE_SYSCALL(mlockall)(long long flags_) { /* Nothing to do */ } +POST_SYSCALL(mlockall)(long long res, long long flags_) { /* Nothing to do */ } +PRE_SYSCALL(munlockall)(void) { /* Nothing to do */ } +POST_SYSCALL(munlockall)(long long res) { /* Nothing to do */ } +PRE_SYSCALL(compat_50___sigtimedwait)(void *set_, void *info_, void *timeout_) { +  /* TODO */ +} +POST_SYSCALL(compat_50___sigtimedwait) +(long long res, void *set_, void *info_, void *timeout_) { +  /* TODO */ +} +PRE_SYSCALL(sigqueueinfo)(long long pid_, void *info_) { +  if (info_) { +    PRE_READ(info_, siginfo_t_sz); +  } +} +POST_SYSCALL(sigqueueinfo)(long long res, long long pid_, void *info_) {} +PRE_SYSCALL(modctl)(long long cmd_, void *arg_) { /* TODO */ } +POST_SYSCALL(modctl)(long long res, long long cmd_, void *arg_) { /* TODO */ } +PRE_SYSCALL(_ksem_init)(long long value_, void *idp_) { /* Nothing to do */ } +POST_SYSCALL(_ksem_init)(long long res, long long value_, void *idp_) { +  /* Nothing to do */ +} +PRE_SYSCALL(_ksem_open) +(void *name_, long long oflag_, long long mode_, long long value_, void *idp_) { +  const char *name = (const char *)name_; +  if (name) { +    PRE_READ(name, __sanitizer::internal_strlen(name) + 1); +  } +} +POST_SYSCALL(_ksem_open) +(long long res, void *name_, long long oflag_, long long mode_, +  long long value_, void *idp_) { +  const char *name = (const char *)name_; +  if (name) { +    POST_READ(name, __sanitizer::internal_strlen(name) + 1); +  } +} +PRE_SYSCALL(_ksem_unlink)(void *name_) { +  const char *name = (const char *)name_; +  if (name) { +    PRE_READ(name, __sanitizer::internal_strlen(name) + 1); +  } +} +POST_SYSCALL(_ksem_unlink)(long long res, void *name_) { +  const char *name = (const char *)name_; +  if (name) { +    POST_READ(name, __sanitizer::internal_strlen(name) + 1); +  } +} +PRE_SYSCALL(_ksem_close)(long long id_) { /* Nothing to do */ } +POST_SYSCALL(_ksem_close)(long long res, long long id_) { /* Nothing to do */ } +PRE_SYSCALL(_ksem_post)(long long id_) { /* Nothing to do */ } +POST_SYSCALL(_ksem_post)(long long res, long long id_) { /* Nothing to do */ } +PRE_SYSCALL(_ksem_wait)(long long id_) { /* Nothing to do */ } +POST_SYSCALL(_ksem_wait)(long long res, long long id_) { /* Nothing to do */ } +PRE_SYSCALL(_ksem_trywait)(long long id_) { /* Nothing to do */ } +POST_SYSCALL(_ksem_trywait)(long long res, long long id_) { +  /* Nothing to do */ +} +PRE_SYSCALL(_ksem_getvalue)(long long id_, void *value_) { /* Nothing to do */ } +POST_SYSCALL(_ksem_getvalue)(long long res, long long id_, void *value_) { +  /* Nothing to do */ +} +PRE_SYSCALL(_ksem_destroy)(long long id_) { /* Nothing to do */ } +POST_SYSCALL(_ksem_destroy)(long long res, long long id_) { +  /* Nothing to do */ +} +PRE_SYSCALL(_ksem_timedwait)(long long id_, void *abstime_) { +  if (abstime_) { +    PRE_READ(abstime_, struct_timespec_sz); +  } +} +POST_SYSCALL(_ksem_timedwait)(long long res, long long id_, void *abstime_) {} +PRE_SYSCALL(mq_open) +(void *name_, long long oflag_, long long mode_, void *attr_) { +  const char *name = (const char *)name_; +  if (name) { +    PRE_READ(name, __sanitizer::internal_strlen(name) + 1); +  } +} +POST_SYSCALL(mq_open) +(long long res, void *name_, long long oflag_, long long mode_, void *attr_) { +  const char *name = (const char *)name_; +  if (name) { +    POST_READ(name, __sanitizer::internal_strlen(name) + 1); +  } +} +PRE_SYSCALL(mq_close)(long long mqdes_) { /* Nothing to do */ } +POST_SYSCALL(mq_close)(long long res, long long mqdes_) { /* Nothing to do */ } +PRE_SYSCALL(mq_unlink)(void *name_) { +  const char *name = (const char *)name_; +  if (name) { +    PRE_READ(name, __sanitizer::internal_strlen(name) + 1); +  } +} +POST_SYSCALL(mq_unlink)(long long res, void *name_) { +  const char *name = (const char *)name_; +  if (name) { +    POST_READ(name, __sanitizer::internal_strlen(name) + 1); +  } +} +PRE_SYSCALL(mq_getattr)(long long mqdes_, void *mqstat_) { /* Nothing to do */ } +POST_SYSCALL(mq_getattr)(long long res, long long mqdes_, void *mqstat_) { +  /* Nothing to do */ +} +PRE_SYSCALL(mq_setattr)(long long mqdes_, void *mqstat_, void *omqstat_) { +  if (mqstat_) { +    PRE_READ(mqstat_, struct_mq_attr_sz); +  } +} +POST_SYSCALL(mq_setattr) +(long long res, long long mqdes_, void *mqstat_, void *omqstat_) {} +PRE_SYSCALL(mq_notify)(long long mqdes_, void *notification_) { +  if (notification_) { +    PRE_READ(notification_, struct_sigevent_sz); +  } +} +POST_SYSCALL(mq_notify)(long long res, long long mqdes_, void *notification_) {} +PRE_SYSCALL(mq_send) +(long long mqdes_, void *msg_ptr_, long long msg_len_, long long msg_prio_) { +  if (msg_ptr_) { +    PRE_READ(msg_ptr_, msg_len_); +  } +} +POST_SYSCALL(mq_send) +(long long res, long long mqdes_, void *msg_ptr_, long long msg_len_, +  long long msg_prio_) {} +PRE_SYSCALL(mq_receive) +(long long mqdes_, void *msg_ptr_, long long msg_len_, void *msg_prio_) { +  /* Nothing to do */ +} +POST_SYSCALL(mq_receive) +(long long res, long long mqdes_, void *msg_ptr_, long long msg_len_, +  void *msg_prio_) { +  /* Nothing to do */ +} +PRE_SYSCALL(compat_50_mq_timedsend) +(long long mqdes_, void *msg_ptr_, long long msg_len_, long long msg_prio_, +  void *abs_timeout_) { +  /* TODO */ +} +POST_SYSCALL(compat_50_mq_timedsend) +(long long res, long long mqdes_, void *msg_ptr_, long long msg_len_, +  long long msg_prio_, void *abs_timeout_) { +  /* TODO */ +} +PRE_SYSCALL(compat_50_mq_timedreceive) +(long long mqdes_, void *msg_ptr_, long long msg_len_, void *msg_prio_, +  void *abs_timeout_) { +  /* TODO */ +} +POST_SYSCALL(compat_50_mq_timedreceive) +(long long res, long long mqdes_, void *msg_ptr_, long long msg_len_, +  void *msg_prio_, void *abs_timeout_) { +  /* TODO */ +} +/* syscall 267 has been skipped */ +/* syscall 268 has been skipped */ +/* syscall 269 has been skipped */ +PRE_SYSCALL(__posix_rename)(void *from_, void *to_) { +  const char *from = (const char *)from_; +  const char *to = (const char *)to_; +  if (from_) { +    PRE_READ(from, __sanitizer::internal_strlen(from) + 1); +  } +  if (to) { +    PRE_READ(to, __sanitizer::internal_strlen(to) + 1); +  } +} +POST_SYSCALL(__posix_rename)(long long res, void *from_, void *to_) { +  const char *from = (const char *)from_; +  const char *to = (const char *)to_; +  if (from) { +    POST_READ(from, __sanitizer::internal_strlen(from) + 1); +  } +  if (to) { +    POST_READ(to, __sanitizer::internal_strlen(to) + 1); +  } +} +PRE_SYSCALL(swapctl)(long long cmd_, void *arg_, long long misc_) { /* TODO */ } +POST_SYSCALL(swapctl) +(long long res, long long cmd_, void *arg_, long long misc_) { +  /* TODO */ +} +PRE_SYSCALL(compat_30_getdents)(long long fd_, void *buf_, long long count_) { +  /* TODO */ +} +POST_SYSCALL(compat_30_getdents) +(long long res, long long fd_, void *buf_, long long count_) { +  /* TODO */ +} +PRE_SYSCALL(minherit)(void *addr_, long long len_, long long inherit_) { +  /* Nothing to do */ +} +POST_SYSCALL(minherit) +(long long res, void *addr_, long long len_, long long inherit_) { +  /* Nothing to do */ +} +PRE_SYSCALL(lchmod)(void *path_, long long mode_) { +  const char *path = (const char *)path_; +  if (path) { +    PRE_READ(path, __sanitizer::internal_strlen(path) + 1); +  } +} +POST_SYSCALL(lchmod)(long long res, void *path_, long long mode_) { +  const char *path = (const char *)path_; +  if (path) { +    POST_READ(path, __sanitizer::internal_strlen(path) + 1); +  } +} +PRE_SYSCALL(lchown)(void *path_, long long uid_, long long gid_) { +  const char *path = (const char *)path_; +  if (path) { +    PRE_READ(path, __sanitizer::internal_strlen(path) + 1); +  } +} +POST_SYSCALL(lchown) +(long long res, void *path_, long long uid_, long long gid_) { +  const char *path = (const char *)path_; +  if (path) { +    POST_READ(path, __sanitizer::internal_strlen(path) + 1); +  } +} +PRE_SYSCALL(compat_50_lutimes)(void *path_, void *tptr_) { /* TODO */ } +POST_SYSCALL(compat_50_lutimes)(long long res, void *path_, void *tptr_) { +  /* TODO */ +} +PRE_SYSCALL(__msync13)(void *addr_, long long len_, long long flags_) { +  /* Nothing to do */ +} +POST_SYSCALL(__msync13) +(long long res, void *addr_, long long len_, long long flags_) { +  /* Nothing to do */ +} +PRE_SYSCALL(compat_30___stat13)(void *path_, void *ub_) { /* TODO */ } +POST_SYSCALL(compat_30___stat13)(long long res, void *path_, void *ub_) { +  /* TODO */ +} +PRE_SYSCALL(compat_30___fstat13)(long long fd_, void *sb_) { /* TODO */ } +POST_SYSCALL(compat_30___fstat13)(long long res, long long fd_, void *sb_) { +  /* TODO */ +} +PRE_SYSCALL(compat_30___lstat13)(void *path_, void *ub_) { /* TODO */ } +POST_SYSCALL(compat_30___lstat13)(long long res, void *path_, void *ub_) { +  /* TODO */ +} +PRE_SYSCALL(__sigaltstack14)(void *nss_, void *oss_) { +  if (nss_) { +    PRE_READ(nss_, struct_sigaltstack_sz); +  } +  if (oss_) { +    PRE_READ(oss_, struct_sigaltstack_sz); +  } +} +POST_SYSCALL(__sigaltstack14)(long long res, void *nss_, void *oss_) {} +PRE_SYSCALL(__vfork14)(void) { /* Nothing to do */ } +POST_SYSCALL(__vfork14)(long long res) { /* Nothing to do */ } +PRE_SYSCALL(__posix_chown)(void *path_, long long uid_, long long gid_) { +  const char *path = (const char *)path_; +  if (path) { +    PRE_READ(path, __sanitizer::internal_strlen(path) + 1); +  } +} +POST_SYSCALL(__posix_chown) +(long long res, void *path_, long long uid_, long long gid_) { +  const char *path = (const char *)path_; +  if (path) { +    POST_READ(path, __sanitizer::internal_strlen(path) + 1); +  } +} +PRE_SYSCALL(__posix_fchown)(long long fd_, long long uid_, long long gid_) { +  /* Nothing to do */ +} +POST_SYSCALL(__posix_fchown) +(long long res, long long fd_, long long uid_, long long gid_) { +  /* Nothing to do */ +} +PRE_SYSCALL(__posix_lchown)(void *path_, long long uid_, long long gid_) { +  const char *path = (const char *)path_; +  if (path) { +    PRE_READ(path, __sanitizer::internal_strlen(path) + 1); +  } +} +POST_SYSCALL(__posix_lchown) +(long long res, void *path_, long long uid_, long long gid_) { +  const char *path = (const char *)path_; +  if (path) { +    POST_READ(path, __sanitizer::internal_strlen(path) + 1); +  } +} +PRE_SYSCALL(getsid)(long long pid_) { /* Nothing to do */ } +POST_SYSCALL(getsid)(long long res, long long pid_) { /* Nothing to do */ } +PRE_SYSCALL(__clone)(long long flags_, void *stack_) { /* Nothing to do */ } +POST_SYSCALL(__clone)(long long res, long long flags_, void *stack_) { +  /* Nothing to do */ +} +PRE_SYSCALL(fktrace) +(long long fd_, long long ops_, long long facs_, long long pid_) { +  /* Nothing to do */ +} +POST_SYSCALL(fktrace) +(long long res, long long fd_, long long ops_, long long facs_, +  long long pid_) { +  /* Nothing to do */ +} +PRE_SYSCALL(preadv) +(long long fd_, void *iovp_, long long iovcnt_, long long PAD_, +  long long offset_) { +  /* Nothing to do */ +} +POST_SYSCALL(preadv) +(long long res, long long fd_, void *iovp_, long long iovcnt_, long long PAD_, +  long long offset_) { +  /* Nothing to do */ +} +PRE_SYSCALL(pwritev) +(long long fd_, void *iovp_, long long iovcnt_, long long PAD_, +  long long offset_) { +  /* Nothing to do */ +} +POST_SYSCALL(pwritev) +(long long res, long long fd_, void *iovp_, long long iovcnt_, long long PAD_, +  long long offset_) { +  /* Nothing to do */ +} +PRE_SYSCALL(compat_16___sigaction14) +(long long signum_, void *nsa_, void *osa_) { +  /* TODO */ +} +POST_SYSCALL(compat_16___sigaction14) +(long long res, long long signum_, void *nsa_, void *osa_) { +  /* TODO */ +} +PRE_SYSCALL(__sigpending14)(void *set_) { /* Nothing to do */ } +POST_SYSCALL(__sigpending14)(long long res, void *set_) { /* Nothing to do */ } +PRE_SYSCALL(__sigprocmask14)(long long how_, void *set_, void *oset_) { +  /* Nothing to do */ +} +POST_SYSCALL(__sigprocmask14) +(long long res, long long how_, void *set_, void *oset_) { +  /* Nothing to do */ +} +PRE_SYSCALL(__sigsuspend14)(void *set_) { +  if (set_) { +    PRE_READ(set_, sizeof(__sanitizer_sigset_t)); +  } +} +POST_SYSCALL(__sigsuspend14)(long long res, void *set_) { +  if (set_) { +    PRE_READ(set_, sizeof(__sanitizer_sigset_t)); +  } +} +PRE_SYSCALL(compat_16___sigreturn14)(void *sigcntxp_) { /* TODO */ } +POST_SYSCALL(compat_16___sigreturn14)(long long res, void *sigcntxp_) { +  /* TODO */ +} +PRE_SYSCALL(__getcwd)(void *bufp_, long long length_) { /* Nothing to do */ } +POST_SYSCALL(__getcwd)(long long res, void *bufp_, long long length_) { +  /* Nothing to do */ +} +PRE_SYSCALL(fchroot)(long long fd_) { /* Nothing to do */ } +POST_SYSCALL(fchroot)(long long res, long long fd_) { /* Nothing to do */ } +PRE_SYSCALL(compat_30_fhopen)(void *fhp_, long long flags_) { /* TODO */ } +POST_SYSCALL(compat_30_fhopen)(long long res, void *fhp_, long long flags_) { +  /* TODO */ +} +PRE_SYSCALL(compat_30_fhstat)(void *fhp_, void *sb_) { /* TODO */ } +POST_SYSCALL(compat_30_fhstat)(long long res, void *fhp_, void *sb_) { +  /* TODO */ +} +PRE_SYSCALL(compat_20_fhstatfs)(void *fhp_, void *buf_) { /* TODO */ } +POST_SYSCALL(compat_20_fhstatfs)(long long res, void *fhp_, void *buf_) { +  /* TODO */ +} +PRE_SYSCALL(compat_50_____semctl13) +(long long semid_, long long semnum_, long long cmd_, void *arg_) { +  /* TODO */ +} +POST_SYSCALL(compat_50_____semctl13) +(long long res, long long semid_, long long semnum_, long long cmd_, +  void *arg_) { +  /* TODO */ +} +PRE_SYSCALL(compat_50___msgctl13) +(long long msqid_, long long cmd_, void *buf_) { +  /* TODO */ +} +POST_SYSCALL(compat_50___msgctl13) +(long long res, long long msqid_, long long cmd_, void *buf_) { +  /* TODO */ +} +PRE_SYSCALL(compat_50___shmctl13) +(long long shmid_, long long cmd_, void *buf_) { +  /* TODO */ +} +POST_SYSCALL(compat_50___shmctl13) +(long long res, long long shmid_, long long cmd_, void *buf_) { +  /* TODO */ +} +PRE_SYSCALL(lchflags)(void *path_, long long flags_) { +  const char *path = (const char *)path_; +  if (path) { +    PRE_READ(path, __sanitizer::internal_strlen(path) + 1); +  } +} +POST_SYSCALL(lchflags)(long long res, void *path_, long long flags_) { +  const char *path = (const char *)path_; +  if (path) { +    POST_READ(path, __sanitizer::internal_strlen(path) + 1); +  } +} +PRE_SYSCALL(issetugid)(void) { /* Nothing to do */ } +POST_SYSCALL(issetugid)(long long res) { /* Nothing to do */ } +PRE_SYSCALL(utrace)(void *label_, void *addr_, long long len_) { +  const char *label = (const char *)label_; +  if (label) { +    PRE_READ(label, __sanitizer::internal_strlen(label) + 1); +  } +  if (addr_) { +    PRE_READ(addr_, len_); +  } +} +POST_SYSCALL(utrace)(long long res, void *label_, void *addr_, long long len_) { +  const char *label = (const char *)label_; +  if (label) { +    POST_READ(label, __sanitizer::internal_strlen(label) + 1); +  } +  if (addr_) { +    POST_READ(addr_, len_); +  } +} +PRE_SYSCALL(getcontext)(void *ucp_) { /* Nothing to do */ } +POST_SYSCALL(getcontext)(long long res, void *ucp_) { /* Nothing to do */ } +PRE_SYSCALL(setcontext)(void *ucp_) { +  if (ucp_) { +    PRE_READ(ucp_, ucontext_t_sz); +  } +} +POST_SYSCALL(setcontext)(long long res, void *ucp_) {} +PRE_SYSCALL(_lwp_create)(void *ucp_, long long flags_, void *new_lwp_) { +  if (ucp_) { +    PRE_READ(ucp_, ucontext_t_sz); +  } +} +POST_SYSCALL(_lwp_create) +(long long res, void *ucp_, long long flags_, void *new_lwp_) {} +PRE_SYSCALL(_lwp_exit)(void) { /* Nothing to do */ } +POST_SYSCALL(_lwp_exit)(long long res) { /* Nothing to do */ } +PRE_SYSCALL(_lwp_self)(void) { /* Nothing to do */ } +POST_SYSCALL(_lwp_self)(long long res) { /* Nothing to do */ } +PRE_SYSCALL(_lwp_wait)(long long wait_for_, void *departed_) { +  /* Nothing to do */ +} +POST_SYSCALL(_lwp_wait)(long long res, long long wait_for_, void *departed_) { +  /* Nothing to do */ +} +PRE_SYSCALL(_lwp_suspend)(long long target_) { /* Nothing to do */ } +POST_SYSCALL(_lwp_suspend)(long long res, long long target_) { +  /* Nothing to do */ +} +PRE_SYSCALL(_lwp_continue)(long long target_) { /* Nothing to do */ } +POST_SYSCALL(_lwp_continue)(long long res, long long target_) { +  /* Nothing to do */ +} +PRE_SYSCALL(_lwp_wakeup)(long long target_) { /* Nothing to do */ } +POST_SYSCALL(_lwp_wakeup)(long long res, long long target_) { +  /* Nothing to do */ +} +PRE_SYSCALL(_lwp_getprivate)(void) { /* Nothing to do */ } +POST_SYSCALL(_lwp_getprivate)(long long res) { /* Nothing to do */ } +PRE_SYSCALL(_lwp_setprivate)(void *ptr_) { /* Nothing to do */ } +POST_SYSCALL(_lwp_setprivate)(long long res, void *ptr_) { /* Nothing to do */ } +PRE_SYSCALL(_lwp_kill)(long long target_, long long signo_) { +  /* Nothing to do */ +} +POST_SYSCALL(_lwp_kill)(long long res, long long target_, long long signo_) { +  /* Nothing to do */ +} +PRE_SYSCALL(_lwp_detach)(long long target_) { /* Nothing to do */ } +POST_SYSCALL(_lwp_detach)(long long res, long long target_) { +  /* Nothing to do */ +} +PRE_SYSCALL(compat_50__lwp_park) +(void *ts_, long long unpark_, void *hint_, void *unparkhint_) { +  /* TODO */ +} +POST_SYSCALL(compat_50__lwp_park) +(long long res, void *ts_, long long unpark_, void *hint_, void *unparkhint_) { +  /* TODO */ +} +PRE_SYSCALL(_lwp_unpark)(long long target_, void *hint_) { /* Nothing to do */ } +POST_SYSCALL(_lwp_unpark)(long long res, long long target_, void *hint_) { +  /* Nothing to do */ +} +PRE_SYSCALL(_lwp_unpark_all)(void *targets_, long long ntargets_, void *hint_) { +  if (targets_) { +    PRE_READ(targets_, ntargets_ * sizeof(__sanitizer_lwpid_t)); +  } +} +POST_SYSCALL(_lwp_unpark_all) +(long long res, void *targets_, long long ntargets_, void *hint_) {} +PRE_SYSCALL(_lwp_setname)(long long target_, void *name_) { +  const char *name = (const char *)name_; +  if (name) { +    PRE_READ(name, __sanitizer::internal_strlen(name) + 1); +  } +} +POST_SYSCALL(_lwp_setname)(long long res, long long target_, void *name_) { +  const char *name = (const char *)name_; +  if (name) { +    POST_READ(name, __sanitizer::internal_strlen(name) + 1); +  } +} +PRE_SYSCALL(_lwp_getname)(long long target_, void *name_, long long len_) { +  /* Nothing to do */ +} +POST_SYSCALL(_lwp_getname) +(long long res, long long target_, void *name_, long long len_) { +  /* Nothing to do */ +} +PRE_SYSCALL(_lwp_ctl)(long long features_, void **address_) { +  /* Nothing to do */ +} +POST_SYSCALL(_lwp_ctl)(long long res, long long features_, void **address_) { +  /* Nothing to do */ +} +/* syscall 326 has been skipped */ +/* syscall 327 has been skipped */ +/* syscall 328 has been skipped */ +/* syscall 329 has been skipped */ +PRE_SYSCALL(compat_60_sa_register) +(void *newv_, void **oldv_, long long flags_, long long stackinfo_offset_) { +  /* TODO */ +} +POST_SYSCALL(compat_60_sa_register) +(long long res, void *newv_, void **oldv_, long long flags_, +  long long stackinfo_offset_) { +  /* TODO */ +} +PRE_SYSCALL(compat_60_sa_stacks)(long long num_, void *stacks_) { /* TODO */ } +POST_SYSCALL(compat_60_sa_stacks) +(long long res, long long num_, void *stacks_) { +  /* TODO */ +} +PRE_SYSCALL(compat_60_sa_enable)(void) { /* TODO */ } +POST_SYSCALL(compat_60_sa_enable)(long long res) { /* TODO */ } +PRE_SYSCALL(compat_60_sa_setconcurrency)(long long concurrency_) { /* TODO */ } +POST_SYSCALL(compat_60_sa_setconcurrency) +(long long res, long long concurrency_) { +  /* TODO */ +} +PRE_SYSCALL(compat_60_sa_yield)(void) { /* TODO */ } +POST_SYSCALL(compat_60_sa_yield)(long long res) { /* TODO */ } +PRE_SYSCALL(compat_60_sa_preempt)(long long sa_id_) { /* TODO */ } +POST_SYSCALL(compat_60_sa_preempt)(long long res, long long sa_id_) { +  /* TODO */ +} +/* syscall 336 has been skipped */ +/* syscall 337 has been skipped */ +/* syscall 338 has been skipped */ +/* syscall 339 has been skipped */ +PRE_SYSCALL(__sigaction_sigtramp) +(long long signum_, void *nsa_, void *osa_, void *tramp_, long long vers_) { +  if (nsa_) { +    PRE_READ(nsa_, sizeof(__sanitizer_sigaction)); +  } +} +POST_SYSCALL(__sigaction_sigtramp) +(long long res, long long signum_, void *nsa_, void *osa_, void *tramp_, +  long long vers_) { +  if (nsa_) { +    PRE_READ(nsa_, sizeof(__sanitizer_sigaction)); +  } +} +PRE_SYSCALL(pmc_get_info)(long long ctr_, long long op_, void *args_) { +  /* TODO */ +} +POST_SYSCALL(pmc_get_info) +(long long res, long long ctr_, long long op_, void *args_) { +  /* TODO */ +} +PRE_SYSCALL(pmc_control)(long long ctr_, long long op_, void *args_) { +  /* TODO */ +} +POST_SYSCALL(pmc_control) +(long long res, long long ctr_, long long op_, void *args_) { +  /* TODO */ +} +PRE_SYSCALL(rasctl)(void *addr_, long long len_, long long op_) { +  /* Nothing to do */ +} +POST_SYSCALL(rasctl) +(long long res, void *addr_, long long len_, long long op_) { +  /* Nothing to do */ +} +PRE_SYSCALL(kqueue)(void) { /* Nothing to do */ } +POST_SYSCALL(kqueue)(long long res) { /* Nothing to do */ } +PRE_SYSCALL(compat_50_kevent) +(long long fd_, void *changelist_, long long nchanges_, void *eventlist_, +  long long nevents_, void *timeout_) { +  /* TODO */ +} +POST_SYSCALL(compat_50_kevent) +(long long res, long long fd_, void *changelist_, long long nchanges_, +  void *eventlist_, long long nevents_, void *timeout_) { +  /* TODO */ +} +PRE_SYSCALL(_sched_setparam) +(long long pid_, long long lid_, long long policy_, void *params_) { +  if (params_) { +    PRE_READ(params_, struct_sched_param_sz); +  } +} +POST_SYSCALL(_sched_setparam) +(long long res, long long pid_, long long lid_, long long policy_, +  void *params_) { +  if (params_) { +    PRE_READ(params_, struct_sched_param_sz); +  } +} +PRE_SYSCALL(_sched_getparam) +(long long pid_, long long lid_, void *policy_, void *params_) { +  /* Nothing to do */ +} +POST_SYSCALL(_sched_getparam) +(long long res, long long pid_, long long lid_, void *policy_, void *params_) { +  /* Nothing to do */ +} +PRE_SYSCALL(_sched_setaffinity) +(long long pid_, long long lid_, long long size_, void *cpuset_) { +  if (cpuset_) { +    PRE_READ(cpuset_, size_); +  } +} +POST_SYSCALL(_sched_setaffinity) +(long long res, long long pid_, long long lid_, long long size_, +  void *cpuset_) { +  if (cpuset_) { +    PRE_READ(cpuset_, size_); +  } +} +PRE_SYSCALL(_sched_getaffinity) +(long long pid_, long long lid_, long long size_, void *cpuset_) { +  /* Nothing to do */ +} +POST_SYSCALL(_sched_getaffinity) +(long long res, long long pid_, long long lid_, long long size_, +  void *cpuset_) { +  /* Nothing to do */ +} +PRE_SYSCALL(sched_yield)(void) { /* Nothing to do */ } +POST_SYSCALL(sched_yield)(long long res) { /* Nothing to do */ } +PRE_SYSCALL(_sched_protect)(long long priority_) { /* Nothing to do */ } +POST_SYSCALL(_sched_protect)(long long res, long long priority_) { +  /* Nothing to do */ +} +/* syscall 352 has been skipped */ +/* syscall 353 has been skipped */ +PRE_SYSCALL(fsync_range) +(long long fd_, long long flags_, long long start_, long long length_) { +  /* Nothing to do */ +} +POST_SYSCALL(fsync_range) +(long long res, long long fd_, long long flags_, long long start_, +  long long length_) { +  /* Nothing to do */ +} +PRE_SYSCALL(uuidgen)(void *store_, long long count_) { /* Nothing to do */ } +POST_SYSCALL(uuidgen)(long long res, void *store_, long long count_) { +  /* Nothing to do */ +} +PRE_SYSCALL(getvfsstat)(void *buf_, long long bufsize_, long long flags_) { +  /* Nothing to do */ +} +POST_SYSCALL(getvfsstat) +(long long res, void *buf_, long long bufsize_, long long flags_) { +  /* Nothing to do */ +} +PRE_SYSCALL(statvfs1)(void *path_, void *buf_, long long flags_) { +  const char *path = (const char *)path_; +  if (path) { +    PRE_READ(path, __sanitizer::internal_strlen(path) + 1); +  } +} +POST_SYSCALL(statvfs1) +(long long res, void *path_, void *buf_, long long flags_) { +  const char *path = (const char *)path_; +  if (path) { +    POST_READ(path, __sanitizer::internal_strlen(path) + 1); +  } +} +PRE_SYSCALL(fstatvfs1)(long long fd_, void *buf_, long long flags_) { +  /* Nothing to do */ +} +POST_SYSCALL(fstatvfs1) +(long long res, long long fd_, void *buf_, long long flags_) { +  /* Nothing to do */ +} +PRE_SYSCALL(compat_30_fhstatvfs1)(void *fhp_, void *buf_, long long flags_) { +  /* TODO */ +} +POST_SYSCALL(compat_30_fhstatvfs1) +(long long res, void *fhp_, void *buf_, long long flags_) { +  /* TODO */ +} +PRE_SYSCALL(extattrctl) +(void *path_, long long cmd_, void *filename_, long long attrnamespace_, +  void *attrname_) { +  const char *path = (const char *)path_; +  if (path) { +    PRE_READ(path, __sanitizer::internal_strlen(path) + 1); +  } +} +POST_SYSCALL(extattrctl) +(long long res, void *path_, long long cmd_, void *filename_, +  long long attrnamespace_, void *attrname_) { +  const char *path = (const char *)path_; +  if (path) { +    POST_READ(path, __sanitizer::internal_strlen(path) + 1); +  } +} +PRE_SYSCALL(extattr_set_file) +(void *path_, long long attrnamespace_, void *attrname_, void *data_, +  long long nbytes_) { +  const char *path = (const char *)path_; +  if (path) { +    PRE_READ(path, __sanitizer::internal_strlen(path) + 1); +  } +} +POST_SYSCALL(extattr_set_file) +(long long res, void *path_, long long attrnamespace_, void *attrname_, +  void *data_, long long nbytes_) { +  const char *path = (const char *)path_; +  if (path) { +    POST_READ(path, __sanitizer::internal_strlen(path) + 1); +  } +} +PRE_SYSCALL(extattr_get_file) +(void *path_, long long attrnamespace_, void *attrname_, void *data_, +  long long nbytes_) { +  const char *path = (const char *)path_; +  if (path) { +    PRE_READ(path, __sanitizer::internal_strlen(path) + 1); +  } +} +POST_SYSCALL(extattr_get_file) +(long long res, void *path_, long long attrnamespace_, void *attrname_, +  void *data_, long long nbytes_) { +  const char *path = (const char *)path_; +  if (path) { +    POST_READ(path, __sanitizer::internal_strlen(path) + 1); +  } +} +PRE_SYSCALL(extattr_delete_file) +(void *path_, long long attrnamespace_, void *attrname_) { +  const char *path = (const char *)path_; +  if (path) { +    PRE_READ(path, __sanitizer::internal_strlen(path) + 1); +  } +} +POST_SYSCALL(extattr_delete_file) +(long long res, void *path_, long long attrnamespace_, void *attrname_) { +  const char *path = (const char *)path_; +  if (path) { +    POST_READ(path, __sanitizer::internal_strlen(path) + 1); +  } +} +PRE_SYSCALL(extattr_set_fd) +(long long fd_, long long attrnamespace_, void *attrname_, void *data_, +  long long nbytes_) { +  /* TODO */ +} +POST_SYSCALL(extattr_set_fd) +(long long res, long long fd_, long long attrnamespace_, void *attrname_, +  void *data_, long long nbytes_) { +  /* TODO */ +} +PRE_SYSCALL(extattr_get_fd) +(long long fd_, long long attrnamespace_, void *attrname_, void *data_, +  long long nbytes_) { +  /* TODO */ +} +POST_SYSCALL(extattr_get_fd) +(long long res, long long fd_, long long attrnamespace_, void *attrname_, +  void *data_, long long nbytes_) { +  /* TODO */ +} +PRE_SYSCALL(extattr_delete_fd) +(long long fd_, long long attrnamespace_, void *attrname_) { +  /* TODO */ +} +POST_SYSCALL(extattr_delete_fd) +(long long res, long long fd_, long long attrnamespace_, void *attrname_) { +  /* TODO */ +} +PRE_SYSCALL(extattr_set_link) +(void *path_, long long attrnamespace_, void *attrname_, void *data_, +  long long nbytes_) { +  const char *path = (const char *)path_; +  if (path) { +    PRE_READ(path, __sanitizer::internal_strlen(path) + 1); +  } +} +POST_SYSCALL(extattr_set_link) +(long long res, void *path_, long long attrnamespace_, void *attrname_, +  void *data_, long long nbytes_) { +  const char *path = (const char *)path_; +  if (path) { +    POST_READ(path, __sanitizer::internal_strlen(path) + 1); +  } +} +PRE_SYSCALL(extattr_get_link) +(void *path_, long long attrnamespace_, void *attrname_, void *data_, +  long long nbytes_) { +  const char *path = (const char *)path_; +  if (path) { +    PRE_READ(path, __sanitizer::internal_strlen(path) + 1); +  } +} +POST_SYSCALL(extattr_get_link) +(long long res, void *path_, long long attrnamespace_, void *attrname_, +  void *data_, long long nbytes_) { +  const char *path = (const char *)path_; +  if (path) { +    POST_READ(path, __sanitizer::internal_strlen(path) + 1); +  } +} +PRE_SYSCALL(extattr_delete_link) +(void *path_, long long attrnamespace_, void *attrname_) { +  const char *path = (const char *)path_; +  if (path) { +    PRE_READ(path, __sanitizer::internal_strlen(path) + 1); +  } +} +POST_SYSCALL(extattr_delete_link) +(long long res, void *path_, long long attrnamespace_, void *attrname_) { +  const char *path = (const char *)path_; +  if (path) { +    POST_READ(path, __sanitizer::internal_strlen(path) + 1); +  } +} +PRE_SYSCALL(extattr_list_fd) +(long long fd_, long long attrnamespace_, void *data_, long long nbytes_) { +  /* TODO */ +} +POST_SYSCALL(extattr_list_fd) +(long long res, long long fd_, long long attrnamespace_, void *data_, +  long long nbytes_) { +  /* TODO */ +} +PRE_SYSCALL(extattr_list_file) +(void *path_, long long attrnamespace_, void *data_, long long nbytes_) { +  const char *path = (const char *)path_; +  if (path) { +    PRE_READ(path, __sanitizer::internal_strlen(path) + 1); +  } +} +POST_SYSCALL(extattr_list_file) +(long long res, void *path_, long long attrnamespace_, void *data_, +  long long nbytes_) { +  const char *path = (const char *)path_; +  if (path) { +    POST_READ(path, __sanitizer::internal_strlen(path) + 1); +  } +} +PRE_SYSCALL(extattr_list_link) +(void *path_, long long attrnamespace_, void *data_, long long nbytes_) { +  const char *path = (const char *)path_; +  if (path) { +    PRE_READ(path, __sanitizer::internal_strlen(path) + 1); +  } +} +POST_SYSCALL(extattr_list_link) +(long long res, void *path_, long long attrnamespace_, void *data_, +  long long nbytes_) { +  const char *path = (const char *)path_; +  if (path) { +    POST_READ(path, __sanitizer::internal_strlen(path) + 1); +  } +} +PRE_SYSCALL(compat_50_pselect) +(long long nd_, void *in_, void *ou_, void *ex_, void *ts_, void *mask_) { +  /* TODO */ +} +POST_SYSCALL(compat_50_pselect) +(long long res, long long nd_, void *in_, void *ou_, void *ex_, void *ts_, +  void *mask_) { +  /* TODO */ +} +PRE_SYSCALL(compat_50_pollts) +(void *fds_, long long nfds_, void *ts_, void *mask_) { +  /* TODO */ +} +POST_SYSCALL(compat_50_pollts) +(long long res, void *fds_, long long nfds_, void *ts_, void *mask_) { +  /* TODO */ +} +PRE_SYSCALL(setxattr) +(void *path_, void *name_, void *value_, long long size_, long long flags_) { +  const char *path = (const char *)path_; +  if (path) { +    PRE_READ(path, __sanitizer::internal_strlen(path) + 1); +  } +} +POST_SYSCALL(setxattr) +(long long res, void *path_, void *name_, void *value_, long long size_, +  long long flags_) { +  const char *path = (const char *)path_; +  if (path) { +    POST_READ(path, __sanitizer::internal_strlen(path) + 1); +  } +} +PRE_SYSCALL(lsetxattr) +(void *path_, void *name_, void *value_, long long size_, long long flags_) { +  const char *path = (const char *)path_; +  if (path) { +    PRE_READ(path, __sanitizer::internal_strlen(path) + 1); +  } +} +POST_SYSCALL(lsetxattr) +(long long res, void *path_, void *name_, void *value_, long long size_, +  long long flags_) { +  const char *path = (const char *)path_; +  if (path) { +    POST_READ(path, __sanitizer::internal_strlen(path) + 1); +  } +} +PRE_SYSCALL(fsetxattr) +(long long fd_, void *name_, void *value_, long long size_, long long flags_) { +  /* Nothing to do */ +} +POST_SYSCALL(fsetxattr) +(long long res, long long fd_, void *name_, void *value_, long long size_, +  long long flags_) { +  /* Nothing to do */ +} +PRE_SYSCALL(getxattr)(void *path_, void *name_, void *value_, long long size_) { +  const char *path = (const char *)path_; +  if (path) { +    PRE_READ(path, __sanitizer::internal_strlen(path) + 1); +  } +} +POST_SYSCALL(getxattr) +(long long res, void *path_, void *name_, void *value_, long long size_) { +  const char *path = (const char *)path_; +  if (path) { +    POST_READ(path, __sanitizer::internal_strlen(path) + 1); +  } +} +PRE_SYSCALL(lgetxattr) +(void *path_, void *name_, void *value_, long long size_) { +  const char *path = (const char *)path_; +  if (path) { +    PRE_READ(path, __sanitizer::internal_strlen(path) + 1); +  } +} +POST_SYSCALL(lgetxattr) +(long long res, void *path_, void *name_, void *value_, long long size_) { +  const char *path = (const char *)path_; +  if (path) { +    POST_READ(path, __sanitizer::internal_strlen(path) + 1); +  } +} +PRE_SYSCALL(fgetxattr) +(long long fd_, void *name_, void *value_, long long size_) { +  /* Nothing to do */ +} +POST_SYSCALL(fgetxattr) +(long long res, long long fd_, void *name_, void *value_, long long size_) { +  /* Nothing to do */ +} +PRE_SYSCALL(listxattr)(void *path_, void *list_, long long size_) { +  const char *path = (const char *)path_; +  if (path) { +    PRE_READ(path, __sanitizer::internal_strlen(path) + 1); +  } +} +POST_SYSCALL(listxattr) +(long long res, void *path_, void *list_, long long size_) { +  const char *path = (const char *)path_; +  if (path) { +    POST_READ(path, __sanitizer::internal_strlen(path) + 1); +  } +} +PRE_SYSCALL(llistxattr)(void *path_, void *list_, long long size_) { +  const char *path = (const char *)path_; +  if (path) { +    PRE_READ(path, __sanitizer::internal_strlen(path) + 1); +  } +} +POST_SYSCALL(llistxattr) +(long long res, void *path_, void *list_, long long size_) { +  const char *path = (const char *)path_; +  if (path) { +    POST_READ(path, __sanitizer::internal_strlen(path) + 1); +  } +} +PRE_SYSCALL(flistxattr)(long long fd_, void *list_, long long size_) { +  /* TODO */ +} +POST_SYSCALL(flistxattr) +(long long res, long long fd_, void *list_, long long size_) { +  /* TODO */ +} +PRE_SYSCALL(removexattr)(void *path_, void *name_) { +  const char *path = (const char *)path_; +  if (path) { +    PRE_READ(path, __sanitizer::internal_strlen(path) + 1); +  } +} +POST_SYSCALL(removexattr)(long long res, void *path_, void *name_) { +  const char *path = (const char *)path_; +  if (path) { +    POST_READ(path, __sanitizer::internal_strlen(path) + 1); +  } +} +PRE_SYSCALL(lremovexattr)(void *path_, void *name_) { +  const char *path = (const char *)path_; +  if (path) { +    PRE_READ(path, __sanitizer::internal_strlen(path) + 1); +  } +} +POST_SYSCALL(lremovexattr)(long long res, void *path_, void *name_) { +  const char *path = (const char *)path_; +  if (path) { +    POST_READ(path, __sanitizer::internal_strlen(path) + 1); +  } +} +PRE_SYSCALL(fremovexattr)(long long fd_, void *name_) { /* TODO */ } +POST_SYSCALL(fremovexattr)(long long res, long long fd_, void *name_) { +  /* TODO */ +} +PRE_SYSCALL(compat_50___stat30)(void *path_, void *ub_) { /* TODO */ } +POST_SYSCALL(compat_50___stat30)(long long res, void *path_, void *ub_) { +  /* TODO */ +} +PRE_SYSCALL(compat_50___fstat30)(long long fd_, void *sb_) { /* TODO */ } +POST_SYSCALL(compat_50___fstat30)(long long res, long long fd_, void *sb_) { +  /* TODO */ +} +PRE_SYSCALL(compat_50___lstat30)(void *path_, void *ub_) { /* TODO */ } +POST_SYSCALL(compat_50___lstat30)(long long res, void *path_, void *ub_) { +  /* TODO */ +} +PRE_SYSCALL(__getdents30)(long long fd_, void *buf_, long long count_) { +  /* Nothing to do */ +} +POST_SYSCALL(__getdents30) +(long long res, long long fd_, void *buf_, long long count_) { +  /* Nothing to do */ +} +PRE_SYSCALL(posix_fadvise)(long long) { /* Nothing to do */ } +POST_SYSCALL(posix_fadvise)(long long res, long long) { /* Nothing to do */ } +PRE_SYSCALL(compat_30___fhstat30)(void *fhp_, void *sb_) { /* TODO */ } +POST_SYSCALL(compat_30___fhstat30)(long long res, void *fhp_, void *sb_) { +  /* TODO */ +} +PRE_SYSCALL(compat_50___ntp_gettime30)(void *ntvp_) { /* TODO */ } +POST_SYSCALL(compat_50___ntp_gettime30)(long long res, void *ntvp_) { +  /* TODO */ +} +PRE_SYSCALL(__socket30) +(long long domain_, long long type_, long long protocol_) { +  /* Nothing to do */ +} +POST_SYSCALL(__socket30) +(long long res, long long domain_, long long type_, long long protocol_) { +  /* Nothing to do */ +} +PRE_SYSCALL(__getfh30)(void *fname_, void *fhp_, void *fh_size_) { +  const char *fname = (const char *)fname_; +  if (fname) { +    PRE_READ(fname, __sanitizer::internal_strlen(fname) + 1); +  } +} +POST_SYSCALL(__getfh30) +(long long res, void *fname_, void *fhp_, void *fh_size_) { +  const char *fname = (const char *)fname_; +  if (res == 0) { +    if (fname) { +      POST_READ(fname, __sanitizer::internal_strlen(fname) + 1); +    } +  } +} +PRE_SYSCALL(__fhopen40)(void *fhp_, long long fh_size_, long long flags_) { +  if (fhp_) { +    PRE_READ(fhp_, fh_size_); +  } +} +POST_SYSCALL(__fhopen40) +(long long res, void *fhp_, long long fh_size_, long long flags_) {} +PRE_SYSCALL(__fhstatvfs140) +(void *fhp_, long long fh_size_, void *buf_, long long flags_) { +  if (fhp_) { +    PRE_READ(fhp_, fh_size_); +  } +} +POST_SYSCALL(__fhstatvfs140) +(long long res, void *fhp_, long long fh_size_, void *buf_, long long flags_) {} +PRE_SYSCALL(compat_50___fhstat40)(void *fhp_, long long fh_size_, void *sb_) { +  if (fhp_) { +    PRE_READ(fhp_, fh_size_); +  } +} +POST_SYSCALL(compat_50___fhstat40) +(long long res, void *fhp_, long long fh_size_, void *sb_) {} +PRE_SYSCALL(aio_cancel)(long long fildes_, void *aiocbp_) { +  if (aiocbp_) { +    PRE_READ(aiocbp_, sizeof(struct __sanitizer_aiocb)); +  } +} +POST_SYSCALL(aio_cancel)(long long res, long long fildes_, void *aiocbp_) {} +PRE_SYSCALL(aio_error)(void *aiocbp_) { +  if (aiocbp_) { +    PRE_READ(aiocbp_, sizeof(struct __sanitizer_aiocb)); +  } +} +POST_SYSCALL(aio_error)(long long res, void *aiocbp_) {} +PRE_SYSCALL(aio_fsync)(long long op_, void *aiocbp_) { +  if (aiocbp_) { +    PRE_READ(aiocbp_, sizeof(struct __sanitizer_aiocb)); +  } +} +POST_SYSCALL(aio_fsync)(long long res, long long op_, void *aiocbp_) {} +PRE_SYSCALL(aio_read)(void *aiocbp_) { +  if (aiocbp_) { +    PRE_READ(aiocbp_, sizeof(struct __sanitizer_aiocb)); +  } +} +POST_SYSCALL(aio_read)(long long res, void *aiocbp_) {} +PRE_SYSCALL(aio_return)(void *aiocbp_) { +  if (aiocbp_) { +    PRE_READ(aiocbp_, sizeof(struct __sanitizer_aiocb)); +  } +} +POST_SYSCALL(aio_return)(long long res, void *aiocbp_) {} +PRE_SYSCALL(compat_50_aio_suspend) +(void *list_, long long nent_, void *timeout_) { +  /* TODO */ +} +POST_SYSCALL(compat_50_aio_suspend) +(long long res, void *list_, long long nent_, void *timeout_) { +  /* TODO */ +} +PRE_SYSCALL(aio_write)(void *aiocbp_) { +  if (aiocbp_) { +    PRE_READ(aiocbp_, sizeof(struct __sanitizer_aiocb)); +  } +} +POST_SYSCALL(aio_write)(long long res, void *aiocbp_) {} +PRE_SYSCALL(lio_listio) +(long long mode_, void *list_, long long nent_, void *sig_) { +  /* Nothing to do */ +} +POST_SYSCALL(lio_listio) +(long long res, long long mode_, void *list_, long long nent_, void *sig_) { +  /* Nothing to do */ +} +/* syscall 407 has been skipped */ +/* syscall 408 has been skipped */ +/* syscall 409 has been skipped */ +PRE_SYSCALL(__mount50) +(void *type_, void *path_, long long flags_, void *data_, long long data_len_) { +  const char *type = (const char *)type_; +  const char *path = (const char *)path_; +  if (type) { +    PRE_READ(type, __sanitizer::internal_strlen(type) + 1); +  } +  if (path) { +    PRE_READ(path, __sanitizer::internal_strlen(path) + 1); +  } +  if (data_) { +    PRE_READ(data_, data_len_); +  } +} +POST_SYSCALL(__mount50) +(long long res, void *type_, void *path_, long long flags_, void *data_, +  long long data_len_) { +  const char *type = (const char *)type_; +  const char *path = (const char *)path_; +  if (type) { +    POST_READ(type, __sanitizer::internal_strlen(type) + 1); +  } +  if (path) { +    POST_READ(path, __sanitizer::internal_strlen(path) + 1); +  } +  if (data_) { +    POST_READ(data_, data_len_); +  } +} +PRE_SYSCALL(mremap) +(void *old_address_, long long old_size_, void *new_address_, +  long long new_size_, long long flags_) { +  /* Nothing to do */ +} +POST_SYSCALL(mremap) +(long long res, void *old_address_, long long old_size_, void *new_address_, +  long long new_size_, long long flags_) { +  /* Nothing to do */ +} +PRE_SYSCALL(pset_create)(void *psid_) { /* Nothing to do */ } +POST_SYSCALL(pset_create)(long long res, void *psid_) { /* Nothing to do */ } +PRE_SYSCALL(pset_destroy)(long long psid_) { /* Nothing to do */ } +POST_SYSCALL(pset_destroy)(long long res, long long psid_) { +  /* Nothing to do */ +} +PRE_SYSCALL(pset_assign)(long long psid_, long long cpuid_, void *opsid_) { +  /* Nothing to do */ +} +POST_SYSCALL(pset_assign) +(long long res, long long psid_, long long cpuid_, void *opsid_) { +  /* Nothing to do */ +} +PRE_SYSCALL(_pset_bind) +(long long idtype_, long long first_id_, long long second_id_, long long psid_, +  void *opsid_) { +  /* Nothing to do */ +} +POST_SYSCALL(_pset_bind) +(long long res, long long idtype_, long long first_id_, long long second_id_, +  long long psid_, void *opsid_) { +  /* Nothing to do */ +} +PRE_SYSCALL(__posix_fadvise50) +(long long fd_, long long PAD_, long long offset_, long long len_, +  long long advice_) { +  /* Nothing to do */ +} +POST_SYSCALL(__posix_fadvise50) +(long long res, long long fd_, long long PAD_, long long offset_, +  long long len_, long long advice_) { +  /* Nothing to do */ +} +PRE_SYSCALL(__select50) +(long long nd_, void *in_, void *ou_, void *ex_, void *tv_) { +  /* Nothing to do */ +} +POST_SYSCALL(__select50) +(long long res, long long nd_, void *in_, void *ou_, void *ex_, void *tv_) { +  /* Nothing to do */ +} +PRE_SYSCALL(__gettimeofday50)(void *tp_, void *tzp_) { /* Nothing to do */ } +POST_SYSCALL(__gettimeofday50)(long long res, void *tp_, void *tzp_) { +  /* Nothing to do */ +} +PRE_SYSCALL(__settimeofday50)(void *tv_, void *tzp_) { +  if (tv_) { +    PRE_READ(tv_, timeval_sz); +  } +  if (tzp_) { +    PRE_READ(tzp_, struct_timezone_sz); +  } +} +POST_SYSCALL(__settimeofday50)(long long res, void *tv_, void *tzp_) {} +PRE_SYSCALL(__utimes50)(void *path_, void *tptr_) { +  struct __sanitizer_timespec **tptr = (struct __sanitizer_timespec **)tptr_; +  const char *path = (const char *)path_; +  if (path) { +    PRE_READ(path, __sanitizer::internal_strlen(path) + 1); +  } +  if (tptr) { +    PRE_READ(tptr[0], struct_timespec_sz); +    PRE_READ(tptr[1], struct_timespec_sz); +  } +} +POST_SYSCALL(__utimes50)(long long res, void *path_, void *tptr_) {} +PRE_SYSCALL(__adjtime50)(void *delta_, void *olddelta_) { +  if (delta_) { +    PRE_READ(delta_, timeval_sz); +  } +} +POST_SYSCALL(__adjtime50)(long long res, void *delta_, void *olddelta_) {} +PRE_SYSCALL(__lfs_segwait50)(void *fsidp_, void *tv_) { /* TODO */ } +POST_SYSCALL(__lfs_segwait50)(long long res, void *fsidp_, void *tv_) { +  /* TODO */ +} +PRE_SYSCALL(__futimes50)(long long fd_, void *tptr_) { +  struct __sanitizer_timespec **tptr = (struct __sanitizer_timespec **)tptr_; +  if (tptr) { +    PRE_READ(tptr[0], struct_timespec_sz); +    PRE_READ(tptr[1], struct_timespec_sz); +  } +} +POST_SYSCALL(__futimes50)(long long res, long long fd_, void *tptr_) {} +PRE_SYSCALL(__lutimes50)(void *path_, void *tptr_) { +  struct __sanitizer_timespec **tptr = (struct __sanitizer_timespec **)tptr_; +  const char *path = (const char *)path_; +  if (path) { +    PRE_READ(path, __sanitizer::internal_strlen(path) + 1); +  } +  if (tptr) { +    PRE_READ(tptr[0], struct_timespec_sz); +    PRE_READ(tptr[1], struct_timespec_sz); +  } +} +POST_SYSCALL(__lutimes50)(long long res, void *path_, void *tptr_) { +  struct __sanitizer_timespec **tptr = (struct __sanitizer_timespec **)tptr_; +  const char *path = (const char *)path_; +  if (path) { +    POST_READ(path, __sanitizer::internal_strlen(path) + 1); +  } +  if (tptr) { +    POST_READ(tptr[0], struct_timespec_sz); +    POST_READ(tptr[1], struct_timespec_sz); +  } +} +PRE_SYSCALL(__setitimer50)(long long which_, void *itv_, void *oitv_) { +  struct __sanitizer_itimerval *itv = (struct __sanitizer_itimerval *)itv_; +  if (itv) { +    PRE_READ(&itv->it_interval.tv_sec, sizeof(__sanitizer_time_t)); +    PRE_READ(&itv->it_interval.tv_usec, sizeof(__sanitizer_suseconds_t)); +    PRE_READ(&itv->it_value.tv_sec, sizeof(__sanitizer_time_t)); +    PRE_READ(&itv->it_value.tv_usec, sizeof(__sanitizer_suseconds_t)); +  } +} +POST_SYSCALL(__setitimer50) +(long long res, long long which_, void *itv_, void *oitv_) {} +PRE_SYSCALL(__getitimer50)(long long which_, void *itv_) { /* Nothing to do */ } +POST_SYSCALL(__getitimer50)(long long res, long long which_, void *itv_) { +  /* Nothing to do */ +} +PRE_SYSCALL(__clock_gettime50)(long long clock_id_, void *tp_) { +  /* Nothing to do */ +} +POST_SYSCALL(__clock_gettime50)(long long res, long long clock_id_, void *tp_) { +  /* Nothing to do */ +} +PRE_SYSCALL(__clock_settime50)(long long clock_id_, void *tp_) { +  if (tp_) { +    PRE_READ(tp_, struct_timespec_sz); +  } +} +POST_SYSCALL(__clock_settime50) +(long long res, long long clock_id_, void *tp_) {} +PRE_SYSCALL(__clock_getres50)(long long clock_id_, void *tp_) { +  /* Nothing to do */ +} +POST_SYSCALL(__clock_getres50)(long long res, long long clock_id_, void *tp_) { +  /* Nothing to do */ +} +PRE_SYSCALL(__nanosleep50)(void *rqtp_, void *rmtp_) { +  if (rqtp_) { +    PRE_READ(rqtp_, struct_timespec_sz); +  } +} +POST_SYSCALL(__nanosleep50)(long long res, void *rqtp_, void *rmtp_) {} +PRE_SYSCALL(____sigtimedwait50)(void *set_, void *info_, void *timeout_) { +  if (set_) { +    PRE_READ(set_, sizeof(__sanitizer_sigset_t)); +  } +  if (timeout_) { +    PRE_READ(timeout_, struct_timespec_sz); +  } +} +POST_SYSCALL(____sigtimedwait50) +(long long res, void *set_, void *info_, void *timeout_) {} +PRE_SYSCALL(__mq_timedsend50) +(long long mqdes_, void *msg_ptr_, long long msg_len_, long long msg_prio_, +  void *abs_timeout_) { +  if (msg_ptr_) { +    PRE_READ(msg_ptr_, msg_len_); +  } +  if (abs_timeout_) { +    PRE_READ(abs_timeout_, struct_timespec_sz); +  } +} +POST_SYSCALL(__mq_timedsend50) +(long long res, long long mqdes_, void *msg_ptr_, long long msg_len_, +  long long msg_prio_, void *abs_timeout_) {} +PRE_SYSCALL(__mq_timedreceive50) +(long long mqdes_, void *msg_ptr_, long long msg_len_, void *msg_prio_, +  void *abs_timeout_) { +  if (msg_ptr_) { +    PRE_READ(msg_ptr_, msg_len_); +  } +  if (abs_timeout_) { +    PRE_READ(abs_timeout_, struct_timespec_sz); +  } +} +POST_SYSCALL(__mq_timedreceive50) +(long long res, long long mqdes_, void *msg_ptr_, long long msg_len_, +  void *msg_prio_, void *abs_timeout_) {} +PRE_SYSCALL(compat_60__lwp_park) +(void *ts_, long long unpark_, void *hint_, void *unparkhint_) { +  /* TODO */ +} +POST_SYSCALL(compat_60__lwp_park) +(long long res, void *ts_, long long unpark_, void *hint_, void *unparkhint_) { +  /* TODO */ +} +PRE_SYSCALL(__kevent50) +(long long fd_, void *changelist_, long long nchanges_, void *eventlist_, +  long long nevents_, void *timeout_) { +  if (changelist_) { +    PRE_READ(changelist_, nchanges_ * struct_kevent_sz); +  } +  if (timeout_) { +    PRE_READ(timeout_, struct_timespec_sz); +  } +} +POST_SYSCALL(__kevent50) +(long long res, long long fd_, void *changelist_, long long nchanges_, +  void *eventlist_, long long nevents_, void *timeout_) {} +PRE_SYSCALL(__pselect50) +(long long nd_, void *in_, void *ou_, void *ex_, void *ts_, void *mask_) { +  if (ts_) { +    PRE_READ(ts_, struct_timespec_sz); +  } +  if (mask_) { +    PRE_READ(mask_, sizeof(struct __sanitizer_sigset_t)); +  } +} +POST_SYSCALL(__pselect50) +(long long res, long long nd_, void *in_, void *ou_, void *ex_, void *ts_, +  void *mask_) {} +PRE_SYSCALL(__pollts50)(void *fds_, long long nfds_, void *ts_, void *mask_) { +  if (ts_) { +    PRE_READ(ts_, struct_timespec_sz); +  } +  if (mask_) { +    PRE_READ(mask_, sizeof(struct __sanitizer_sigset_t)); +  } +} +POST_SYSCALL(__pollts50) +(long long res, void *fds_, long long nfds_, void *ts_, void *mask_) {} +PRE_SYSCALL(__aio_suspend50)(void *list_, long long nent_, void *timeout_) { +  int i; +  const struct aiocb *const *list = (const struct aiocb *const *)list_; +  if (list) { +    for (i = 0; i < nent_; i++) { +      if (list[i]) { +        PRE_READ(list[i], sizeof(struct __sanitizer_aiocb)); +      } +    } +  } +  if (timeout_) { +    PRE_READ(timeout_, struct_timespec_sz); +  } +} +POST_SYSCALL(__aio_suspend50) +(long long res, void *list_, long long nent_, void *timeout_) {} +PRE_SYSCALL(__stat50)(void *path_, void *ub_) { +  const char *path = (const char *)path_; +  if (path) { +    PRE_READ(path, __sanitizer::internal_strlen(path) + 1); +  } +} +POST_SYSCALL(__stat50)(long long res, void *path_, void *ub_) { +  const char *path = (const char *)path_; +  if (res == 0) { +    if (path) { +      POST_READ(path, __sanitizer::internal_strlen(path) + 1); +    } +  } +} +PRE_SYSCALL(__fstat50)(long long fd_, void *sb_) { /* Nothing to do */ } +POST_SYSCALL(__fstat50)(long long res, long long fd_, void *sb_) { +  /* Nothing to do */ +} +PRE_SYSCALL(__lstat50)(void *path_, void *ub_) { +  const char *path = (const char *)path_; +  if (path) { +    PRE_READ(path, __sanitizer::internal_strlen(path) + 1); +  } +} +POST_SYSCALL(__lstat50)(long long res, void *path_, void *ub_) { +  const char *path = (const char *)path_; +  if (res == 0) { +    if (path) { +      POST_READ(path, __sanitizer::internal_strlen(path) + 1); +    } +  } +} +PRE_SYSCALL(____semctl50) +(long long semid_, long long semnum_, long long cmd_, void *arg_) { +  /* Nothing to do */ +} +POST_SYSCALL(____semctl50) +(long long res, long long semid_, long long semnum_, long long cmd_, +  void *arg_) { +  /* Nothing to do */ +} +PRE_SYSCALL(__shmctl50)(long long shmid_, long long cmd_, void *buf_) { +  /* Nothing to do */ +} +POST_SYSCALL(__shmctl50) +(long long res, long long shmid_, long long cmd_, void *buf_) { +  /* Nothing to do */ +} +PRE_SYSCALL(__msgctl50)(long long msqid_, long long cmd_, void *buf_) { +  /* Nothing to do */ +} +POST_SYSCALL(__msgctl50) +(long long res, long long msqid_, long long cmd_, void *buf_) { +  /* Nothing to do */ +} +PRE_SYSCALL(__getrusage50)(long long who_, void *rusage_) { +  /* Nothing to do */ +} +POST_SYSCALL(__getrusage50)(long long res, long long who_, void *rusage_) { +  /* Nothing to do */ +} +PRE_SYSCALL(__timer_settime50) +(long long timerid_, long long flags_, void *value_, void *ovalue_) { +  struct __sanitizer_itimerval *value = (struct __sanitizer_itimerval *)value_; +  if (value) { +    PRE_READ(&value->it_interval.tv_sec, sizeof(__sanitizer_time_t)); +    PRE_READ(&value->it_interval.tv_usec, sizeof(__sanitizer_suseconds_t)); +    PRE_READ(&value->it_value.tv_sec, sizeof(__sanitizer_time_t)); +    PRE_READ(&value->it_value.tv_usec, sizeof(__sanitizer_suseconds_t)); +  } +} +POST_SYSCALL(__timer_settime50) +(long long res, long long timerid_, long long flags_, void *value_, +  void *ovalue_) { +  struct __sanitizer_itimerval *value = (struct __sanitizer_itimerval *)value_; +  if (res == 0) { +    if (value) { +      POST_READ(&value->it_interval.tv_sec, sizeof(__sanitizer_time_t)); +      POST_READ(&value->it_interval.tv_usec, sizeof(__sanitizer_suseconds_t)); +      POST_READ(&value->it_value.tv_sec, sizeof(__sanitizer_time_t)); +      POST_READ(&value->it_value.tv_usec, sizeof(__sanitizer_suseconds_t)); +    } +  } +} +PRE_SYSCALL(__timer_gettime50)(long long timerid_, void *value_) { +  /* Nothing to do */ +} +POST_SYSCALL(__timer_gettime50) +(long long res, long long timerid_, void *value_) { +  /* Nothing to do */ +} +#if defined(NTP) || !defined(_KERNEL_OPT) +PRE_SYSCALL(__ntp_gettime50)(void *ntvp_) { /* Nothing to do */ } +POST_SYSCALL(__ntp_gettime50)(long long res, void *ntvp_) { +  /* Nothing to do */ +} +#else +/* syscall 448 has been skipped */ +#endif +PRE_SYSCALL(__wait450) +(long long pid_, void *status_, long long options_, void *rusage_) { +  /* Nothing to do */ +} +POST_SYSCALL(__wait450) +(long long res, long long pid_, void *status_, long long options_, +  void *rusage_) { +  /* Nothing to do */ +} +PRE_SYSCALL(__mknod50)(void *path_, long long mode_, long long dev_) { +  const char *path = (const char *)path_; +  if (path) { +    PRE_READ(path, __sanitizer::internal_strlen(path) + 1); +  } +} +POST_SYSCALL(__mknod50) +(long long res, void *path_, long long mode_, long long dev_) { +  const char *path = (const char *)path_; +  if (res == 0) { +    if (path) { +      POST_READ(path, __sanitizer::internal_strlen(path) + 1); +    } +  } +} +PRE_SYSCALL(__fhstat50)(void *fhp_, long long fh_size_, void *sb_) { +  if (fhp_) { +    PRE_READ(fhp_, fh_size_); +  } +} +POST_SYSCALL(__fhstat50) +(long long res, void *fhp_, long long fh_size_, void *sb_) { +  if (res == 0) { +    if (fhp_) { +      POST_READ(fhp_, fh_size_); +    } +  } +} +/* syscall 452 has been skipped */ +PRE_SYSCALL(pipe2)(void *fildes_, long long flags_) { /* Nothing to do */ } +POST_SYSCALL(pipe2)(long long res, void *fildes_, long long flags_) { +  /* Nothing to do */ +} +PRE_SYSCALL(dup3)(long long from_, long long to_, long long flags_) { +  /* Nothing to do */ +} +POST_SYSCALL(dup3) +(long long res, long long from_, long long to_, long long flags_) { +  /* Nothing to do */ +} +PRE_SYSCALL(kqueue1)(long long flags_) { /* Nothing to do */ } +POST_SYSCALL(kqueue1)(long long res, long long flags_) { /* Nothing to do */ } +PRE_SYSCALL(paccept) +(long long s_, void *name_, void *anamelen_, void *mask_, long long flags_) { +  if (mask_) { +    PRE_READ(mask_, sizeof(__sanitizer_sigset_t)); +  } +} +POST_SYSCALL(paccept) +(long long res, long long s_, void *name_, void *anamelen_, void *mask_, +  long long flags_) { +  if (res >= 0) { +    if (mask_) { +      PRE_READ(mask_, sizeof(__sanitizer_sigset_t)); +    } +  } +} +PRE_SYSCALL(linkat) +(long long fd1_, void *name1_, long long fd2_, void *name2_, long long flags_) { +  const char *name1 = (const char *)name1_; +  const char *name2 = (const char *)name2_; +  if (name1) { +    PRE_READ(name1, __sanitizer::internal_strlen(name1) + 1); +  } +  if (name2) { +    PRE_READ(name2, __sanitizer::internal_strlen(name2) + 1); +  } +} +POST_SYSCALL(linkat) +(long long res, long long fd1_, void *name1_, long long fd2_, void *name2_, +  long long flags_) { +  const char *name1 = (const char *)name1_; +  const char *name2 = (const char *)name2_; +  if (res == 0) { +    if (name1) { +      POST_READ(name1, __sanitizer::internal_strlen(name1) + 1); +    } +    if (name2) { +      POST_READ(name2, __sanitizer::internal_strlen(name2) + 1); +    } +  } +} +PRE_SYSCALL(renameat) +(long long fromfd_, void *from_, long long tofd_, void *to_) { +  const char *from = (const char *)from_; +  const char *to = (const char *)to_; +  if (from) { +    PRE_READ(from, __sanitizer::internal_strlen(from) + 1); +  } +  if (to) { +    PRE_READ(to, __sanitizer::internal_strlen(to) + 1); +  } +} +POST_SYSCALL(renameat) +(long long res, long long fromfd_, void *from_, long long tofd_, void *to_) { +  const char *from = (const char *)from_; +  const char *to = (const char *)to_; +  if (res == 0) { +    if (from) { +      POST_READ(from, __sanitizer::internal_strlen(from) + 1); +    } +    if (to) { +      POST_READ(to, __sanitizer::internal_strlen(to) + 1); +    } +  } +} +PRE_SYSCALL(mkfifoat)(long long fd_, void *path_, long long mode_) { +  const char *path = (const char *)path_; +  if (path) { +    PRE_READ(path, __sanitizer::internal_strlen(path) + 1); +  } +} +POST_SYSCALL(mkfifoat) +(long long res, long long fd_, void *path_, long long mode_) { +  const char *path = (const char *)path_; +  if (res == 0) { +    if (path) { +      POST_READ(path, __sanitizer::internal_strlen(path) + 1); +    } +  } +} +PRE_SYSCALL(mknodat) +(long long fd_, void *path_, long long mode_, long long PAD_, long long dev_) { +  const char *path = (const char *)path_; +  if (path) { +    PRE_READ(path, __sanitizer::internal_strlen(path) + 1); +  } +} +POST_SYSCALL(mknodat) +(long long res, long long fd_, void *path_, long long mode_, long long PAD_, +  long long dev_) { +  const char *path = (const char *)path_; +  if (res == 0) { +    if (path) { +      POST_READ(path, __sanitizer::internal_strlen(path) + 1); +    } +  } +} +PRE_SYSCALL(mkdirat)(long long fd_, void *path_, long long mode_) { +  const char *path = (const char *)path_; +  if (path) { +    PRE_READ(path, __sanitizer::internal_strlen(path) + 1); +  } +} +POST_SYSCALL(mkdirat) +(long long res, long long fd_, void *path_, long long mode_) { +  const char *path = (const char *)path_; +  if (res == 0) { +    if (path) { +      POST_READ(path, __sanitizer::internal_strlen(path) + 1); +    } +  } +} +PRE_SYSCALL(faccessat) +(long long fd_, void *path_, long long amode_, long long flag_) { +  const char *path = (const char *)path_; +  if (path) { +    PRE_READ(path, __sanitizer::internal_strlen(path) + 1); +  } +} +POST_SYSCALL(faccessat) +(long long res, long long fd_, void *path_, long long amode_, long long flag_) { +  const char *path = (const char *)path_; +  if (res == 0) { +    if (path) { +      POST_READ(path, __sanitizer::internal_strlen(path) + 1); +    } +  } +} +PRE_SYSCALL(fchmodat) +(long long fd_, void *path_, long long mode_, long long flag_) { +  const char *path = (const char *)path_; +  if (path) { +    PRE_READ(path, __sanitizer::internal_strlen(path) + 1); +  } +} +POST_SYSCALL(fchmodat) +(long long res, long long fd_, void *path_, long long mode_, long long flag_) { +  const char *path = (const char *)path_; +  if (res == 0) { +    if (path) { +      POST_READ(path, __sanitizer::internal_strlen(path) + 1); +    } +  } +} +PRE_SYSCALL(fchownat) +(long long fd_, void *path_, long long owner_, long long group_, +  long long flag_) { +  const char *path = (const char *)path_; +  if (path) { +    PRE_READ(path, __sanitizer::internal_strlen(path) + 1); +  } +} +POST_SYSCALL(fchownat) +(long long res, long long fd_, void *path_, long long owner_, long long group_, +  long long flag_) { +  const char *path = (const char *)path_; +  if (res == 0) { +    if (path) { +      POST_READ(path, __sanitizer::internal_strlen(path) + 1); +    } +  } +} +PRE_SYSCALL(fexecve)(long long fd_, void *argp_, void *envp_) { /* TODO */ } +POST_SYSCALL(fexecve)(long long res, long long fd_, void *argp_, void *envp_) { +  /* TODO */ +} +PRE_SYSCALL(fstatat)(long long fd_, void *path_, void *buf_, long long flag_) { +  const char *path = (const char *)path_; +  if (path) { +    PRE_READ(path, __sanitizer::internal_strlen(path) + 1); +  } +} +POST_SYSCALL(fstatat) +(long long res, long long fd_, void *path_, void *buf_, long long flag_) { +  const char *path = (const char *)path_; +  if (path) { +    POST_READ(path, __sanitizer::internal_strlen(path) + 1); +  } +} +PRE_SYSCALL(utimensat) +(long long fd_, void *path_, void *tptr_, long long flag_) { +  const char *path = (const char *)path_; +  if (path) { +    PRE_READ(path, __sanitizer::internal_strlen(path) + 1); +  } +  if (tptr_) { +    PRE_READ(tptr_, struct_timespec_sz); +  } +} +POST_SYSCALL(utimensat) +(long long res, long long fd_, void *path_, void *tptr_, long long flag_) { +  const char *path = (const char *)path_; +  if (res > 0) { +    if (path) { +      POST_READ(path, __sanitizer::internal_strlen(path) + 1); +    } +    if (tptr_) { +      POST_READ(tptr_, struct_timespec_sz); +    } +  } +} +PRE_SYSCALL(openat) +(long long fd_, void *path_, long long oflags_, long long mode_) { +  const char *path = (const char *)path_; +  if (path) { +    PRE_READ(path, __sanitizer::internal_strlen(path) + 1); +  } +} +POST_SYSCALL(openat) +(long long res, long long fd_, void *path_, long long oflags_, +  long long mode_) { +  const char *path = (const char *)path_; +  if (res > 0) { +    if (path) { +      POST_READ(path, __sanitizer::internal_strlen(path) + 1); +    } +  } +} +PRE_SYSCALL(readlinkat) +(long long fd_, void *path_, void *buf_, long long bufsize_) { +  const char *path = (const char *)path_; +  if (path) { +    PRE_READ(path, __sanitizer::internal_strlen(path) + 1); +  } +} +POST_SYSCALL(readlinkat) +(long long res, long long fd_, void *path_, void *buf_, long long bufsize_) { +  const char *path = (const char *)path_; +  if (res > 0) { +    if (path) { +      POST_READ(path, __sanitizer::internal_strlen(path) + 1); +    } +  } +} +PRE_SYSCALL(symlinkat)(void *path1_, long long fd_, void *path2_) { +  const char *path1 = (const char *)path1_; +  const char *path2 = (const char *)path2_; +  if (path1) { +    PRE_READ(path1, __sanitizer::internal_strlen(path1) + 1); +  } +  if (path2) { +    PRE_READ(path2, __sanitizer::internal_strlen(path2) + 1); +  } +} +POST_SYSCALL(symlinkat) +(long long res, void *path1_, long long fd_, void *path2_) { +  const char *path1 = (const char *)path1_; +  const char *path2 = (const char *)path2_; +  if (res == 0) { +    if (path1) { +      POST_READ(path1, __sanitizer::internal_strlen(path1) + 1); +    } +    if (path2) { +      POST_READ(path2, __sanitizer::internal_strlen(path2) + 1); +    } +  } +} +PRE_SYSCALL(unlinkat)(long long fd_, void *path_, long long flag_) { +  const char *path = (const char *)path_; +  if (path) { +    PRE_READ(path, __sanitizer::internal_strlen(path) + 1); +  } +} +POST_SYSCALL(unlinkat) +(long long res, long long fd_, void *path_, long long flag_) { +  const char *path = (const char *)path_; +  if (res == 0) { +    if (path) { +      POST_READ(path, __sanitizer::internal_strlen(path) + 1); +    } +  } +} +PRE_SYSCALL(futimens)(long long fd_, void *tptr_) { +  struct __sanitizer_timespec **tptr = (struct __sanitizer_timespec **)tptr_; +  if (tptr) { +    PRE_READ(tptr[0], struct_timespec_sz); +    PRE_READ(tptr[1], struct_timespec_sz); +  } +} +POST_SYSCALL(futimens)(long long res, long long fd_, void *tptr_) { +  struct __sanitizer_timespec **tptr = (struct __sanitizer_timespec **)tptr_; +  if (res == 0) { +    if (tptr) { +      POST_READ(tptr[0], struct_timespec_sz); +      POST_READ(tptr[1], struct_timespec_sz); +    } +  } +} +PRE_SYSCALL(__quotactl)(void *path_, void *args_) { +  const char *path = (const char *)path_; +  if (path) { +    PRE_READ(path, __sanitizer::internal_strlen(path) + 1); +  } +} +POST_SYSCALL(__quotactl)(long long res, void *path_, void *args_) { +  const char *path = (const char *)path_; +  if (res == 0) { +    if (path) { +      POST_READ(path, __sanitizer::internal_strlen(path) + 1); +    } +  } +} +PRE_SYSCALL(posix_spawn) +(void *pid_, void *path_, void *file_actions_, void *attrp_, void *argv_, +  void *envp_) { +  const char *path = (const char *)path_; +  if (path) { +    PRE_READ(path, __sanitizer::internal_strlen(path) + 1); +  } +} +POST_SYSCALL(posix_spawn) +(long long res, void *pid_, void *path_, void *file_actions_, void *attrp_, +  void *argv_, void *envp_) { +  const char *path = (const char *)path_; +  if (pid_) { +    if (path) { +      POST_READ(path, __sanitizer::internal_strlen(path) + 1); +    } +  } +} +PRE_SYSCALL(recvmmsg) +(long long s_, void *mmsg_, long long vlen_, long long flags_, void *timeout_) { +  if (timeout_) { +    PRE_READ(timeout_, struct_timespec_sz); +  } +} +POST_SYSCALL(recvmmsg) +(long long res, long long s_, void *mmsg_, long long vlen_, long long flags_, +  void *timeout_) { +  if (res >= 0) { +    if (timeout_) { +      POST_READ(timeout_, struct_timespec_sz); +    } +  } +} +PRE_SYSCALL(sendmmsg) +(long long s_, void *mmsg_, long long vlen_, long long flags_) { +  struct __sanitizer_mmsghdr *mmsg = (struct __sanitizer_mmsghdr *)mmsg_; +  unsigned int vlen = (vlen_ > 1024 ? 1024 : vlen_); +  if (mmsg) { +    PRE_READ(mmsg, sizeof(struct __sanitizer_mmsghdr) * vlen); +  } +} +POST_SYSCALL(sendmmsg) +(long long res, long long s_, void *mmsg_, long long vlen_, long long flags_) { +  struct __sanitizer_mmsghdr *mmsg = (struct __sanitizer_mmsghdr *)mmsg_; +  unsigned int vlen = (vlen_ > 1024 ? 1024 : vlen_); +  if (res >= 0) { +    if (mmsg) { +      POST_READ(mmsg, sizeof(struct __sanitizer_mmsghdr) * vlen); +    } +  } +} +PRE_SYSCALL(clock_nanosleep) +(long long clock_id_, long long flags_, void *rqtp_, void *rmtp_) { +  if (rqtp_) { +    PRE_READ(rqtp_, struct_timespec_sz); +  } +} +POST_SYSCALL(clock_nanosleep) +(long long res, long long clock_id_, long long flags_, void *rqtp_, +  void *rmtp_) { +  if (rqtp_) { +    POST_READ(rqtp_, struct_timespec_sz); +  } +} +PRE_SYSCALL(___lwp_park60) +(long long clock_id_, long long flags_, void *ts_, long long unpark_, +  void *hint_, void *unparkhint_) { +  if (ts_) { +    PRE_READ(ts_, struct_timespec_sz); +  } +} +POST_SYSCALL(___lwp_park60) +(long long res, long long clock_id_, long long flags_, void *ts_, +  long long unpark_, void *hint_, void *unparkhint_) { +  if (res == 0) { +    if (ts_) { +      POST_READ(ts_, struct_timespec_sz); +    } +  } +} +PRE_SYSCALL(posix_fallocate) +(long long fd_, long long PAD_, long long pos_, long long len_) { +  /* Nothing to do */ +} +POST_SYSCALL(posix_fallocate) +(long long res, long long fd_, long long PAD_, long long pos_, long long len_) { +  /* Nothing to do */ +} +PRE_SYSCALL(fdiscard) +(long long fd_, long long PAD_, long long pos_, long long len_) { +  /* Nothing to do */ +} +POST_SYSCALL(fdiscard) +(long long res, long long fd_, long long PAD_, long long pos_, long long len_) { +  /* Nothing to do */ +} +PRE_SYSCALL(wait6) +(long long idtype_, long long id_, void *status_, long long options_, +  void *wru_, void *info_) { +  /* Nothing to do */ +} +POST_SYSCALL(wait6) +(long long res, long long idtype_, long long id_, void *status_, +  long long options_, void *wru_, void *info_) { +  /* Nothing to do */ +} +PRE_SYSCALL(clock_getcpuclockid2) +(long long idtype_, long long id_, void *clock_id_) { +  /* Nothing to do */ +} +POST_SYSCALL(clock_getcpuclockid2) +(long long res, long long idtype_, long long id_, void *clock_id_) { +  /* Nothing to do */ +} +#undef SYS_MAXSYSARGS +} // extern "C" + +#undef PRE_SYSCALL +#undef PRE_READ +#undef PRE_WRITE +#undef POST_SYSCALL +#undef POST_READ +#undef POST_WRITE + +#endif // SANITIZER_NETBSD diff --git a/lib/sanitizer_common/sanitizer_tls_get_addr.cc b/lib/sanitizer_common/sanitizer_tls_get_addr.cc index 6fa0e9298b315..85dc806df284e 100644 --- a/lib/sanitizer_common/sanitizer_tls_get_addr.cc +++ b/lib/sanitizer_common/sanitizer_tls_get_addr.cc @@ -142,7 +142,8 @@ bool DTLSInDestruction(DTLS *dtls) {  #else  void DTLS_on_libc_memalign(void *ptr, uptr size) {} -DTLS::DTV *DTLS_on_tls_get_addr(void *arg, void *res) { return 0; } +DTLS::DTV *DTLS_on_tls_get_addr(void *arg, void *res, +  unsigned long, unsigned long) { return 0; }  DTLS *DTLS_Get() { return 0; }  void DTLS_Destroy() {}  bool DTLSInDestruction(DTLS *dtls) { diff --git a/lib/sanitizer_common/sanitizer_unwind_linux_libcdep.cc b/lib/sanitizer_common/sanitizer_unwind_linux_libcdep.cc index 24c94700173d1..9e12c417c71d5 100644 --- a/lib/sanitizer_common/sanitizer_unwind_linux_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_unwind_linux_libcdep.cc @@ -149,7 +149,7 @@ void BufferedStackTrace::SlowUnwindStackWithContext(uptr pc, void *context,    void *map = acquire_my_map_info_list();    CHECK(map); -  InternalScopedBuffer<backtrace_frame_t> frames(kStackTraceMax); +  InternalMmapVector<backtrace_frame_t> frames(kStackTraceMax);    // siginfo argument appears to be unused.    sptr res = unwind_backtrace_signal_arch(/* siginfo */ 0, context, map,                                            frames.data(), diff --git a/lib/sanitizer_common/sanitizer_unwind_win.cc b/lib/sanitizer_common/sanitizer_unwind_win.cc new file mode 100644 index 0000000000000..62bac4e9b4a5b --- /dev/null +++ b/lib/sanitizer_common/sanitizer_unwind_win.cc @@ -0,0 +1,75 @@ +//===-- sanitizer_unwind_win.cc -------------------------------------------===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +/// Sanitizer unwind Windows specific functions. +// +//===----------------------------------------------------------------------===// + +#include "sanitizer_platform.h" +#if SANITIZER_WINDOWS + +#define WIN32_LEAN_AND_MEAN +#define NOGDI +#include <windows.h> + +#include "sanitizer_dbghelp.h"  // for StackWalk64 +#include "sanitizer_stacktrace.h" +#include "sanitizer_symbolizer.h"  // for InitializeDbgHelpIfNeeded + +using namespace __sanitizer; + +#if !SANITIZER_GO +void BufferedStackTrace::SlowUnwindStack(uptr pc, u32 max_depth) { +  CHECK_GE(max_depth, 2); +  // FIXME: CaptureStackBackTrace might be too slow for us. +  // FIXME: Compare with StackWalk64. +  // FIXME: Look at LLVMUnhandledExceptionFilter in Signals.inc +  size = CaptureStackBackTrace(1, Min(max_depth, kStackTraceMax), +    (void **)&trace_buffer[0], 0); +  if (size == 0) +    return; + +  // Skip the RTL frames by searching for the PC in the stacktrace. +  uptr pc_location = LocatePcInTrace(pc); +  PopStackFrames(pc_location); +} + +void BufferedStackTrace::SlowUnwindStackWithContext(uptr pc, void *context, +  u32 max_depth) { +  CONTEXT ctx = *(CONTEXT *)context; +  STACKFRAME64 stack_frame; +  memset(&stack_frame, 0, sizeof(stack_frame)); + +  InitializeDbgHelpIfNeeded(); + +  size = 0; +#if defined(_WIN64) +  int machine_type = IMAGE_FILE_MACHINE_AMD64; +  stack_frame.AddrPC.Offset = ctx.Rip; +  stack_frame.AddrFrame.Offset = ctx.Rbp; +  stack_frame.AddrStack.Offset = ctx.Rsp; +#else +  int machine_type = IMAGE_FILE_MACHINE_I386; +  stack_frame.AddrPC.Offset = ctx.Eip; +  stack_frame.AddrFrame.Offset = ctx.Ebp; +  stack_frame.AddrStack.Offset = ctx.Esp; +#endif +  stack_frame.AddrPC.Mode = AddrModeFlat; +  stack_frame.AddrFrame.Mode = AddrModeFlat; +  stack_frame.AddrStack.Mode = AddrModeFlat; +  while (StackWalk64(machine_type, GetCurrentProcess(), GetCurrentThread(), +    &stack_frame, &ctx, NULL, SymFunctionTableAccess64, +    SymGetModuleBase64, NULL) && +    size < Min(max_depth, kStackTraceMax)) { +    trace_buffer[size++] = (uptr)stack_frame.AddrPC.Offset; +  } +} +#endif  // #if !SANITIZER_GO + +#endif  // SANITIZER_WINDOWS diff --git a/lib/sanitizer_common/sanitizer_vector.h b/lib/sanitizer_common/sanitizer_vector.h index 25cfeed35f223..0632ccce262e5 100644 --- a/lib/sanitizer_common/sanitizer_vector.h +++ b/lib/sanitizer_common/sanitizer_vector.h @@ -82,6 +82,10 @@ class Vector {        return;      }      uptr old_size = Size(); +    if (size <= old_size) { +      end_ = begin_ + size; +      return; +    }      EnsureSize(size);      if (old_size < size) {        for (uptr i = old_size; i < size; i++) diff --git a/lib/sanitizer_common/sanitizer_win.cc b/lib/sanitizer_common/sanitizer_win.cc index 34bf1812d6054..b8060b2e640cb 100644 --- a/lib/sanitizer_common/sanitizer_win.cc +++ b/lib/sanitizer_common/sanitizer_win.cc @@ -23,13 +23,10 @@  #include <stdlib.h>  #include "sanitizer_common.h" -#include "sanitizer_dbghelp.h"  #include "sanitizer_file.h"  #include "sanitizer_libc.h"  #include "sanitizer_mutex.h"  #include "sanitizer_placement_new.h" -#include "sanitizer_stacktrace.h" -#include "sanitizer_symbolizer.h"  #include "sanitizer_win_defs.h"  // A macro to tell the compiler that this part of the code cannot be reached, @@ -205,7 +202,7 @@ void *MmapAlignedOrDieOnFatalError(uptr size, uptr alignment,    return (void *)mapped_addr;  } -void *MmapFixedNoReserve(uptr fixed_addr, uptr size, const char *name) { +bool MmapFixedNoReserve(uptr fixed_addr, uptr size, const char *name) {    // FIXME: is this really "NoReserve"? On Win32 this does not matter much,    // but on Win64 it does.    (void)name;  // unsupported @@ -218,11 +215,13 @@ void *MmapFixedNoReserve(uptr fixed_addr, uptr size, const char *name) {    void *p = VirtualAlloc((LPVOID)fixed_addr, size, MEM_RESERVE | MEM_COMMIT,                           PAGE_READWRITE);  #endif -  if (p == 0) +  if (p == 0) {      Report("ERROR: %s failed to "             "allocate %p (%zd) bytes at %p (error code: %d)\n",             SanitizerToolName, size, size, fixed_addr, GetLastError()); -  return p; +    return false; +  } +  return true;  }  // Memory space mapped by 'MmapFixedOrDie' must have been reserved by @@ -250,15 +249,12 @@ uptr ReservedAddressRange::MapOrDie(uptr fixed_addr, uptr size) {  }  void ReservedAddressRange::Unmap(uptr addr, uptr size) { -  void* addr_as_void = reinterpret_cast<void*>(addr); -  uptr base_as_uptr = reinterpret_cast<uptr>(base_);    // Only unmap if it covers the entire range. -  CHECK((addr == base_as_uptr) && (size == size_)); -  UnmapOrDie(addr_as_void, size); -  if (addr_as_void == base_) { -    base_ = reinterpret_cast<void*>(addr + size); -  } -  size_ = size_ - size; +  CHECK((addr == reinterpret_cast<uptr>(base_)) && (size == size_)); +  // We unmap the whole range, just null out the base. +  base_ = nullptr; +  size_ = 0; +  UnmapOrDie(reinterpret_cast<void*>(addr), size);  }  void *MmapFixedOrDieOnFatalError(uptr fixed_addr, uptr size) { @@ -279,11 +275,7 @@ void *MmapNoReserveOrDie(uptr size, const char *mem_type) {  }  uptr ReservedAddressRange::Init(uptr size, const char *name, uptr fixed_addr) { -  if (fixed_addr) { -    base_ = MmapFixedNoAccess(fixed_addr, size, name); -  } else { -    base_ = MmapNoAccess(size); -  } +  base_ = fixed_addr ? MmapFixedNoAccess(fixed_addr, size) : MmapNoAccess(size);    size_ = size;    name_ = name;    (void)os_handle_;  // unsupported @@ -321,17 +313,20 @@ void ReleaseMemoryPagesToOS(uptr beg, uptr end) {    // FIXME: add madvise-analog when we move to 64-bits.  } -void NoHugePagesInRegion(uptr addr, uptr size) { +bool NoHugePagesInRegion(uptr addr, uptr size) {    // FIXME: probably similar to ReleaseMemoryToOS. +  return true;  } -void DontDumpShadowMemory(uptr addr, uptr length) { +bool DontDumpShadowMemory(uptr addr, uptr length) {    // This is almost useless on 32-bits.    // FIXME: add madvise-analog when we move to 64-bits. +  return true;  }  uptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding, -                              uptr *largest_gap_found) { +                              uptr *largest_gap_found, +                              uptr *max_occupied_addr) {    uptr address = 0;    while (true) {      MEMORY_BASIC_INFORMATION info; @@ -433,7 +428,7 @@ void DumpProcessMap() {    modules.init();    uptr num_modules = modules.size(); -  InternalScopedBuffer<ModuleInfo> module_infos(num_modules); +  InternalMmapVector<ModuleInfo> module_infos(num_modules);    for (size_t i = 0; i < num_modules; ++i) {      module_infos[i].filepath = modules[i].full_name();      module_infos[i].base_address = modules[i].ranges().front()->beg; @@ -466,8 +461,7 @@ void ReExec() {    UNIMPLEMENTED();  } -void PrepareForSandboxing(__sanitizer_sandbox_arguments *args) { -} +void PlatformPrepareForSandboxing(__sanitizer_sandbox_arguments *args) {}  bool StackSizeIsUnlimited() {    UNIMPLEMENTED(); @@ -502,12 +496,19 @@ void SleepForMillis(int millis) {  }  u64 NanoTime() { -  return 0; +  static LARGE_INTEGER frequency = {}; +  LARGE_INTEGER counter; +  if (UNLIKELY(frequency.QuadPart == 0)) { +    QueryPerformanceFrequency(&frequency); +    CHECK_NE(frequency.QuadPart, 0); +  } +  QueryPerformanceCounter(&counter); +  counter.QuadPart *= 1000ULL * 1000000ULL; +  counter.QuadPart /= frequency.QuadPart; +  return counter.QuadPart;  } -u64 MonotonicNanoTime() { -  return 0; -} +u64 MonotonicNanoTime() { return NanoTime(); }  void Abort() {    internal__exit(3); @@ -756,7 +757,10 @@ uptr internal_ftruncate(fd_t fd, uptr size) {  }  uptr GetRSS() { -  return 0; +  PROCESS_MEMORY_COUNTERS counters; +  if (!GetProcessMemoryInfo(GetCurrentProcess(), &counters, sizeof(counters))) +    return 0; +  return counters.WorkingSetSize;  }  void *internal_start_thread(void (*func)(void *arg), void *arg) { return 0; } @@ -830,54 +834,6 @@ void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,  #endif  } -#if !SANITIZER_GO -void BufferedStackTrace::SlowUnwindStack(uptr pc, u32 max_depth) { -  CHECK_GE(max_depth, 2); -  // FIXME: CaptureStackBackTrace might be too slow for us. -  // FIXME: Compare with StackWalk64. -  // FIXME: Look at LLVMUnhandledExceptionFilter in Signals.inc -  size = CaptureStackBackTrace(1, Min(max_depth, kStackTraceMax), -                               (void **)&trace_buffer[0], 0); -  if (size == 0) -    return; - -  // Skip the RTL frames by searching for the PC in the stacktrace. -  uptr pc_location = LocatePcInTrace(pc); -  PopStackFrames(pc_location); -} - -void BufferedStackTrace::SlowUnwindStackWithContext(uptr pc, void *context, -                                                    u32 max_depth) { -  CONTEXT ctx = *(CONTEXT *)context; -  STACKFRAME64 stack_frame; -  memset(&stack_frame, 0, sizeof(stack_frame)); - -  InitializeDbgHelpIfNeeded(); - -  size = 0; -#if defined(_WIN64) -  int machine_type = IMAGE_FILE_MACHINE_AMD64; -  stack_frame.AddrPC.Offset = ctx.Rip; -  stack_frame.AddrFrame.Offset = ctx.Rbp; -  stack_frame.AddrStack.Offset = ctx.Rsp; -#else -  int machine_type = IMAGE_FILE_MACHINE_I386; -  stack_frame.AddrPC.Offset = ctx.Eip; -  stack_frame.AddrFrame.Offset = ctx.Ebp; -  stack_frame.AddrStack.Offset = ctx.Esp; -#endif -  stack_frame.AddrPC.Mode = AddrModeFlat; -  stack_frame.AddrFrame.Mode = AddrModeFlat; -  stack_frame.AddrStack.Mode = AddrModeFlat; -  while (StackWalk64(machine_type, GetCurrentProcess(), GetCurrentThread(), -                     &stack_frame, &ctx, NULL, SymFunctionTableAccess64, -                     SymGetModuleBase64, NULL) && -         size < Min(max_depth, kStackTraceMax)) { -    trace_buffer[size++] = (uptr)stack_frame.AddrPC.Offset; -  } -} -#endif  // #if !SANITIZER_GO -  void ReportFile::Write(const char *buffer, uptr length) {    SpinMutexLock l(mu);    ReopenIfNecessary(); @@ -1073,6 +1029,10 @@ void MaybeReexec() {    // No need to re-exec on Windows.  } +void CheckASLR() { +  // Do nothing +} +  char **GetArgv() {    // FIXME: Actually implement this function.    return 0; @@ -1106,9 +1066,10 @@ bool GetRandom(void *buffer, uptr length, bool blocking) {    UNIMPLEMENTED();  } -// FIXME: implement on this platform.  u32 GetNumberOfCPUs() { -  UNIMPLEMENTED(); +  SYSTEM_INFO sysinfo = {}; +  GetNativeSystemInfo(&sysinfo); +  return sysinfo.dwNumberOfProcessors;  }  }  // namespace __sanitizer diff --git a/lib/sanitizer_common/symbolizer/scripts/build_symbolizer.sh b/lib/sanitizer_common/symbolizer/scripts/build_symbolizer.sh index 0559a2e7eb053..0c3917c6b17b1 100755 --- a/lib/sanitizer_common/symbolizer/scripts/build_symbolizer.sh +++ b/lib/sanitizer_common/symbolizer/scripts/build_symbolizer.sh @@ -2,7 +2,7 @@  #  # Run as: CLANG=bin/clang ZLIB_SRC=src/zlib \  #             build_symbolizer.sh runtime_build/lib/clang/4.0.0/lib/linux/ -# zlib can be downloaded from from http://www.zlib.net. +# zlib can be downloaded from http://www.zlib.net.  #  # Script compiles self-contained object file with symbolization code and injects  # it into the given set of runtime libraries. Script updates only libraries @@ -98,12 +98,10 @@ if [[ ! -d ${LIBCXX_BUILD} ]]; then      -DLIBCXXABI_ENABLE_ASSERTIONS=OFF \      -DLIBCXXABI_ENABLE_EXCEPTIONS=OFF \      -DLIBCXXABI_ENABLE_SHARED=OFF \ -    -DLIBCXXABI_ENABLE_THREADS=OFF \      -DLIBCXX_ENABLE_ASSERTIONS=OFF \      -DLIBCXX_ENABLE_EXCEPTIONS=OFF \      -DLIBCXX_ENABLE_RTTI=OFF \      -DLIBCXX_ENABLE_SHARED=OFF \ -    -DLIBCXX_ENABLE_THREADS=OFF \    $LLVM_SRC  fi  cd ${LIBCXX_BUILD} @@ -129,7 +127,7 @@ if [[ ! -d ${LLVM_BUILD} ]]; then    $LLVM_SRC  fi  cd ${LLVM_BUILD} -ninja LLVMSymbolize LLVMObject LLVMBinaryFormat LLVMDebugInfoDWARF LLVMSupport LLVMDebugInfoPDB LLVMMC +ninja LLVMSymbolize LLVMObject LLVMBinaryFormat LLVMDebugInfoDWARF LLVMSupport LLVMDebugInfoPDB LLVMMC LLVMDemangle  cd ${BUILD_DIR}  rm -rf ${SYMBOLIZER_BUILD} @@ -152,6 +150,7 @@ $SCRIPT_DIR/ar_to_bc.sh $LIBCXX_BUILD/lib/libc++.a \                          $LLVM_BUILD/lib/libLLVMDebugInfoDWARF.a \                          $LLVM_BUILD/lib/libLLVMSupport.a \                          $LLVM_BUILD/lib/libLLVMDebugInfoPDB.a \ +                        $LLVM_BUILD/lib/libLLVMDemangle.a \                          $LLVM_BUILD/lib/libLLVMMC.a \                          $ZLIB_BUILD/libz.a \                          symbolizer.a \ diff --git a/lib/sanitizer_common/symbolizer/scripts/global_symbols.txt b/lib/sanitizer_common/symbolizer/scripts/global_symbols.txt index a23c9534701d8..f77648d7818a2 100644 --- a/lib/sanitizer_common/symbolizer/scripts/global_symbols.txt +++ b/lib/sanitizer_common/symbolizer/scripts/global_symbols.txt @@ -15,6 +15,14 @@ __divdi3 U  __dso_handle U  __errno_location U  __interceptor_pread w +__interceptor_pthread_cond_broadcast w +__interceptor_pthread_cond_wait w +__interceptor_pthread_getspecific w +__interceptor_pthread_key_create w +__interceptor_pthread_mutex_lock w +__interceptor_pthread_mutex_unlock w +__interceptor_pthread_once w +__interceptor_pthread_setspecific w  __interceptor_read w  __interceptor_realpath w  __moddi3 U @@ -61,6 +69,7 @@ gettimeofday U  ioctl U  isalpha U  isatty U +islower U  isprint U  isupper U  isxdigit U diff --git a/lib/sanitizer_common/tests/CMakeLists.txt b/lib/sanitizer_common/tests/CMakeLists.txt index 1bccaa78f39bd..401682baa07b4 100644 --- a/lib/sanitizer_common/tests/CMakeLists.txt +++ b/lib/sanitizer_common/tests/CMakeLists.txt @@ -41,7 +41,7 @@ set(SANITIZER_TEST_HEADERS    sanitizer_pthread_wrappers.h    sanitizer_test_config.h    sanitizer_test_utils.h) -foreach(header ${SANITIZER_HEADERS}) +foreach(header ${SANITIZER_IMPL_HEADERS})    list(APPEND SANITIZER_TEST_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/../${header})  endforeach() @@ -54,7 +54,8 @@ set(SANITIZER_TEST_CFLAGS_COMMON    -fno-rtti    -O2    -Werror=sign-compare -  -Wno-non-virtual-dtor) +  -Wno-non-virtual-dtor +  -Wno-gnu-zero-variadic-macro-arguments)  if(MSVC)    # Disable exceptions on Windows until they work reliably. @@ -178,7 +179,8 @@ if(COMPILER_RT_CAN_EXECUTE_TESTS AND NOT ANDROID)    if(APPLE)      add_sanitizer_common_lib("RTSanitizerCommon.test.osx"                               $<TARGET_OBJECTS:RTSanitizerCommon.osx> -                             $<TARGET_OBJECTS:RTSanitizerCommonLibc.osx>) +                             $<TARGET_OBJECTS:RTSanitizerCommonLibc.osx> +                             $<TARGET_OBJECTS:RTSanitizerCommonSymbolizer.osx>)    else()      if(CAN_TARGET_x86_64)        add_sanitizer_common_lib("RTSanitizerCommon.test.nolibc.x86_64" @@ -188,7 +190,8 @@ if(COMPILER_RT_CAN_EXECUTE_TESTS AND NOT ANDROID)      foreach(arch ${SANITIZER_UNITTEST_SUPPORTED_ARCH})        add_sanitizer_common_lib("RTSanitizerCommon.test.${arch}"                                 $<TARGET_OBJECTS:RTSanitizerCommon.${arch}> -                               $<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>) +                               $<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}> +                               $<TARGET_OBJECTS:RTSanitizerCommonSymbolizer.${arch}>)      endforeach()    endif()    foreach(arch ${SANITIZER_UNITTEST_SUPPORTED_ARCH}) @@ -202,7 +205,8 @@ if(ANDROID)        ${SANITIZER_UNITTESTS}        ${COMPILER_RT_GTEST_SOURCE}        $<TARGET_OBJECTS:RTSanitizerCommon.${arch}> -      $<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>) +      $<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}> +      $<TARGET_OBJECTS:RTSanitizerCommonSymbolizer.${arch}>)      set_target_compile_flags(SanitizerTest        ${SANITIZER_COMMON_CFLAGS}        ${SANITIZER_TEST_CFLAGS_COMMON}) diff --git a/lib/sanitizer_common/tests/sanitizer_allocator_test.cc b/lib/sanitizer_common/tests/sanitizer_allocator_test.cc index 7b5e3e21f1ee3..ef4c10b8de5d3 100644 --- a/lib/sanitizer_common/tests/sanitizer_allocator_test.cc +++ b/lib/sanitizer_common/tests/sanitizer_allocator_test.cc @@ -444,7 +444,7 @@ TEST(SanitizerCommon, SizeClassAllocator32MapUnmapCallback) {  TEST(SanitizerCommon, LargeMmapAllocatorMapUnmapCallback) {    TestMapUnmapCallback::map_count = 0;    TestMapUnmapCallback::unmap_count = 0; -  LargeMmapAllocator<TestMapUnmapCallback, DieOnFailure> a; +  LargeMmapAllocator<TestMapUnmapCallback> a;    a.Init();    AllocatorStats stats;    stats.Init(); @@ -482,7 +482,7 @@ TEST(SanitizerCommon, SizeClassAllocator64Overflow) {  #endif  TEST(SanitizerCommon, LargeMmapAllocator) { -  LargeMmapAllocator<NoOpMapUnmapCallback, DieOnFailure> a; +  LargeMmapAllocator<NoOpMapUnmapCallback> a;    a.Init();    AllocatorStats stats;    stats.Init(); @@ -565,7 +565,6 @@ void TestCombinedAllocator() {    typedef        CombinedAllocator<PrimaryAllocator, AllocatorCache, SecondaryAllocator>        Allocator; -  SetAllocatorMayReturnNull(true);    Allocator *a = new Allocator;    a->Init(kReleaseToOSIntervalNever);    std::mt19937 r; @@ -579,11 +578,7 @@ void TestCombinedAllocator() {    EXPECT_EQ(a->Allocate(&cache, (uptr)-1 - 1024, 1), (void*)0);    EXPECT_EQ(a->Allocate(&cache, (uptr)-1 - 1024, 1024), (void*)0);    EXPECT_EQ(a->Allocate(&cache, (uptr)-1 - 1023, 1024), (void*)0); - -  // Set to false -  SetAllocatorMayReturnNull(false); -  EXPECT_DEATH(a->Allocate(&cache, -1, 1), -               "allocator is terminating the process"); +  EXPECT_EQ(a->Allocate(&cache, -1, 1), (void*)0);    const uptr kNumAllocs = 100000;    const uptr kNumIter = 10; @@ -818,11 +813,11 @@ TEST(Allocator, LargeAlloc) {  TEST(Allocator, ScopedBuffer) {    const int kSize = 512;    { -    InternalScopedBuffer<int> int_buf(kSize); -    EXPECT_EQ(sizeof(int) * kSize, int_buf.size());  // NOLINT +    InternalMmapVector<int> int_buf(kSize); +    EXPECT_EQ((uptr)kSize, int_buf.size()); // NOLINT    } -  InternalScopedBuffer<char> char_buf(kSize); -  EXPECT_EQ(sizeof(char) * kSize, char_buf.size());  // NOLINT +  InternalMmapVector<char> char_buf(kSize); +  EXPECT_EQ((uptr)kSize, char_buf.size()); // NOLINT    internal_memset(char_buf.data(), 'c', kSize);    for (int i = 0; i < kSize; i++) {      EXPECT_EQ('c', char_buf[i]); @@ -893,7 +888,7 @@ TEST(SanitizerCommon, SizeClassAllocator32Iteration) {  }  TEST(SanitizerCommon, LargeMmapAllocatorIteration) { -  LargeMmapAllocator<NoOpMapUnmapCallback, DieOnFailure> a; +  LargeMmapAllocator<NoOpMapUnmapCallback> a;    a.Init();    AllocatorStats stats;    stats.Init(); @@ -920,7 +915,7 @@ TEST(SanitizerCommon, LargeMmapAllocatorIteration) {  }  TEST(SanitizerCommon, LargeMmapAllocatorBlockBegin) { -  LargeMmapAllocator<NoOpMapUnmapCallback, DieOnFailure> a; +  LargeMmapAllocator<NoOpMapUnmapCallback> a;    a.Init();    AllocatorStats stats;    stats.Init(); @@ -1294,7 +1289,7 @@ TEST(SanitizerCommon, TwoLevelByteMap) {    const u64 kSize1 = 1 << 6, kSize2 = 1 << 12;    const u64 n = kSize1 * kSize2;    TwoLevelByteMap<kSize1, kSize2> m; -  m.TestOnlyInit(); +  m.Init();    for (u64 i = 0; i < n; i += 7) {      m.set(i, (i % 100) + 1);    } @@ -1329,7 +1324,7 @@ void *TwoLevelByteMapUserThread(void *param) {  TEST(SanitizerCommon, ThreadedTwoLevelByteMap) {    TestByteMap m; -  m.TestOnlyInit(); +  m.Init();    TestMapUnmapCallback::map_count = 0;    TestMapUnmapCallback::unmap_count = 0;    static const int kNumThreads = 4; diff --git a/lib/sanitizer_common/tests/sanitizer_common_test.cc b/lib/sanitizer_common/tests/sanitizer_common_test.cc index 576649cea3597..0177484a55a87 100644 --- a/lib/sanitizer_common/tests/sanitizer_common_test.cc +++ b/lib/sanitizer_common/tests/sanitizer_common_test.cc @@ -39,37 +39,37 @@ TEST(SanitizerCommon, SortTest) {    for (uptr i = 0; i < n; i++) {      array[i] = i;    } -  SortArray(array, n); +  Sort(array, n);    EXPECT_TRUE(IsSorted(array, n));    // Reverse order.    for (uptr i = 0; i < n; i++) {      array[i] = n - 1 - i;    } -  SortArray(array, n); +  Sort(array, n);    EXPECT_TRUE(IsSorted(array, n));    // Mixed order.    for (uptr i = 0; i < n; i++) {      array[i] = (i % 2 == 0) ? i : n - 1 - i;    } -  SortArray(array, n); +  Sort(array, n);    EXPECT_TRUE(IsSorted(array, n));    // All equal.    for (uptr i = 0; i < n; i++) {      array[i] = 42;    } -  SortArray(array, n); +  Sort(array, n);    EXPECT_TRUE(IsSorted(array, n));    // All but one sorted.    for (uptr i = 0; i < n - 1; i++) {      array[i] = i;    }    array[n - 1] = 42; -  SortArray(array, n); +  Sort(array, n);    EXPECT_TRUE(IsSorted(array, n));    // Minimal case - sort three elements.    array[0] = 1;    array[1] = 0; -  SortArray(array, 2); +  Sort(array, 2);    EXPECT_TRUE(IsSorted(array, 2));  } @@ -88,25 +88,37 @@ TEST(SanitizerCommon, MmapAlignedOrDieOnFatalError) {    }  } -#if SANITIZER_LINUX -TEST(SanitizerCommon, SanitizerSetThreadName) { -  const char *names[] = { -    "0123456789012", -    "01234567890123", -    "012345678901234",  // Larger names will be truncated on linux. -  }; +TEST(SanitizerCommon, InternalMmapVectorRoundUpCapacity) { +  InternalMmapVector<uptr> v; +  v.reserve(1); +  CHECK_EQ(v.capacity(), GetPageSizeCached() / sizeof(uptr)); +} -  for (size_t i = 0; i < ARRAY_SIZE(names); i++) { -    EXPECT_TRUE(SanitizerSetThreadName(names[i])); -    char buff[100]; -    EXPECT_TRUE(SanitizerGetThreadName(buff, sizeof(buff) - 1)); -    EXPECT_EQ(0, internal_strcmp(buff, names[i])); -  } +TEST(SanitizerCommon, InternalMmapVectorReize) { +  InternalMmapVector<uptr> v; +  CHECK_EQ(0U, v.size()); +  CHECK_GE(v.capacity(), v.size()); + +  v.reserve(1000); +  CHECK_EQ(0U, v.size()); +  CHECK_GE(v.capacity(), 1000U); + +  v.resize(10000); +  CHECK_EQ(10000U, v.size()); +  CHECK_GE(v.capacity(), v.size()); +  uptr cap = v.capacity(); + +  v.resize(100); +  CHECK_EQ(100U, v.size()); +  CHECK_EQ(v.capacity(), cap); + +  v.reserve(10); +  CHECK_EQ(100U, v.size()); +  CHECK_EQ(v.capacity(), cap);  } -#endif  TEST(SanitizerCommon, InternalMmapVector) { -  InternalMmapVector<uptr> vector(1); +  InternalMmapVector<uptr> vector;    for (uptr i = 0; i < 100; i++) {      EXPECT_EQ(i, vector.size());      vector.push_back(i); @@ -119,11 +131,52 @@ TEST(SanitizerCommon, InternalMmapVector) {      vector.pop_back();      EXPECT_EQ((uptr)i, vector.size());    } -  InternalMmapVector<uptr> empty_vector(0); +  InternalMmapVector<uptr> empty_vector;    CHECK_GT(empty_vector.capacity(), 0U);    CHECK_EQ(0U, empty_vector.size());  } +TEST(SanitizerCommon, InternalMmapVectorEq) { +  InternalMmapVector<uptr> vector1; +  InternalMmapVector<uptr> vector2; +  for (uptr i = 0; i < 100; i++) { +    vector1.push_back(i); +    vector2.push_back(i); +  } +  EXPECT_TRUE(vector1 == vector2); +  EXPECT_FALSE(vector1 != vector2); + +  vector1.push_back(1); +  EXPECT_FALSE(vector1 == vector2); +  EXPECT_TRUE(vector1 != vector2); + +  vector2.push_back(1); +  EXPECT_TRUE(vector1 == vector2); +  EXPECT_FALSE(vector1 != vector2); + +  vector1[55] = 1; +  EXPECT_FALSE(vector1 == vector2); +  EXPECT_TRUE(vector1 != vector2); +} + +TEST(SanitizerCommon, InternalMmapVectorSwap) { +  InternalMmapVector<uptr> vector1; +  InternalMmapVector<uptr> vector2; +  InternalMmapVector<uptr> vector3; +  InternalMmapVector<uptr> vector4; +  for (uptr i = 0; i < 100; i++) { +    vector1.push_back(i); +    vector2.push_back(i); +    vector3.push_back(-i); +    vector4.push_back(-i); +  } +  EXPECT_NE(vector2, vector3); +  EXPECT_NE(vector1, vector4); +  vector1.swap(vector3); +  EXPECT_EQ(vector2, vector3); +  EXPECT_EQ(vector1, vector4); +} +  void TestThreadInfo(bool main) {    uptr stk_addr = 0;    uptr stk_size = 0; diff --git a/lib/sanitizer_common/tests/sanitizer_libc_test.cc b/lib/sanitizer_common/tests/sanitizer_libc_test.cc index a73c65a510c2a..2f61601cdff95 100644 --- a/lib/sanitizer_common/tests/sanitizer_libc_test.cc +++ b/lib/sanitizer_common/tests/sanitizer_libc_test.cc @@ -9,6 +9,7 @@  // Tests for sanitizer_libc.h.  //===----------------------------------------------------------------------===//  #include <algorithm> +#include <fstream>  #include "sanitizer_common/sanitizer_common.h"  #include "sanitizer_common/sanitizer_file.h" @@ -82,8 +83,18 @@ static void temp_file_name(char *buf, size_t bufsize, const char *prefix) {    // on Android already.    tmpdir = GetEnv("EXTERNAL_STORAGE");  #endif -  u32 uid = GetUid(); -  internal_snprintf(buf, bufsize, "%s/%s%d", tmpdir, prefix, uid); +  internal_snprintf(buf, bufsize, "%s/%sXXXXXX", tmpdir, prefix); +  ASSERT_TRUE(mkstemp(buf)); +#endif +} + +static void Unlink(const char *path) { +#if SANITIZER_WINDOWS +  // No sanitizer needs to delete a file on Windows yet. If we ever do, we can +  // add a portable wrapper and test it from here. +  ::DeleteFileA(&path[0]); +#else +  internal_unlink(path);  #endif  } @@ -97,6 +108,14 @@ TEST(SanitizerCommon, FileOps) {    temp_file_name(tmpfile, sizeof(tmpfile), "sanitizer_common.fileops.tmp.");    fd_t fd = OpenFile(tmpfile, WrOnly);    ASSERT_NE(fd, kInvalidFd); +  ASSERT_TRUE(WriteToFile(fd, "A", 1)); +  CloseFile(fd); + +  fd = OpenFile(tmpfile, WrOnly); +  ASSERT_NE(fd, kInvalidFd); +#if SANITIZER_POSIX && !SANITIZER_MAC +  EXPECT_EQ(internal_lseek(fd, 0, SEEK_END), 0u); +#endif    uptr bytes_written = 0;    EXPECT_TRUE(WriteToFile(fd, str1, len1, &bytes_written));    EXPECT_EQ(len1, bytes_written); @@ -142,15 +161,67 @@ TEST(SanitizerCommon, FileOps) {    EXPECT_EQ(0, internal_memcmp(buf, str2, len2));    CloseFile(fd); -#if SANITIZER_WINDOWS -  // No sanitizer needs to delete a file on Windows yet. If we ever do, we can -  // add a portable wrapper and test it from here. -  ::DeleteFileA(&tmpfile[0]); -#else -  internal_unlink(tmpfile); -#endif +  Unlink(tmpfile);  } +class SanitizerCommonFileTest : public ::testing::TestWithParam<uptr> { +  void SetUp() override { +    data_.resize(GetParam()); +    std::generate(data_.begin(), data_.end(), [] { +      return rand() % 256;  // NOLINT +    }); + +    temp_file_name(file_name_, sizeof(file_name_), +                   "sanitizer_common.ReadFile.tmp."); + +    std::ofstream f(file_name_, std::ios::out | std::ios::binary); +    if (!data_.empty()) +      f.write(data_.data(), data_.size()); +  } + +  void TearDown() override { Unlink(file_name_); } + + protected: +  char file_name_[256]; +  std::vector<char> data_; +}; + +TEST_P(SanitizerCommonFileTest, ReadFileToBuffer) { +  char *buff; +  uptr size; +  uptr len; +  EXPECT_TRUE(ReadFileToBuffer(file_name_, &buff, &len, &size)); +  EXPECT_EQ(data_, std::vector<char>(buff, buff + size)); +  UnmapOrDie(buff, len); +} + +TEST_P(SanitizerCommonFileTest, ReadFileToBufferHalf) { +  char *buff; +  uptr size; +  uptr len; +  data_.resize(data_.size() / 2); +  EXPECT_TRUE(ReadFileToBuffer(file_name_, &buff, &len, &size, data_.size())); +  EXPECT_EQ(data_, std::vector<char>(buff, buff + size)); +  UnmapOrDie(buff, len); +} + +TEST_P(SanitizerCommonFileTest, ReadFileToVector) { +  InternalMmapVector<char> buff; +  EXPECT_TRUE(ReadFileToVector(file_name_, &buff)); +  EXPECT_EQ(data_, std::vector<char>(buff.begin(), buff.end())); +} + +TEST_P(SanitizerCommonFileTest, ReadFileToVectorHalf) { +  InternalMmapVector<char> buff; +  data_.resize(data_.size() / 2); +  EXPECT_TRUE(ReadFileToVector(file_name_, &buff, data_.size())); +  EXPECT_EQ(data_, std::vector<char>(buff.begin(), buff.end())); +} + +INSTANTIATE_TEST_CASE_P(FileSizes, SanitizerCommonFileTest, +                        ::testing::Values(0, 1, 7, 13, 32, 4096, 4097, 1048575, +                                          1048576, 1048577)); +  static const size_t kStrlcpyBufSize = 8;  void test_internal_strlcpy(char *dbuf, const char *sbuf) {    uptr retval = 0; diff --git a/lib/sanitizer_common/tests/sanitizer_linux_test.cc b/lib/sanitizer_common/tests/sanitizer_linux_test.cc index 8a6afab65adb5..fbac9cc1438e8 100644 --- a/lib/sanitizer_common/tests/sanitizer_linux_test.cc +++ b/lib/sanitizer_common/tests/sanitizer_linux_test.cc @@ -45,7 +45,7 @@ struct TidReporterArgument {      pthread_cond_destroy(&tid_reported_cond);    } -  pid_t reported_tid; +  tid_t reported_tid;    // For signaling to spawned threads that they should terminate.    pthread_cond_t terminate_thread_cond;    pthread_mutex_t terminate_thread_mutex; @@ -64,7 +64,7 @@ class ThreadListerTest : public ::testing::Test {   protected:    virtual void SetUp() {      pthread_t pthread_id; -    pid_t tid; +    tid_t tid;      for (uptr i = 0; i < kThreadCount; i++) {        SpawnTidReporter(&pthread_id, &tid);        pthread_ids_.push_back(pthread_id); @@ -81,12 +81,12 @@ class ThreadListerTest : public ::testing::Test {        pthread_join(pthread_ids_[i], NULL);    } -  void SpawnTidReporter(pthread_t *pthread_id, pid_t *tid); +  void SpawnTidReporter(pthread_t *pthread_id, tid_t *tid);    static const uptr kThreadCount = 20;    std::vector<pthread_t> pthread_ids_; -  std::vector<pid_t> tids_; +  std::vector<tid_t> tids_;    TidReporterArgument thread_arg;  }; @@ -107,72 +107,66 @@ void *TidReporterThread(void *argument) {    return NULL;  } -void ThreadListerTest::SpawnTidReporter(pthread_t *pthread_id, -                                        pid_t *tid) { +void ThreadListerTest::SpawnTidReporter(pthread_t *pthread_id, tid_t *tid) {    pthread_mutex_lock(&thread_arg.tid_reported_mutex);    thread_arg.reported_tid = -1;    ASSERT_EQ(0, pthread_create(pthread_id, NULL,                                TidReporterThread,                                &thread_arg)); -  while (thread_arg.reported_tid == -1) +  while (thread_arg.reported_tid == (tid_t)(-1))      pthread_cond_wait(&thread_arg.tid_reported_cond,                        &thread_arg.tid_reported_mutex);    pthread_mutex_unlock(&thread_arg.tid_reported_mutex);    *tid = thread_arg.reported_tid;  } -static std::vector<pid_t> ReadTidsToVector(ThreadLister *thread_lister) { -  std::vector<pid_t> listed_tids; -  pid_t tid; -  while ((tid = thread_lister->GetNextTID()) >= 0) -    listed_tids.push_back(tid); -  EXPECT_FALSE(thread_lister->error()); -  return listed_tids; +static std::vector<tid_t> ReadTidsToVector(ThreadLister *thread_lister) { +  std::vector<tid_t> listed_tids; +  InternalMmapVector<tid_t> threads(128); +  EXPECT_TRUE(thread_lister->ListThreads(&threads)); +  return std::vector<tid_t>(threads.begin(), threads.end());  } -static bool Includes(std::vector<pid_t> first, std::vector<pid_t> second) { +static bool Includes(std::vector<tid_t> first, std::vector<tid_t> second) {    std::sort(first.begin(), first.end());    std::sort(second.begin(), second.end());    return std::includes(first.begin(), first.end(),                         second.begin(), second.end());  } -static bool HasElement(std::vector<pid_t> vector, pid_t element) { +static bool HasElement(const std::vector<tid_t> &vector, tid_t element) {    return std::find(vector.begin(), vector.end(), element) != vector.end();  }  // ThreadLister's output should include the current thread's TID and the TID of  // every thread we spawned.  TEST_F(ThreadListerTest, ThreadListerSeesAllSpawnedThreads) { -  pid_t self_tid = GetTid(); +  tid_t self_tid = GetTid();    ThreadLister thread_lister(getpid()); -  std::vector<pid_t> listed_tids = ReadTidsToVector(&thread_lister); +  std::vector<tid_t> listed_tids = ReadTidsToVector(&thread_lister);    ASSERT_TRUE(HasElement(listed_tids, self_tid));    ASSERT_TRUE(Includes(listed_tids, tids_));  } -// Calling Reset() should not cause ThreadLister to forget any threads it's -// supposed to know about. -TEST_F(ThreadListerTest, ResetDoesNotForgetThreads) { +TEST_F(ThreadListerTest, DoNotForgetThreads) {    ThreadLister thread_lister(getpid()); -  // Run the loop body twice, because Reset() might behave differently if called -  // on a freshly created object. +  // Run the loop body twice, because ThreadLister might behave differently if +  // called on a freshly created object.    for (uptr i = 0; i < 2; i++) { -    thread_lister.Reset(); -    std::vector<pid_t> listed_tids = ReadTidsToVector(&thread_lister); +    std::vector<tid_t> listed_tids = ReadTidsToVector(&thread_lister);      ASSERT_TRUE(Includes(listed_tids, tids_));    }  }  // If new threads have spawned during ThreadLister object's lifetime, calling -// Reset() should cause ThreadLister to recognize their existence. -TEST_F(ThreadListerTest, ResetMakesNewThreadsKnown) { +// relisting should cause ThreadLister to recognize their existence. +TEST_F(ThreadListerTest, NewThreads) {    ThreadLister thread_lister(getpid()); -  std::vector<pid_t> threads_before_extra = ReadTidsToVector(&thread_lister); +  std::vector<tid_t> threads_before_extra = ReadTidsToVector(&thread_lister);    pthread_t extra_pthread_id; -  pid_t extra_tid; +  tid_t extra_tid;    SpawnTidReporter(&extra_pthread_id, &extra_tid);    // Register the new thread so it gets terminated in TearDown().    pthread_ids_.push_back(extra_pthread_id); @@ -182,9 +176,7 @@ TEST_F(ThreadListerTest, ResetMakesNewThreadsKnown) {    // so better check for that.    ASSERT_FALSE(HasElement(threads_before_extra, extra_tid)); -  thread_lister.Reset(); - -  std::vector<pid_t> threads_after_extra = ReadTidsToVector(&thread_lister); +  std::vector<tid_t> threads_after_extra = ReadTidsToVector(&thread_lister);    ASSERT_TRUE(HasElement(threads_after_extra, extra_tid));  } diff --git a/lib/sanitizer_common/tests/sanitizer_printf_test.cc b/lib/sanitizer_common/tests/sanitizer_printf_test.cc index 5a77b470caf5c..75fe6667864f8 100644 --- a/lib/sanitizer_common/tests/sanitizer_printf_test.cc +++ b/lib/sanitizer_common/tests/sanitizer_printf_test.cc @@ -148,6 +148,14 @@ TEST(Printf, Precision) {    len = internal_snprintf(buf, sizeof(buf), "%.*s", 6, "12345");    EXPECT_EQ(5U, len);    EXPECT_STREQ("12345", buf); +  len = internal_snprintf(buf, sizeof(buf), "%-6s", "12345"); +  EXPECT_EQ(6U, len); +  EXPECT_STREQ("12345 ", buf); +  // Check that width does not overflow the smaller buffer, although +  // 10 chars is requested, it stops at the buffer size, 8. +  len = internal_snprintf(buf, 8, "%-10s", "12345"); +  EXPECT_EQ(10U, len);  // The required size reported. +  EXPECT_STREQ("12345  ", buf);  }  }  // namespace __sanitizer diff --git a/lib/sanitizer_common/tests/sanitizer_procmaps_test.cc b/lib/sanitizer_common/tests/sanitizer_procmaps_test.cc index 4ac55c706d6c4..22052d9a4f592 100644 --- a/lib/sanitizer_common/tests/sanitizer_procmaps_test.cc +++ b/lib/sanitizer_common/tests/sanitizer_procmaps_test.cc @@ -37,7 +37,8 @@ TEST(MemoryMappingLayout, DumpListOfModules) {    const char *binary_name = last_slash ? last_slash + 1 : argv0;    MemoryMappingLayout memory_mapping(false);    const uptr kMaxModules = 100; -  InternalMmapVector<LoadedModule> modules(kMaxModules); +  InternalMmapVector<LoadedModule> modules; +  modules.reserve(kMaxModules);    memory_mapping.DumpListOfModules(&modules);    EXPECT_GT(modules.size(), 0U);    bool found = false; @@ -56,7 +57,8 @@ TEST(MemoryMapping, LoadedModuleArchAndUUID) {    if (SANITIZER_MAC) {      MemoryMappingLayout memory_mapping(false);      const uptr kMaxModules = 100; -    InternalMmapVector<LoadedModule> modules(kMaxModules); +    InternalMmapVector<LoadedModule> modules; +    modules.reserve(kMaxModules);      memory_mapping.DumpListOfModules(&modules);      for (uptr i = 0; i < modules.size(); ++i) {        ModuleArch arch = modules[i].arch(); diff --git a/lib/sanitizer_common/tests/sanitizer_test_utils.h b/lib/sanitizer_common/tests/sanitizer_test_utils.h index f8821a15d9b91..5c1f8ad488647 100644 --- a/lib/sanitizer_common/tests/sanitizer_test_utils.h +++ b/lib/sanitizer_common/tests/sanitizer_test_utils.h @@ -104,10 +104,16 @@ static inline uint32_t my_rand() {  #if !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(__ANDROID__) && \      !defined(__NetBSD__) && !defined(_WIN32)  # define SANITIZER_TEST_HAS_MEMALIGN 1 +#else +# define SANITIZER_TEST_HAS_MEMALIGN 0 +#endif + +#if !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(__ANDROID__) && \ +    !defined(__NetBSD__) && !defined(_WIN32) && \ +    !(defined(__sun__) && defined(__svr4__))  # define SANITIZER_TEST_HAS_PVALLOC 1  # define SANITIZER_TEST_HAS_MALLOC_USABLE_SIZE 1  #else -# define SANITIZER_TEST_HAS_MEMALIGN 0  # define SANITIZER_TEST_HAS_PVALLOC 0  # define SANITIZER_TEST_HAS_MALLOC_USABLE_SIZE 0  #endif diff --git a/lib/sanitizer_common/tests/sanitizer_vector_test.cc b/lib/sanitizer_common/tests/sanitizer_vector_test.cc index 33ed14e190c52..59fbf39685bdf 100644 --- a/lib/sanitizer_common/tests/sanitizer_vector_test.cc +++ b/lib/sanitizer_common/tests/sanitizer_vector_test.cc @@ -17,12 +17,12 @@ namespace __sanitizer {  TEST(Vector, Basic) {    Vector<int> v; -  EXPECT_EQ(v.Size(), (uptr)0); +  EXPECT_EQ(v.Size(), 0u);    v.PushBack(42); -  EXPECT_EQ(v.Size(), (uptr)1); +  EXPECT_EQ(v.Size(), 1u);    EXPECT_EQ(v[0], 42);    v.PushBack(43); -  EXPECT_EQ(v.Size(), (uptr)2); +  EXPECT_EQ(v.Size(), 2u);    EXPECT_EQ(v[0], 42);    EXPECT_EQ(v[1], 43);  } @@ -31,7 +31,7 @@ TEST(Vector, Stride) {    Vector<int> v;    for (int i = 0; i < 1000; i++) {      v.PushBack(i); -    EXPECT_EQ(v.Size(), (uptr)(i + 1)); +    EXPECT_EQ(v.Size(), i + 1u);      EXPECT_EQ(v[i], i);    }    for (int i = 0; i < 1000; i++) { @@ -39,4 +39,13 @@ TEST(Vector, Stride) {    }  } +TEST(Vector, ResizeReduction) { +  Vector<int> v; +  v.PushBack(0); +  v.PushBack(0); +  EXPECT_EQ(v.Size(), 2u); +  v.Resize(1); +  EXPECT_EQ(v.Size(), 1u); +} +  }  // namespace __sanitizer diff --git a/lib/scudo/CMakeLists.txt b/lib/scudo/CMakeLists.txt index 4d26a3477feb6..0646c3dd4f538 100644 --- a/lib/scudo/CMakeLists.txt +++ b/lib/scudo/CMakeLists.txt @@ -7,11 +7,41 @@ set(SCUDO_CFLAGS ${SANITIZER_COMMON_CFLAGS})  list(APPEND SCUDO_CFLAGS -fbuiltin)  append_rtti_flag(OFF SCUDO_CFLAGS) +set(SCUDO_MINIMAL_DYNAMIC_LIBS ${SANITIZER_COMMON_LINK_LIBS}) +append_list_if(COMPILER_RT_HAS_LIBDL dl SCUDO_MINIMAL_DYNAMIC_LIBS) +append_list_if(COMPILER_RT_HAS_LIBRT rt SCUDO_MINIMAL_DYNAMIC_LIBS) +append_list_if(COMPILER_RT_HAS_LIBPTHREAD pthread SCUDO_MINIMAL_DYNAMIC_LIBS) +append_list_if(COMPILER_RT_HAS_LIBLOG log SCUDO_MINIMAL_DYNAMIC_LIBS) + +set(SCUDO_DYNAMIC_LINK_FLAGS ${SANITIZER_COMMON_LINK_FLAGS}) +# Use gc-sections by default to avoid unused code being pulled in. +list(APPEND SCUDO_DYNAMIC_LINK_FLAGS -Wl,--gc-sections) + +# The minimal Scudo runtime does not inlude the UBSan runtime. +set(SCUDO_MINIMAL_OBJECT_LIBS +  RTSanitizerCommonNoTermination +  RTSanitizerCommonLibc +  RTInterception) +set(SCUDO_OBJECT_LIBS ${SCUDO_MINIMAL_OBJECT_LIBS}) +set(SCUDO_DYNAMIC_LIBS ${SCUDO_MINIMAL_DYNAMIC_LIBS}) + +if (FUCHSIA) +  list(APPEND SCUDO_CFLAGS -nostdinc++) +  list(APPEND SCUDO_DYNAMIC_LINK_FLAGS -nostdlib++) +else() +  list(APPEND SCUDO_DYNAMIC_LIBS ${SANITIZER_CXX_ABI_LIBRARY}) +  list(APPEND SCUDO_OBJECT_LIBS +    RTSanitizerCommonCoverage +    RTSanitizerCommonSymbolizer +    RTUbsan) +endif() +  set(SCUDO_SOURCES    scudo_allocator.cpp -  scudo_flags.cpp    scudo_crc32.cpp -  scudo_interceptors.cpp +  scudo_errors.cpp +  scudo_flags.cpp +  scudo_malloc.cpp    scudo_termination.cpp    scudo_tsd_exclusive.cpp    scudo_tsd_shared.cpp @@ -20,6 +50,21 @@ set(SCUDO_SOURCES  set(SCUDO_CXX_SOURCES    scudo_new_delete.cpp) +set(SCUDO_HEADERS +  scudo_allocator.h +  scudo_allocator_combined.h +  scudo_allocator_secondary.h +  scudo_crc32.h +  scudo_errors.h +  scudo_flags.h +  scudo_flags.inc +  scudo_interface_internal.h +  scudo_platform.h +  scudo_tsd.h +  scudo_tsd_exclusive.inc +  scudo_tsd_shared.inc +  scudo_utils.h) +  # Enable the SSE 4.2 instruction set for scudo_crc32.cpp, if available.  if (COMPILER_RT_HAS_MSSE4_2_FLAG)    set_source_files_properties(scudo_crc32.cpp PROPERTIES COMPILE_FLAGS -msse4.2) @@ -32,41 +77,58 @@ if (COMPILER_RT_HAS_MCRC_FLAG)  endif()  if(COMPILER_RT_HAS_SCUDO) -  set(SCUDO_DYNAMIC_LIBS ${SANITIZER_COMMON_LINK_LIBS}) -  append_list_if(COMPILER_RT_HAS_LIBDL dl SCUDO_DYNAMIC_LIBS) -  append_list_if(COMPILER_RT_HAS_LIBRT rt SCUDO_DYNAMIC_LIBS) -  append_list_if(COMPILER_RT_HAS_LIBPTHREAD pthread SCUDO_DYNAMIC_LIBS) -  append_list_if(COMPILER_RT_HAS_LIBLOG log SCUDO_DYNAMIC_LIBS) +  add_compiler_rt_runtime(clang_rt.scudo_minimal +    STATIC +    ARCHS ${SCUDO_SUPPORTED_ARCH} +    SOURCES ${SCUDO_SOURCES} +    ADDITIONAL_HEADERS ${SCUDO_HEADERS} +    OBJECT_LIBS ${SCUDO_MINIMAL_OBJECT_LIBS} +    CFLAGS ${SCUDO_CFLAGS} +    PARENT_TARGET scudo) +  add_compiler_rt_runtime(clang_rt.scudo_cxx_minimal +    STATIC +    ARCHS ${SCUDO_SUPPORTED_ARCH} +    SOURCES ${SCUDO_CXX_SOURCES} +    ADDITIONAL_HEADERS ${SCUDO_HEADERS} +    CFLAGS ${SCUDO_CFLAGS} +    PARENT_TARGET scudo)    add_compiler_rt_runtime(clang_rt.scudo      STATIC      ARCHS ${SCUDO_SUPPORTED_ARCH}      SOURCES ${SCUDO_SOURCES} -    OBJECT_LIBS RTSanitizerCommonNoTermination -                RTSanitizerCommonLibc -                RTInterception -                RTUbsan +    ADDITIONAL_HEADERS ${SCUDO_HEADERS} +    OBJECT_LIBS ${SCUDO_OBJECT_LIBS}      CFLAGS ${SCUDO_CFLAGS}      PARENT_TARGET scudo) -    add_compiler_rt_runtime(clang_rt.scudo_cxx      STATIC      ARCHS ${SCUDO_SUPPORTED_ARCH}      SOURCES ${SCUDO_CXX_SOURCES} +    ADDITIONAL_HEADERS ${SCUDO_HEADERS}      OBJECT_LIBS RTUbsan_cxx      CFLAGS ${SCUDO_CFLAGS}      PARENT_TARGET scudo) +  add_compiler_rt_runtime(clang_rt.scudo_minimal +    SHARED +    ARCHS ${SCUDO_SUPPORTED_ARCH} +    SOURCES ${SCUDO_SOURCES} ${SCUDO_CXX_SOURCES} +    ADDITIONAL_HEADERS ${SCUDO_HEADERS} +    OBJECT_LIBS ${SCUDO_MINIMAL_OBJECT_LIBS} +    CFLAGS ${SCUDO_CFLAGS} +    LINK_FLAGS ${SCUDO_DYNAMIC_LINK_FLAGS} +    LINK_LIBS ${SCUDO_MINIMAL_DYNAMIC_LIBS} +    PARENT_TARGET scudo) +    add_compiler_rt_runtime(clang_rt.scudo      SHARED      ARCHS ${SCUDO_SUPPORTED_ARCH}      SOURCES ${SCUDO_SOURCES} ${SCUDO_CXX_SOURCES} -    OBJECT_LIBS RTSanitizerCommonNoTermination -                RTSanitizerCommonLibc -                RTInterception -                RTUbsan -                RTUbsan_cxx +    ADDITIONAL_HEADERS ${SCUDO_HEADERS} +    OBJECT_LIBS ${SCUDO_OBJECT_LIBS}      CFLAGS ${SCUDO_CFLAGS} +    LINK_FLAGS ${SCUDO_DYNAMIC_LINK_FLAGS}      LINK_LIBS ${SCUDO_DYNAMIC_LIBS}      PARENT_TARGET scudo)  endif() diff --git a/lib/scudo/scudo_allocator.cpp b/lib/scudo/scudo_allocator.cpp index e5a4d714c66e4..4a11bf5fcc212 100644 --- a/lib/scudo/scudo_allocator.cpp +++ b/lib/scudo/scudo_allocator.cpp @@ -16,7 +16,9 @@  #include "scudo_allocator.h"  #include "scudo_crc32.h" +#include "scudo_errors.h"  #include "scudo_flags.h" +#include "scudo_interface_internal.h"  #include "scudo_tsd.h"  #include "scudo_utils.h" @@ -60,40 +62,49 @@ INLINE u32 computeCRC32(u32 Crc, uptr Value, uptr *Array, uptr ArraySize) {  #endif  // defined(__SSE4_2__) || defined(__ARM_FEATURE_CRC32)  } -static ScudoBackendAllocator &getBackendAllocator(); +static BackendT &getBackend();  namespace Chunk { -  // We can't use the offset member of the chunk itself, as we would double -  // fetch it without any warranty that it wouldn't have been tampered. To -  // prevent this, we work with a local copy of the header. -  static INLINE void *getBackendPtr(const void *Ptr, UnpackedHeader *Header) { -    return reinterpret_cast<void *>(reinterpret_cast<uptr>(Ptr) - -                                    AlignedChunkHeaderSize - -                                    (Header->Offset << MinAlignmentLog)); -  } -    static INLINE AtomicPackedHeader *getAtomicHeader(void *Ptr) {      return reinterpret_cast<AtomicPackedHeader *>(reinterpret_cast<uptr>(Ptr) - -                                                  AlignedChunkHeaderSize); +        getHeaderSize());    }    static INLINE    const AtomicPackedHeader *getConstAtomicHeader(const void *Ptr) {      return reinterpret_cast<const AtomicPackedHeader *>( -        reinterpret_cast<uptr>(Ptr) - AlignedChunkHeaderSize); +        reinterpret_cast<uptr>(Ptr) - getHeaderSize());    }    static INLINE bool isAligned(const void *Ptr) {      return IsAligned(reinterpret_cast<uptr>(Ptr), MinAlignment);    } +  // We can't use the offset member of the chunk itself, as we would double +  // fetch it without any warranty that it wouldn't have been tampered. To +  // prevent this, we work with a local copy of the header. +  static INLINE void *getBackendPtr(const void *Ptr, UnpackedHeader *Header) { +    return reinterpret_cast<void *>(reinterpret_cast<uptr>(Ptr) - +        getHeaderSize() - (Header->Offset << MinAlignmentLog)); +  } +    // Returns the usable size for a chunk, meaning the amount of bytes from the    // beginning of the user data to the end of the backend allocated chunk.    static INLINE uptr getUsableSize(const void *Ptr, UnpackedHeader *Header) { -    const uptr Size = getBackendAllocator().getActuallyAllocatedSize( -        getBackendPtr(Ptr, Header), Header->ClassId); -    if (Size == 0) -      return 0; -    return Size - AlignedChunkHeaderSize - (Header->Offset << MinAlignmentLog); +    const uptr ClassId = Header->ClassId; +    if (ClassId) +      return PrimaryT::ClassIdToSize(ClassId) - getHeaderSize() - +          (Header->Offset << MinAlignmentLog); +    return SecondaryT::GetActuallyAllocatedSize( +        getBackendPtr(Ptr, Header)) - getHeaderSize(); +  } + +  // Returns the size the user requested when allocating the chunk. +  static INLINE uptr getSize(const void *Ptr, UnpackedHeader *Header) { +    const uptr SizeOrUnusedBytes = Header->SizeOrUnusedBytes; +    if (Header->ClassId) +      return SizeOrUnusedBytes; +    return SecondaryT::GetActuallyAllocatedSize( +        getBackendPtr(Ptr, Header)) - getHeaderSize() - SizeOrUnusedBytes;    }    // Compute the checksum of the chunk pointer and its header. @@ -136,9 +147,8 @@ namespace Chunk {          atomic_load_relaxed(getConstAtomicHeader(Ptr));      *NewUnpackedHeader = bit_cast<UnpackedHeader>(NewPackedHeader);      if (UNLIKELY(NewUnpackedHeader->Checksum != -        computeChecksum(Ptr, NewUnpackedHeader))) { -      dieWithMessage("ERROR: corrupted chunk header at address %p\n", Ptr); -    } +        computeChecksum(Ptr, NewUnpackedHeader))) +      dieWithMessage("corrupted chunk header at address %p\n", Ptr);    }    // Packs and stores the header, computing the checksum in the process. @@ -159,14 +169,13 @@ namespace Chunk {      PackedHeader OldPackedHeader = bit_cast<PackedHeader>(*OldUnpackedHeader);      if (UNLIKELY(!atomic_compare_exchange_strong(              getAtomicHeader(Ptr), &OldPackedHeader, NewPackedHeader, -            memory_order_relaxed))) { -      dieWithMessage("ERROR: race on chunk header at address %p\n", Ptr); -    } +            memory_order_relaxed))) +      dieWithMessage("race on chunk header at address %p\n", Ptr);    }  }  // namespace Chunk  struct QuarantineCallback { -  explicit QuarantineCallback(AllocatorCache *Cache) +  explicit QuarantineCallback(AllocatorCacheT *Cache)      : Cache_(Cache) {}    // Chunk recycling function, returns a quarantined chunk to the backend, @@ -174,53 +183,48 @@ struct QuarantineCallback {    void Recycle(void *Ptr) {      UnpackedHeader Header;      Chunk::loadHeader(Ptr, &Header); -    if (UNLIKELY(Header.State != ChunkQuarantine)) { -      dieWithMessage("ERROR: invalid chunk state when recycling address %p\n", -                     Ptr); -    } +    if (UNLIKELY(Header.State != ChunkQuarantine)) +      dieWithMessage("invalid chunk state when recycling address %p\n", Ptr);      Chunk::eraseHeader(Ptr);      void *BackendPtr = Chunk::getBackendPtr(Ptr, &Header);      if (Header.ClassId) -      getBackendAllocator().deallocatePrimary(Cache_, BackendPtr, -                                              Header.ClassId); +      getBackend().deallocatePrimary(Cache_, BackendPtr, Header.ClassId);      else -      getBackendAllocator().deallocateSecondary(BackendPtr); +      getBackend().deallocateSecondary(BackendPtr);    }    // Internal quarantine allocation and deallocation functions. We first check    // that the batches are indeed serviced by the Primary.    // TODO(kostyak): figure out the best way to protect the batches.    void *Allocate(uptr Size) { -    return getBackendAllocator().allocatePrimary(Cache_, BatchClassId); +    const uptr BatchClassId = SizeClassMap::ClassID(sizeof(QuarantineBatch)); +    return getBackend().allocatePrimary(Cache_, BatchClassId);    }    void Deallocate(void *Ptr) { -    getBackendAllocator().deallocatePrimary(Cache_, Ptr, BatchClassId); +    const uptr BatchClassId = SizeClassMap::ClassID(sizeof(QuarantineBatch)); +    getBackend().deallocatePrimary(Cache_, Ptr, BatchClassId);    } -  AllocatorCache *Cache_; +  AllocatorCacheT *Cache_;    COMPILER_CHECK(sizeof(QuarantineBatch) < SizeClassMap::kMaxSize); -  const uptr BatchClassId = SizeClassMap::ClassID(sizeof(QuarantineBatch));  }; -typedef Quarantine<QuarantineCallback, void> ScudoQuarantine; -typedef ScudoQuarantine::Cache ScudoQuarantineCache; -COMPILER_CHECK(sizeof(ScudoQuarantineCache) <= +typedef Quarantine<QuarantineCallback, void> QuarantineT; +typedef QuarantineT::Cache QuarantineCacheT; +COMPILER_CHECK(sizeof(QuarantineCacheT) <=                 sizeof(ScudoTSD::QuarantineCachePlaceHolder)); -ScudoQuarantineCache *getQuarantineCache(ScudoTSD *TSD) { -  return reinterpret_cast<ScudoQuarantineCache *>( -      TSD->QuarantineCachePlaceHolder); +QuarantineCacheT *getQuarantineCache(ScudoTSD *TSD) { +  return reinterpret_cast<QuarantineCacheT *>(TSD->QuarantineCachePlaceHolder);  } -struct ScudoAllocator { +struct Allocator {    static const uptr MaxAllowedMallocSize =        FIRST_32_SECOND_64(2UL << 30, 1ULL << 40); -  typedef ReturnNullOrDieOnFailure FailureHandler; - -  ScudoBackendAllocator BackendAllocator; -  ScudoQuarantine AllocatorQuarantine; +  BackendT Backend; +  QuarantineT Quarantine;    u32 QuarantineChunksUpToSize; @@ -234,49 +238,16 @@ struct ScudoAllocator {    atomic_uint8_t RssLimitExceeded;    atomic_uint64_t RssLastCheckedAtNS; -  explicit ScudoAllocator(LinkerInitialized) -    : AllocatorQuarantine(LINKER_INITIALIZED) {} - -  void performSanityChecks() { -    // Verify that the header offset field can hold the maximum offset. In the -    // case of the Secondary allocator, it takes care of alignment and the -    // offset will always be 0. In the case of the Primary, the worst case -    // scenario happens in the last size class, when the backend allocation -    // would already be aligned on the requested alignment, which would happen -    // to be the maximum alignment that would fit in that size class. As a -    // result, the maximum offset will be at most the maximum alignment for the -    // last size class minus the header size, in multiples of MinAlignment. -    UnpackedHeader Header = {}; -    const uptr MaxPrimaryAlignment = -        1 << MostSignificantSetBitIndex(SizeClassMap::kMaxSize - MinAlignment); -    const uptr MaxOffset = -        (MaxPrimaryAlignment - AlignedChunkHeaderSize) >> MinAlignmentLog; -    Header.Offset = MaxOffset; -    if (Header.Offset != MaxOffset) { -      dieWithMessage("ERROR: the maximum possible offset doesn't fit in the " -                     "header\n"); -    } -    // Verify that we can fit the maximum size or amount of unused bytes in the -    // header. Given that the Secondary fits the allocation to a page, the worst -    // case scenario happens in the Primary. It will depend on the second to -    // last and last class sizes, as well as the dynamic base for the Primary. -    // The following is an over-approximation that works for our needs. -    const uptr MaxSizeOrUnusedBytes = SizeClassMap::kMaxSize - 1; -    Header.SizeOrUnusedBytes = MaxSizeOrUnusedBytes; -    if (Header.SizeOrUnusedBytes != MaxSizeOrUnusedBytes) { -      dieWithMessage("ERROR: the maximum possible unused bytes doesn't fit in " -                     "the header\n"); -    } +  explicit Allocator(LinkerInitialized) +    : Quarantine(LINKER_INITIALIZED) {} -    const uptr LargestClassId = SizeClassMap::kLargestClassID; -    Header.ClassId = LargestClassId; -    if (Header.ClassId != LargestClassId) { -      dieWithMessage("ERROR: the largest class ID doesn't fit in the header\n"); -    } -  } +  NOINLINE void performSanityChecks();    void init() {      SanitizerToolName = "Scudo"; +    PrimaryAllocatorName = "ScudoPrimary"; +    SecondaryAllocatorName = "ScudoSecondary"; +      initFlags();      performSanityChecks(); @@ -287,10 +258,10 @@ struct ScudoAllocator {        atomic_store_relaxed(&HashAlgorithm, CRC32Hardware);      SetAllocatorMayReturnNull(common_flags()->allocator_may_return_null); -    BackendAllocator.init(common_flags()->allocator_release_to_os_interval_ms); +    Backend.init(common_flags()->allocator_release_to_os_interval_ms);      HardRssLimitMb = common_flags()->hard_rss_limit_mb;      SoftRssLimitMb = common_flags()->soft_rss_limit_mb; -    AllocatorQuarantine.Init( +    Quarantine.Init(          static_cast<uptr>(getFlags()->QuarantineSizeKb) << 10,          static_cast<uptr>(getFlags()->ThreadLocalQuarantineSizeKb) << 10);      QuarantineChunksUpToSize = getFlags()->QuarantineChunksUpToSize; @@ -319,62 +290,36 @@ struct ScudoAllocator {      return Chunk::isValid(Ptr);    } -  // Opportunistic RSS limit check. This will update the RSS limit status, if -  // it can, every 100ms, otherwise it will just return the current one. -  bool isRssLimitExceeded() { -    u64 LastCheck = atomic_load_relaxed(&RssLastCheckedAtNS); -    const u64 CurrentCheck = MonotonicNanoTime(); -    if (LIKELY(CurrentCheck < LastCheck + (100ULL * 1000000ULL))) -      return atomic_load_relaxed(&RssLimitExceeded); -    if (!atomic_compare_exchange_weak(&RssLastCheckedAtNS, &LastCheck, -                                      CurrentCheck, memory_order_relaxed)) -      return atomic_load_relaxed(&RssLimitExceeded); -    // TODO(kostyak): We currently use sanitizer_common's GetRSS which reads the -    //                RSS from /proc/self/statm by default. We might want to -    //                call getrusage directly, even if it's less accurate. -    const uptr CurrentRssMb = GetRSS() >> 20; -    if (HardRssLimitMb && HardRssLimitMb < CurrentRssMb) { -      Report("%s: hard RSS limit exhausted (%zdMb vs %zdMb)\n", -             SanitizerToolName, HardRssLimitMb, CurrentRssMb); -      DumpProcessMap(); -      Die(); -    } -    if (SoftRssLimitMb) { -      if (atomic_load_relaxed(&RssLimitExceeded)) { -        if (CurrentRssMb <= SoftRssLimitMb) -          atomic_store_relaxed(&RssLimitExceeded, false); -      } else { -        if (CurrentRssMb > SoftRssLimitMb) { -          atomic_store_relaxed(&RssLimitExceeded, true); -          Report("%s: soft RSS limit exhausted (%zdMb vs %zdMb)\n", -                 SanitizerToolName, SoftRssLimitMb, CurrentRssMb); -        } -      } -    } -    return atomic_load_relaxed(&RssLimitExceeded); -  } +  NOINLINE bool isRssLimitExceeded();    // Allocates a chunk.    void *allocate(uptr Size, uptr Alignment, AllocType Type,                   bool ForceZeroContents = false) {      initThreadMaybe(); -    if (UNLIKELY(Alignment > MaxAlignment)) -      return FailureHandler::OnBadRequest(); +    if (UNLIKELY(Alignment > MaxAlignment)) { +      if (AllocatorMayReturnNull()) +        return nullptr; +      reportAllocationAlignmentTooBig(Alignment, MaxAlignment); +    }      if (UNLIKELY(Alignment < MinAlignment))        Alignment = MinAlignment; -    if (UNLIKELY(Size >= MaxAllowedMallocSize)) -      return FailureHandler::OnBadRequest(); -    if (UNLIKELY(Size == 0)) -      Size = 1; -    uptr NeededSize = RoundUpTo(Size, MinAlignment) + AlignedChunkHeaderSize; -    uptr AlignedSize = (Alignment > MinAlignment) ? -        NeededSize + (Alignment - AlignedChunkHeaderSize) : NeededSize; -    if (UNLIKELY(AlignedSize >= MaxAllowedMallocSize)) -      return FailureHandler::OnBadRequest(); +    const uptr NeededSize = RoundUpTo(Size ? Size : 1, MinAlignment) + +        Chunk::getHeaderSize(); +    const uptr AlignedSize = (Alignment > MinAlignment) ? +        NeededSize + (Alignment - Chunk::getHeaderSize()) : NeededSize; +    if (UNLIKELY(Size >= MaxAllowedMallocSize) || +        UNLIKELY(AlignedSize >= MaxAllowedMallocSize)) { +      if (AllocatorMayReturnNull()) +        return nullptr; +      reportAllocationSizeTooBig(Size, AlignedSize, MaxAllowedMallocSize); +    } -    if (CheckRssLimit && UNLIKELY(isRssLimitExceeded())) -      return FailureHandler::OnOOM(); +    if (CheckRssLimit && UNLIKELY(isRssLimitExceeded())) { +      if (AllocatorMayReturnNull()) +        return nullptr; +      reportRssLimitExceeded(); +    }      // Primary and Secondary backed allocations have a different treatment. We      // deal with alignment requirements of Primary serviced allocations here, @@ -382,27 +327,32 @@ struct ScudoAllocator {      void *BackendPtr;      uptr BackendSize;      u8 ClassId; -    if (PrimaryAllocator::CanAllocate(AlignedSize, MinAlignment)) { +    if (PrimaryT::CanAllocate(AlignedSize, MinAlignment)) {        BackendSize = AlignedSize;        ClassId = SizeClassMap::ClassID(BackendSize); -      ScudoTSD *TSD = getTSDAndLock(); -      BackendPtr = BackendAllocator.allocatePrimary(&TSD->Cache, ClassId); -      TSD->unlock(); +      bool UnlockRequired; +      ScudoTSD *TSD = getTSDAndLock(&UnlockRequired); +      BackendPtr = Backend.allocatePrimary(&TSD->Cache, ClassId); +      if (UnlockRequired) +        TSD->unlock();      } else {        BackendSize = NeededSize;        ClassId = 0; -      BackendPtr = BackendAllocator.allocateSecondary(BackendSize, Alignment); +      BackendPtr = Backend.allocateSecondary(BackendSize, Alignment); +    } +    if (UNLIKELY(!BackendPtr)) { +      SetAllocatorOutOfMemory(); +      if (AllocatorMayReturnNull()) +        return nullptr; +      reportOutOfMemory(Size);      } -    if (UNLIKELY(!BackendPtr)) -      return FailureHandler::OnOOM();      // If requested, we will zero out the entire contents of the returned chunk.      if ((ForceZeroContents || ZeroContents) && ClassId) -      memset(BackendPtr, 0, -             BackendAllocator.getActuallyAllocatedSize(BackendPtr, ClassId)); +      memset(BackendPtr, 0, PrimaryT::ClassIdToSize(ClassId));      UnpackedHeader Header = {}; -    uptr UserPtr = reinterpret_cast<uptr>(BackendPtr) + AlignedChunkHeaderSize; +    uptr UserPtr = reinterpret_cast<uptr>(BackendPtr) + Chunk::getHeaderSize();      if (UNLIKELY(!IsAligned(UserPtr, Alignment))) {        // Since the Secondary takes care of alignment, a non-aligned pointer        // means it is from the Primary. It is also the only case where the offset @@ -412,7 +362,7 @@ struct ScudoAllocator {        Header.Offset = (AlignedUserPtr - UserPtr) >> MinAlignmentLog;        UserPtr = AlignedUserPtr;      } -    CHECK_LE(UserPtr + Size, reinterpret_cast<uptr>(BackendPtr) + BackendSize); +    DCHECK_LE(UserPtr + Size, reinterpret_cast<uptr>(BackendPtr) + BackendSize);      Header.State = ChunkAllocated;      Header.AllocType = Type;      if (ClassId) { @@ -429,7 +379,8 @@ struct ScudoAllocator {      }      void *Ptr = reinterpret_cast<void *>(UserPtr);      Chunk::storeHeader(Ptr, &Header); -    // if (&__sanitizer_malloc_hook) __sanitizer_malloc_hook(Ptr, Size); +    if (SCUDO_CAN_USE_HOOKS && &__sanitizer_malloc_hook) +      __sanitizer_malloc_hook(Ptr, Size);      return Ptr;    } @@ -438,18 +389,20 @@ struct ScudoAllocator {    // quarantine chunk size threshold.    void quarantineOrDeallocateChunk(void *Ptr, UnpackedHeader *Header,                                     uptr Size) { -    const bool BypassQuarantine = (AllocatorQuarantine.GetCacheSize() == 0) || +    const bool BypassQuarantine = (Quarantine.GetCacheSize() == 0) ||          (Size > QuarantineChunksUpToSize);      if (BypassQuarantine) {        Chunk::eraseHeader(Ptr);        void *BackendPtr = Chunk::getBackendPtr(Ptr, Header);        if (Header->ClassId) { -        ScudoTSD *TSD = getTSDAndLock(); -        getBackendAllocator().deallocatePrimary(&TSD->Cache, BackendPtr, -                                                Header->ClassId); -        TSD->unlock(); +        bool UnlockRequired; +        ScudoTSD *TSD = getTSDAndLock(&UnlockRequired); +        getBackend().deallocatePrimary(&TSD->Cache, BackendPtr, +                                       Header->ClassId); +        if (UnlockRequired) +          TSD->unlock();        } else { -        getBackendAllocator().deallocateSecondary(BackendPtr); +        getBackend().deallocateSecondary(BackendPtr);        }      } else {        // If a small memory amount was allocated with a larger alignment, we want @@ -457,21 +410,23 @@ struct ScudoAllocator {        // with tiny chunks, taking a lot of VA memory. This is an approximation        // of the usable size, that allows us to not call        // GetActuallyAllocatedSize. -      uptr EstimatedSize = Size + (Header->Offset << MinAlignmentLog); +      const uptr EstimatedSize = Size + (Header->Offset << MinAlignmentLog);        UnpackedHeader NewHeader = *Header;        NewHeader.State = ChunkQuarantine;        Chunk::compareExchangeHeader(Ptr, &NewHeader, Header); -      ScudoTSD *TSD = getTSDAndLock(); -      AllocatorQuarantine.Put(getQuarantineCache(TSD), -                              QuarantineCallback(&TSD->Cache), Ptr, -                              EstimatedSize); -      TSD->unlock(); +      bool UnlockRequired; +      ScudoTSD *TSD = getTSDAndLock(&UnlockRequired); +      Quarantine.Put(getQuarantineCache(TSD), QuarantineCallback(&TSD->Cache), +                     Ptr, EstimatedSize); +      if (UnlockRequired) +        TSD->unlock();      }    }    // Deallocates a Chunk, which means either adding it to the quarantine or    // directly returning it to the backend if criteria are met. -  void deallocate(void *Ptr, uptr DeleteSize, AllocType Type) { +  void deallocate(void *Ptr, uptr DeleteSize, uptr DeleteAlignment, +                  AllocType Type) {      // For a deallocation, we only ensure minimal initialization, meaning thread      // local data will be left uninitialized for now (when using ELF TLS). The      // fallback cache will be used instead. This is a workaround for a situation @@ -479,37 +434,32 @@ struct ScudoAllocator {      // the TLS destructors, ending up in initialized thread specific data never      // being destroyed properly. Any other heap operation will do a full init.      initThreadMaybe(/*MinimalInit=*/true); -    // if (&__sanitizer_free_hook) __sanitizer_free_hook(Ptr); +    if (SCUDO_CAN_USE_HOOKS && &__sanitizer_free_hook) +      __sanitizer_free_hook(Ptr);      if (UNLIKELY(!Ptr))        return; -    if (UNLIKELY(!Chunk::isAligned(Ptr))) { -      dieWithMessage("ERROR: attempted to deallocate a chunk not properly " -                     "aligned at address %p\n", Ptr); -    } +    if (UNLIKELY(!Chunk::isAligned(Ptr))) +      dieWithMessage("misaligned pointer when deallocating address %p\n", Ptr);      UnpackedHeader Header;      Chunk::loadHeader(Ptr, &Header); -    if (UNLIKELY(Header.State != ChunkAllocated)) { -      dieWithMessage("ERROR: invalid chunk state when deallocating address " -                     "%p\n", Ptr); -    } +    if (UNLIKELY(Header.State != ChunkAllocated)) +      dieWithMessage("invalid chunk state when deallocating address %p\n", Ptr);      if (DeallocationTypeMismatch) {        // The deallocation type has to match the allocation one.        if (Header.AllocType != Type) {          // With the exception of memalign'd Chunks, that can be still be free'd. -        if (Header.AllocType != FromMemalign || Type != FromMalloc) { -          dieWithMessage("ERROR: allocation type mismatch when deallocating " -                         "address %p\n", Ptr); -        } +        if (Header.AllocType != FromMemalign || Type != FromMalloc) +          dieWithMessage("allocation type mismatch when deallocating address " +                         "%p\n", Ptr);        }      } -    uptr Size = Header.ClassId ? Header.SizeOrUnusedBytes : -        Chunk::getUsableSize(Ptr, &Header) - Header.SizeOrUnusedBytes; +    const uptr Size = Chunk::getSize(Ptr, &Header);      if (DeleteSizeMismatch) { -      if (DeleteSize && DeleteSize != Size) { -        dieWithMessage("ERROR: invalid sized delete on chunk at address %p\n", +      if (DeleteSize && DeleteSize != Size) +        dieWithMessage("invalid sized delete when deallocating address %p\n",                         Ptr); -      }      } +    (void)DeleteAlignment;  // TODO(kostyak): verify that the alignment matches.      quarantineOrDeallocateChunk(Ptr, &Header, Size);    } @@ -517,21 +467,18 @@ struct ScudoAllocator {    // size still fits in the chunk.    void *reallocate(void *OldPtr, uptr NewSize) {      initThreadMaybe(); -    if (UNLIKELY(!Chunk::isAligned(OldPtr))) { -      dieWithMessage("ERROR: attempted to reallocate a chunk not properly " -                     "aligned at address %p\n", OldPtr); -    } +    if (UNLIKELY(!Chunk::isAligned(OldPtr))) +      dieWithMessage("misaligned address when reallocating address %p\n", +                     OldPtr);      UnpackedHeader OldHeader;      Chunk::loadHeader(OldPtr, &OldHeader); -    if (UNLIKELY(OldHeader.State != ChunkAllocated)) { -      dieWithMessage("ERROR: invalid chunk state when reallocating address " -                     "%p\n", OldPtr); -    } +    if (UNLIKELY(OldHeader.State != ChunkAllocated)) +      dieWithMessage("invalid chunk state when reallocating address %p\n", +                     OldPtr);      if (DeallocationTypeMismatch) { -      if (UNLIKELY(OldHeader.AllocType != FromMalloc)) { -        dieWithMessage("ERROR: allocation type mismatch when reallocating " -                       "address %p\n", OldPtr); -      } +      if (UNLIKELY(OldHeader.AllocType != FromMalloc)) +        dieWithMessage("allocation type mismatch when reallocating address " +                       "%p\n", OldPtr);      }      const uptr UsableSize = Chunk::getUsableSize(OldPtr, &OldHeader);      // The new size still fits in the current chunk, and the size difference @@ -548,7 +495,7 @@ struct ScudoAllocator {      // old one.      void *NewPtr = allocate(NewSize, MinAlignment, FromMalloc);      if (NewPtr) { -      uptr OldSize = OldHeader.ClassId ? OldHeader.SizeOrUnusedBytes : +      const uptr OldSize = OldHeader.ClassId ? OldHeader.SizeOrUnusedBytes :            UsableSize - OldHeader.SizeOrUnusedBytes;        memcpy(NewPtr, OldPtr, Min(NewSize, UsableSize));        quarantineOrDeallocateChunk(OldPtr, &OldHeader, OldSize); @@ -564,36 +511,36 @@ struct ScudoAllocator {      UnpackedHeader Header;      Chunk::loadHeader(Ptr, &Header);      // Getting the usable size of a chunk only makes sense if it's allocated. -    if (UNLIKELY(Header.State != ChunkAllocated)) { -      dieWithMessage("ERROR: invalid chunk state when sizing address %p\n", -                     Ptr); -    } +    if (UNLIKELY(Header.State != ChunkAllocated)) +      dieWithMessage("invalid chunk state when sizing address %p\n", Ptr);      return Chunk::getUsableSize(Ptr, &Header);    }    void *calloc(uptr NMemB, uptr Size) {      initThreadMaybe(); -    if (UNLIKELY(CheckForCallocOverflow(NMemB, Size))) -      return FailureHandler::OnBadRequest(); +    if (UNLIKELY(CheckForCallocOverflow(NMemB, Size))) { +      if (AllocatorMayReturnNull()) +        return nullptr; +      reportCallocOverflow(NMemB, Size); +    }      return allocate(NMemB * Size, MinAlignment, FromMalloc, true);    }    void commitBack(ScudoTSD *TSD) { -    AllocatorQuarantine.Drain(getQuarantineCache(TSD), -                              QuarantineCallback(&TSD->Cache)); -    BackendAllocator.destroyCache(&TSD->Cache); +    Quarantine.Drain(getQuarantineCache(TSD), QuarantineCallback(&TSD->Cache)); +    Backend.destroyCache(&TSD->Cache);    }    uptr getStats(AllocatorStat StatType) {      initThreadMaybe();      uptr stats[AllocatorStatCount]; -    BackendAllocator.getStats(stats); +    Backend.getStats(stats);      return stats[StatType];    } -  void *handleBadRequest() { +  bool canReturnNull() {      initThreadMaybe(); -    return FailureHandler::OnBadRequest(); +    return AllocatorMayReturnNull();    }    void setRssLimit(uptr LimitMb, bool HardLimit) { @@ -603,21 +550,90 @@ struct ScudoAllocator {        SoftRssLimitMb = LimitMb;      CheckRssLimit = HardRssLimitMb || SoftRssLimitMb;    } + +  void printStats() { +    initThreadMaybe(); +    Backend.printStats(); +  }  }; -static ScudoAllocator Instance(LINKER_INITIALIZED); +NOINLINE void Allocator::performSanityChecks() { +  // Verify that the header offset field can hold the maximum offset. In the +  // case of the Secondary allocator, it takes care of alignment and the +  // offset will always be 0. In the case of the Primary, the worst case +  // scenario happens in the last size class, when the backend allocation +  // would already be aligned on the requested alignment, which would happen +  // to be the maximum alignment that would fit in that size class. As a +  // result, the maximum offset will be at most the maximum alignment for the +  // last size class minus the header size, in multiples of MinAlignment. +  UnpackedHeader Header = {}; +  const uptr MaxPrimaryAlignment = +      1 << MostSignificantSetBitIndex(SizeClassMap::kMaxSize - MinAlignment); +  const uptr MaxOffset = +      (MaxPrimaryAlignment - Chunk::getHeaderSize()) >> MinAlignmentLog; +  Header.Offset = MaxOffset; +  if (Header.Offset != MaxOffset) +    dieWithMessage("maximum possible offset doesn't fit in header\n"); +  // Verify that we can fit the maximum size or amount of unused bytes in the +  // header. Given that the Secondary fits the allocation to a page, the worst +  // case scenario happens in the Primary. It will depend on the second to +  // last and last class sizes, as well as the dynamic base for the Primary. +  // The following is an over-approximation that works for our needs. +  const uptr MaxSizeOrUnusedBytes = SizeClassMap::kMaxSize - 1; +  Header.SizeOrUnusedBytes = MaxSizeOrUnusedBytes; +  if (Header.SizeOrUnusedBytes != MaxSizeOrUnusedBytes) +    dieWithMessage("maximum possible unused bytes doesn't fit in header\n"); + +  const uptr LargestClassId = SizeClassMap::kLargestClassID; +  Header.ClassId = LargestClassId; +  if (Header.ClassId != LargestClassId) +    dieWithMessage("largest class ID doesn't fit in header\n"); +} -static ScudoBackendAllocator &getBackendAllocator() { -  return Instance.BackendAllocator; +// Opportunistic RSS limit check. This will update the RSS limit status, if +// it can, every 100ms, otherwise it will just return the current one. +NOINLINE bool Allocator::isRssLimitExceeded() { +  u64 LastCheck = atomic_load_relaxed(&RssLastCheckedAtNS); +  const u64 CurrentCheck = MonotonicNanoTime(); +  if (LIKELY(CurrentCheck < LastCheck + (100ULL * 1000000ULL))) +    return atomic_load_relaxed(&RssLimitExceeded); +  if (!atomic_compare_exchange_weak(&RssLastCheckedAtNS, &LastCheck, +                                    CurrentCheck, memory_order_relaxed)) +    return atomic_load_relaxed(&RssLimitExceeded); +  // TODO(kostyak): We currently use sanitizer_common's GetRSS which reads the +  //                RSS from /proc/self/statm by default. We might want to +  //                call getrusage directly, even if it's less accurate. +  const uptr CurrentRssMb = GetRSS() >> 20; +  if (HardRssLimitMb && UNLIKELY(HardRssLimitMb < CurrentRssMb)) +    dieWithMessage("hard RSS limit exhausted (%zdMb vs %zdMb)\n", +                   HardRssLimitMb, CurrentRssMb); +  if (SoftRssLimitMb) { +    if (atomic_load_relaxed(&RssLimitExceeded)) { +      if (CurrentRssMb <= SoftRssLimitMb) +        atomic_store_relaxed(&RssLimitExceeded, false); +    } else { +      if (CurrentRssMb > SoftRssLimitMb) { +        atomic_store_relaxed(&RssLimitExceeded, true); +        Printf("Scudo INFO: soft RSS limit exhausted (%zdMb vs %zdMb)\n", +               SoftRssLimitMb, CurrentRssMb); +      } +    } +  } +  return atomic_load_relaxed(&RssLimitExceeded); +} + +static Allocator Instance(LINKER_INITIALIZED); + +static BackendT &getBackend() { +  return Instance.Backend;  }  void initScudo() {    Instance.init();  } -void ScudoTSD::init(bool Shared) { -  UnlockRequired = Shared; -  getBackendAllocator().initCache(&Cache); +void ScudoTSD::init() { +  getBackend().initCache(&Cache);    memset(QuarantineCachePlaceHolder, 0, sizeof(QuarantineCachePlaceHolder));  } @@ -625,23 +641,25 @@ void ScudoTSD::commitBack() {    Instance.commitBack(this);  } -void *scudoMalloc(uptr Size, AllocType Type) { -  return SetErrnoOnNull(Instance.allocate(Size, MinAlignment, Type)); -} - -void scudoFree(void *Ptr, AllocType Type) { -  Instance.deallocate(Ptr, 0, Type); +void *scudoAllocate(uptr Size, uptr Alignment, AllocType Type) { +  if (Alignment && UNLIKELY(!IsPowerOfTwo(Alignment))) { +    errno = EINVAL; +    if (Instance.canReturnNull()) +      return nullptr; +    reportAllocationAlignmentNotPowerOfTwo(Alignment); +  } +  return SetErrnoOnNull(Instance.allocate(Size, Alignment, Type));  } -void scudoSizedFree(void *Ptr, uptr Size, AllocType Type) { -  Instance.deallocate(Ptr, Size, Type); +void scudoDeallocate(void *Ptr, uptr Size, uptr Alignment, AllocType Type) { +  Instance.deallocate(Ptr, Size, Alignment, Type);  }  void *scudoRealloc(void *Ptr, uptr Size) {    if (!Ptr)      return SetErrnoOnNull(Instance.allocate(Size, MinAlignment, FromMalloc));    if (Size == 0) { -    Instance.deallocate(Ptr, 0, FromMalloc); +    Instance.deallocate(Ptr, 0, 0, FromMalloc);      return nullptr;    }    return SetErrnoOnNull(Instance.reallocate(Ptr, Size)); @@ -660,24 +678,19 @@ void *scudoPvalloc(uptr Size) {    uptr PageSize = GetPageSizeCached();    if (UNLIKELY(CheckForPvallocOverflow(Size, PageSize))) {      errno = ENOMEM; -    return Instance.handleBadRequest(); +    if (Instance.canReturnNull()) +      return nullptr; +    reportPvallocOverflow(Size);    }    // pvalloc(0) should allocate one page.    Size = Size ? RoundUpTo(Size, PageSize) : PageSize;    return SetErrnoOnNull(Instance.allocate(Size, PageSize, FromMemalign));  } -void *scudoMemalign(uptr Alignment, uptr Size) { -  if (UNLIKELY(!IsPowerOfTwo(Alignment))) { -    errno = EINVAL; -    return Instance.handleBadRequest(); -  } -  return SetErrnoOnNull(Instance.allocate(Size, Alignment, FromMemalign)); -} -  int scudoPosixMemalign(void **MemPtr, uptr Alignment, uptr Size) {    if (UNLIKELY(!CheckPosixMemalignAlignment(Alignment))) { -    Instance.handleBadRequest(); +    if (!Instance.canReturnNull()) +      reportInvalidPosixMemalignAlignment(Alignment);      return EINVAL;    }    void *Ptr = Instance.allocate(Size, Alignment, FromMemalign); @@ -690,7 +703,9 @@ int scudoPosixMemalign(void **MemPtr, uptr Alignment, uptr Size) {  void *scudoAlignedAlloc(uptr Alignment, uptr Size) {    if (UNLIKELY(!CheckAlignedAllocAlignmentAndSize(Alignment, Size))) {      errno = EINVAL; -    return Instance.handleBadRequest(); +    if (Instance.canReturnNull()) +      return nullptr; +    reportInvalidAlignedAllocAlignment(Size, Alignment);    }    return SetErrnoOnNull(Instance.allocate(Size, Alignment, FromMalloc));  } @@ -721,8 +736,8 @@ uptr __sanitizer_get_unmapped_bytes() {    return 1;  } -uptr __sanitizer_get_estimated_allocated_size(uptr size) { -  return size; +uptr __sanitizer_get_estimated_allocated_size(uptr Size) { +  return Size;  }  int __sanitizer_get_ownership(const void *Ptr) { @@ -733,12 +748,26 @@ uptr __sanitizer_get_allocated_size(const void *Ptr) {    return Instance.getUsableSize(Ptr);  } +#if !SANITIZER_SUPPORTS_WEAK_HOOKS +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_malloc_hook, +                             void *Ptr, uptr Size) { +  (void)Ptr; +  (void)Size; +} + +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_free_hook, void *Ptr) { +  (void)Ptr; +} +#endif +  // Interface functions -extern "C" { -void __scudo_set_rss_limit(unsigned long LimitMb, int HardLimit) {  // NOLINT +void __scudo_set_rss_limit(uptr LimitMb, s32 HardLimit) {    if (!SCUDO_CAN_USE_PUBLIC_INTERFACE)      return;    Instance.setRssLimit(LimitMb, !!HardLimit);  } -}  // extern "C" + +void __scudo_print_stats() { +  Instance.printStats(); +} diff --git a/lib/scudo/scudo_allocator.h b/lib/scudo/scudo_allocator.h index a561247def9c8..0002b4a44b781 100644 --- a/lib/scudo/scudo_allocator.h +++ b/lib/scudo/scudo_allocator.h @@ -59,9 +59,17 @@ const uptr MaxAlignmentLog = 24;  // 16 MB  const uptr MinAlignment = 1 << MinAlignmentLog;  const uptr MaxAlignment = 1 << MaxAlignmentLog; -const uptr ChunkHeaderSize = sizeof(PackedHeader); -const uptr AlignedChunkHeaderSize = -    (ChunkHeaderSize + MinAlignment - 1) & ~(MinAlignment - 1); +// constexpr version of __sanitizer::RoundUp without the extraneous CHECK. +// This way we can use it in constexpr variables and functions declarations. +constexpr uptr RoundUpTo(uptr Size, uptr Boundary) { +  return (Size + Boundary - 1) & ~(Boundary - 1); +} + +namespace Chunk { +  constexpr uptr getHeaderSize() { +    return RoundUpTo(sizeof(PackedHeader), MinAlignment); +  } +}  #if SANITIZER_CAN_USE_ALLOCATOR64  const uptr AllocatorSpace = ~0ULL; @@ -74,7 +82,7 @@ struct AP64 {    static const uptr kFlags =        SizeClassAllocator64FlagMasks::kRandomShuffleChunks;  }; -typedef SizeClassAllocator64<AP64> PrimaryAllocator; +typedef SizeClassAllocator64<AP64> PrimaryT;  #else  static const uptr NumRegions = SANITIZER_MMAP_RANGE_SIZE >> RegionSizeLog;  # if SANITIZER_WORDSIZE == 32 @@ -94,30 +102,22 @@ struct AP32 {        SizeClassAllocator32FlagMasks::kRandomShuffleChunks |        SizeClassAllocator32FlagMasks::kUseSeparateSizeClassForBatch;  }; -typedef SizeClassAllocator32<AP32> PrimaryAllocator; +typedef SizeClassAllocator32<AP32> PrimaryT;  #endif  // SANITIZER_CAN_USE_ALLOCATOR64 -// __sanitizer::RoundUp has a CHECK that is extraneous for us. Use our own. -INLINE uptr RoundUpTo(uptr Size, uptr Boundary) { -  return (Size + Boundary - 1) & ~(Boundary - 1); -} -  #include "scudo_allocator_secondary.h"  #include "scudo_allocator_combined.h" -typedef SizeClassAllocatorLocalCache<PrimaryAllocator> AllocatorCache; -typedef ScudoLargeMmapAllocator SecondaryAllocator; -typedef ScudoCombinedAllocator<PrimaryAllocator, AllocatorCache, -    SecondaryAllocator> ScudoBackendAllocator; +typedef SizeClassAllocatorLocalCache<PrimaryT> AllocatorCacheT; +typedef LargeMmapAllocator SecondaryT; +typedef CombinedAllocator<PrimaryT, AllocatorCacheT, SecondaryT> BackendT;  void initScudo(); -void *scudoMalloc(uptr Size, AllocType Type); -void scudoFree(void *Ptr, AllocType Type); -void scudoSizedFree(void *Ptr, uptr Size, AllocType Type); +void *scudoAllocate(uptr Size, uptr Alignment, AllocType Type); +void scudoDeallocate(void *Ptr, uptr Size, uptr Alignment, AllocType Type);  void *scudoRealloc(void *Ptr, uptr Size);  void *scudoCalloc(uptr NMemB, uptr Size); -void *scudoMemalign(uptr Alignment, uptr Size);  void *scudoValloc(uptr Size);  void *scudoPvalloc(uptr Size);  int scudoPosixMemalign(void **MemPtr, uptr Alignment, uptr Size); diff --git a/lib/scudo/scudo_allocator_combined.h b/lib/scudo/scudo_allocator_combined.h index 25e273114c238..6e40660ba9ab7 100644 --- a/lib/scudo/scudo_allocator_combined.h +++ b/lib/scudo/scudo_allocator_combined.h @@ -16,12 +16,12 @@  #define SCUDO_ALLOCATOR_COMBINED_H_  #ifndef SCUDO_ALLOCATOR_H_ -#error "This file must be included inside scudo_allocator.h." +# error "This file must be included inside scudo_allocator.h."  #endif  template <class PrimaryAllocator, class AllocatorCache,      class SecondaryAllocator> -class ScudoCombinedAllocator { +class CombinedAllocator {   public:    void init(s32 ReleaseToOSIntervalMs) {      Primary.Init(ReleaseToOSIntervalMs); @@ -49,12 +49,6 @@ class ScudoCombinedAllocator {      Secondary.Deallocate(&Stats, Ptr);    } -  uptr getActuallyAllocatedSize(void *Ptr, uptr ClassId) { -    if (ClassId) -      return PrimaryAllocator::ClassIdToSize(ClassId); -    return Secondary.GetActuallyAllocatedSize(Ptr); -  } -    void initCache(AllocatorCache *Cache) {      Cache->Init(&Stats);    } @@ -67,6 +61,11 @@ class ScudoCombinedAllocator {      Stats.Get(StatType);    } +  void printStats() { +    Primary.PrintStats(); +    Secondary.PrintStats(); +  } +   private:    PrimaryAllocator Primary;    SecondaryAllocator Secondary; diff --git a/lib/scudo/scudo_allocator_secondary.h b/lib/scudo/scudo_allocator_secondary.h index f2002ed986c31..ff6246e25883b 100644 --- a/lib/scudo/scudo_allocator_secondary.h +++ b/lib/scudo/scudo_allocator_secondary.h @@ -21,120 +21,173 @@  # error "This file must be included inside scudo_allocator.h."  #endif -class ScudoLargeMmapAllocator { +// Secondary backed allocations are standalone chunks that contain extra +// information stored in a LargeChunk::Header prior to the frontend's header. +// +// The secondary takes care of alignment requirements (so that it can release +// unnecessary pages in the rare event of larger alignments), and as such must +// know about the frontend's header size. +// +// Since Windows doesn't support partial releasing of a reserved memory region, +// we have to keep track of both the reserved and the committed memory. +// +// The resulting chunk resembles the following: +// +//   +--------------------+ +//   | Guard page(s)      | +//   +--------------------+ +//   | Unused space*      | +//   +--------------------+ +//   | LargeChunk::Header | +//   +--------------------+ +//   | {Unp,P}ackedHeader | +//   +--------------------+ +//   | Data (aligned)     | +//   +--------------------+ +//   | Unused space**     | +//   +--------------------+ +//   | Guard page(s)      | +//   +--------------------+ + +namespace LargeChunk { +  struct Header { +    ReservedAddressRange StoredRange; +    uptr CommittedSize; +    uptr Size; +  }; +  constexpr uptr getHeaderSize() { +    return RoundUpTo(sizeof(Header), MinAlignment); +  } +  static Header *getHeader(uptr Ptr) { +    return reinterpret_cast<Header *>(Ptr - getHeaderSize()); +  } +  static Header *getHeader(const void *Ptr) { +    return getHeader(reinterpret_cast<uptr>(Ptr)); +  } +}  // namespace LargeChunk + +class LargeMmapAllocator {   public:    void Init() { -    PageSizeCached = GetPageSizeCached(); +    internal_memset(this, 0, sizeof(*this));    }    void *Allocate(AllocatorStats *Stats, uptr Size, uptr Alignment) { -    const uptr UserSize = Size - AlignedChunkHeaderSize; +    const uptr UserSize = Size - Chunk::getHeaderSize();      // The Scudo frontend prevents us from allocating more than      // MaxAllowedMallocSize, so integer overflow checks would be superfluous. -    uptr MapSize = Size + AlignedReservedAddressRangeSize; -    if (Alignment > MinAlignment) -      MapSize += Alignment; -    const uptr PageSize = PageSizeCached; -    MapSize = RoundUpTo(MapSize, PageSize); +    uptr ReservedSize = Size + LargeChunk::getHeaderSize(); +    if (UNLIKELY(Alignment > MinAlignment)) +      ReservedSize += Alignment; +    const uptr PageSize = GetPageSizeCached(); +    ReservedSize = RoundUpTo(ReservedSize, PageSize);      // Account for 2 guard pages, one before and one after the chunk. -    MapSize += 2 * PageSize; +    ReservedSize += 2 * PageSize;      ReservedAddressRange AddressRange; -    uptr MapBeg = AddressRange.Init(MapSize); -    if (MapBeg == ~static_cast<uptr>(0)) -      return ReturnNullOrDieOnFailure::OnOOM(); +    uptr ReservedBeg = AddressRange.Init(ReservedSize, SecondaryAllocatorName); +    if (UNLIKELY(ReservedBeg == ~static_cast<uptr>(0))) +      return nullptr;      // A page-aligned pointer is assumed after that, so check it now. -    CHECK(IsAligned(MapBeg, PageSize)); -    uptr MapEnd = MapBeg + MapSize; +    DCHECK(IsAligned(ReservedBeg, PageSize)); +    uptr ReservedEnd = ReservedBeg + ReservedSize;      // The beginning of the user area for that allocation comes after the      // initial guard page, and both headers. This is the pointer that has to      // abide by alignment requirements. -    uptr UserBeg = MapBeg + PageSize + HeadersSize; +    uptr CommittedBeg = ReservedBeg + PageSize; +    uptr UserBeg = CommittedBeg + HeadersSize;      uptr UserEnd = UserBeg + UserSize; +    uptr CommittedEnd = RoundUpTo(UserEnd, PageSize);      // In the rare event of larger alignments, we will attempt to fit the mmap      // area better and unmap extraneous memory. This will also ensure that the      // offset and unused bytes field of the header stay small. -    if (Alignment > MinAlignment) { +    if (UNLIKELY(Alignment > MinAlignment)) {        if (!IsAligned(UserBeg, Alignment)) {          UserBeg = RoundUpTo(UserBeg, Alignment); -        CHECK_GE(UserBeg, MapBeg); -        uptr NewMapBeg = RoundDownTo(UserBeg - HeadersSize, PageSize) - -            PageSize; -        CHECK_GE(NewMapBeg, MapBeg); -        if (NewMapBeg != MapBeg) { -          AddressRange.Unmap(MapBeg, NewMapBeg - MapBeg); -          MapBeg = NewMapBeg; +        CommittedBeg = RoundDownTo(UserBeg - HeadersSize, PageSize); +        const uptr NewReservedBeg = CommittedBeg - PageSize; +        DCHECK_GE(NewReservedBeg, ReservedBeg); +        if (!SANITIZER_WINDOWS && NewReservedBeg != ReservedBeg) { +          AddressRange.Unmap(ReservedBeg, NewReservedBeg - ReservedBeg); +          ReservedBeg = NewReservedBeg;          }          UserEnd = UserBeg + UserSize; +        CommittedEnd = RoundUpTo(UserEnd, PageSize);        } -      uptr NewMapEnd = RoundUpTo(UserEnd, PageSize) + PageSize; -      if (NewMapEnd != MapEnd) { -        AddressRange.Unmap(NewMapEnd, MapEnd - NewMapEnd); -        MapEnd = NewMapEnd; +      const uptr NewReservedEnd = CommittedEnd + PageSize; +      DCHECK_LE(NewReservedEnd, ReservedEnd); +      if (!SANITIZER_WINDOWS && NewReservedEnd != ReservedEnd) { +        AddressRange.Unmap(NewReservedEnd, ReservedEnd - NewReservedEnd); +        ReservedEnd = NewReservedEnd;        } -      MapSize = MapEnd - MapBeg;      } -    CHECK_LE(UserEnd, MapEnd - PageSize); -    // Actually mmap the memory, preserving the guard pages on either side -    CHECK_EQ(MapBeg + PageSize, -             AddressRange.Map(MapBeg + PageSize, MapSize - 2 * PageSize)); -    const uptr Ptr = UserBeg - AlignedChunkHeaderSize; -    ReservedAddressRange *StoredRange = getReservedAddressRange(Ptr); -    *StoredRange = AddressRange; +    DCHECK_LE(UserEnd, CommittedEnd); +    const uptr CommittedSize = CommittedEnd - CommittedBeg; +    // Actually mmap the memory, preserving the guard pages on either sides. +    CHECK_EQ(CommittedBeg, AddressRange.Map(CommittedBeg, CommittedSize)); +    const uptr Ptr = UserBeg - Chunk::getHeaderSize(); +    LargeChunk::Header *H = LargeChunk::getHeader(Ptr); +    H->StoredRange = AddressRange; +    H->Size = CommittedEnd - Ptr; +    H->CommittedSize = CommittedSize;      // The primary adds the whole class size to the stats when allocating a      // chunk, so we will do something similar here. But we will not account for      // the guard pages.      {        SpinMutexLock l(&StatsMutex); -      Stats->Add(AllocatorStatAllocated, MapSize - 2 * PageSize); -      Stats->Add(AllocatorStatMapped, MapSize - 2 * PageSize); +      Stats->Add(AllocatorStatAllocated, CommittedSize); +      Stats->Add(AllocatorStatMapped, CommittedSize); +      AllocatedBytes += CommittedSize; +      if (LargestSize < CommittedSize) +        LargestSize = CommittedSize; +      NumberOfAllocs++;      }      return reinterpret_cast<void *>(Ptr);    }    void Deallocate(AllocatorStats *Stats, void *Ptr) { +    LargeChunk::Header *H = LargeChunk::getHeader(Ptr);      // Since we're unmapping the entirety of where the ReservedAddressRange      // actually is, copy onto the stack. -    const uptr PageSize = PageSizeCached; -    ReservedAddressRange AddressRange = *getReservedAddressRange(Ptr); +    ReservedAddressRange AddressRange = H->StoredRange; +    const uptr Size = H->CommittedSize;      {        SpinMutexLock l(&StatsMutex); -      Stats->Sub(AllocatorStatAllocated, AddressRange.size() - 2 * PageSize); -      Stats->Sub(AllocatorStatMapped, AddressRange.size() - 2 * PageSize); +      Stats->Sub(AllocatorStatAllocated, Size); +      Stats->Sub(AllocatorStatMapped, Size); +      FreedBytes += Size; +      NumberOfFrees++;      }      AddressRange.Unmap(reinterpret_cast<uptr>(AddressRange.base()),                         AddressRange.size());    } -  uptr GetActuallyAllocatedSize(void *Ptr) { -    ReservedAddressRange *StoredRange = getReservedAddressRange(Ptr); -    // Deduct PageSize as ReservedAddressRange size includes the trailing guard -    // page. -    uptr MapEnd = reinterpret_cast<uptr>(StoredRange->base()) + -        StoredRange->size() - PageSizeCached; -    return MapEnd - reinterpret_cast<uptr>(Ptr); +  static uptr GetActuallyAllocatedSize(void *Ptr) { +    return LargeChunk::getHeader(Ptr)->Size;    } - private: -  ReservedAddressRange *getReservedAddressRange(uptr Ptr) { -    return reinterpret_cast<ReservedAddressRange*>( -        Ptr - sizeof(ReservedAddressRange)); -  } -  ReservedAddressRange *getReservedAddressRange(const void *Ptr) { -    return getReservedAddressRange(reinterpret_cast<uptr>(Ptr)); +  void PrintStats() { +    Printf("Stats: LargeMmapAllocator: allocated %zd times (%zd K), " +           "freed %zd times (%zd K), remains %zd (%zd K) max %zd M\n", +           NumberOfAllocs, AllocatedBytes >> 10, NumberOfFrees, +           FreedBytes >> 10, NumberOfAllocs - NumberOfFrees, +           (AllocatedBytes - FreedBytes) >> 10, LargestSize >> 20);    } -  static constexpr uptr AlignedReservedAddressRangeSize = -      (sizeof(ReservedAddressRange) + MinAlignment - 1) & ~(MinAlignment - 1); + private:    static constexpr uptr HeadersSize = -      AlignedReservedAddressRangeSize + AlignedChunkHeaderSize; +      LargeChunk::getHeaderSize() + Chunk::getHeaderSize(); -  uptr PageSizeCached; -  SpinMutex StatsMutex; +  StaticSpinMutex StatsMutex; +  u32 NumberOfAllocs; +  u32 NumberOfFrees; +  uptr AllocatedBytes; +  uptr FreedBytes; +  uptr LargestSize;  };  #endif  // SCUDO_ALLOCATOR_SECONDARY_H_ diff --git a/lib/scudo/scudo_errors.cpp b/lib/scudo/scudo_errors.cpp new file mode 100644 index 0000000000000..d11e03cf91637 --- /dev/null +++ b/lib/scudo/scudo_errors.cpp @@ -0,0 +1,77 @@ +//===-- scudo_errors.cpp ----------------------------------------*- C++ -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// Verbose termination functions. +/// +//===----------------------------------------------------------------------===// + +#include "scudo_utils.h" + +#include "sanitizer_common/sanitizer_flags.h" + +namespace __scudo { + +void NORETURN reportCallocOverflow(uptr Count, uptr Size) { +  dieWithMessage("calloc parameters overflow: count * size (%zd * %zd) cannot " +      "be represented with type size_t\n", Count, Size); +} + +void NORETURN reportPvallocOverflow(uptr Size) { +  dieWithMessage("pvalloc parameters overflow: size 0x%zx rounded up to system " +      "page size 0x%zx cannot be represented in type size_t\n", Size, +      GetPageSizeCached()); +} + +void NORETURN reportAllocationAlignmentTooBig(uptr Alignment, +                                              uptr MaxAlignment) { +  dieWithMessage("invalid allocation alignment: %zd exceeds maximum supported " +      "allocation of %zd\n", Alignment, MaxAlignment); +} + +void NORETURN reportAllocationAlignmentNotPowerOfTwo(uptr Alignment) { +  dieWithMessage("invalid allocation alignment: %zd, alignment must be a power " +      "of two\n", Alignment); +} + +void NORETURN reportInvalidPosixMemalignAlignment(uptr Alignment) { +  dieWithMessage("invalid alignment requested in posix_memalign: %zd, alignment" +      " must be a power of two and a multiple of sizeof(void *) == %zd\n", +      Alignment, sizeof(void *));  // NOLINT +} + +void NORETURN reportInvalidAlignedAllocAlignment(uptr Size, uptr Alignment) { +#if SANITIZER_POSIX +  dieWithMessage("invalid alignment requested in aligned_alloc: %zd, alignment " +      "must be a power of two and the requested size 0x%zx must be a multiple " +      "of alignment\n", Alignment, Size); +#else +  dieWithMessage("invalid alignment requested in aligned_alloc: %zd, the " +      "requested size 0x%zx must be a multiple of alignment\n", Alignment, +      Size); +#endif +} + +void NORETURN reportAllocationSizeTooBig(uptr UserSize, uptr TotalSize, +                                         uptr MaxSize) { +  dieWithMessage("requested allocation size 0x%zx (0x%zx after adjustments) " +      "exceeds maximum supported size of 0x%zx\n", UserSize, TotalSize, +      MaxSize); +} + +void NORETURN reportRssLimitExceeded() { +  dieWithMessage("specified RSS limit exceeded, currently set to " +      "soft_rss_limit_mb=%zd\n", common_flags()->soft_rss_limit_mb); +} + +void NORETURN reportOutOfMemory(uptr RequestedSize) { +  dieWithMessage("allocator is out of memory trying to allocate 0x%zx bytes\n", +                 RequestedSize); +} + +}  // namespace __scudo diff --git a/lib/scudo/scudo_errors.h b/lib/scudo/scudo_errors.h new file mode 100644 index 0000000000000..8b1af996be048 --- /dev/null +++ b/lib/scudo/scudo_errors.h @@ -0,0 +1,35 @@ +//===-- scudo_errors.h ------------------------------------------*- C++ -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// Header for scudo_errors.cpp. +/// +//===----------------------------------------------------------------------===// + +#ifndef SCUDO_ERRORS_H_ +#define SCUDO_ERRORS_H_ + +#include "sanitizer_common/sanitizer_internal_defs.h" + +namespace __scudo { + +void NORETURN reportCallocOverflow(uptr Count, uptr Size); +void NORETURN reportPvallocOverflow(uptr Size); +void NORETURN reportAllocationAlignmentTooBig(uptr Alignment, +                                              uptr MaxAlignment); +void NORETURN reportAllocationAlignmentNotPowerOfTwo(uptr Alignment); +void NORETURN reportInvalidPosixMemalignAlignment(uptr Alignment); +void NORETURN reportInvalidAlignedAllocAlignment(uptr Size, uptr Alignment); +void NORETURN reportAllocationSizeTooBig(uptr UserSize, uptr TotalSize, +                                         uptr MaxSize); +void NORETURN reportRssLimitExceeded(); +void NORETURN reportOutOfMemory(uptr RequestedSize); + +}  // namespace __scudo + +#endif  // SCUDO_ERRORS_H_ diff --git a/lib/scudo/scudo_flags.cpp b/lib/scudo/scudo_flags.cpp index 2aff3ef1e8fae..c012471a83687 100644 --- a/lib/scudo/scudo_flags.cpp +++ b/lib/scudo/scudo_flags.cpp @@ -12,13 +12,12 @@  //===----------------------------------------------------------------------===//  #include "scudo_flags.h" +#include "scudo_interface_internal.h"  #include "scudo_utils.h"  #include "sanitizer_common/sanitizer_flags.h"  #include "sanitizer_common/sanitizer_flag_parser.h" -SANITIZER_INTERFACE_WEAK_DEF(const char*, __scudo_default_options, void); -  namespace __scudo {  static Flags ScudoFlags;  // Use via getFlags(). @@ -36,6 +35,14 @@ static void RegisterScudoFlags(FlagParser *parser, Flags *f) {  #undef SCUDO_FLAG  } +static const char *getCompileDefinitionScudoDefaultOptions() { +#ifdef SCUDO_DEFAULT_OPTIONS +  return SANITIZER_STRINGIFY(SCUDO_DEFAULT_OPTIONS); +#else +  return ""; +#endif +} +  static const char *getScudoDefaultOptions() {    return (&__scudo_default_options) ? __scudo_default_options() : "";  } @@ -55,6 +62,9 @@ void initFlags() {    RegisterScudoFlags(&ScudoParser, f);    RegisterCommonFlags(&ScudoParser); +  // Override from compile definition. +  ScudoParser.ParseString(getCompileDefinitionScudoDefaultOptions()); +    // Override from user-specified string.    ScudoParser.ParseString(getScudoDefaultOptions()); @@ -119,3 +129,9 @@ Flags *getFlags() {  }  }  // namespace __scudo + +#if !SANITIZER_SUPPORTS_WEAK_HOOKS +SANITIZER_INTERFACE_WEAK_DEF(const char*, __scudo_default_options, void) { +  return ""; +} +#endif diff --git a/lib/scudo/scudo_interceptors.cpp b/lib/scudo/scudo_interceptors.cpp deleted file mode 100644 index 735a131967575..0000000000000 --- a/lib/scudo/scudo_interceptors.cpp +++ /dev/null @@ -1,75 +0,0 @@ -//===-- scudo_interceptors.cpp ----------------------------------*- C++ -*-===// -// -//                     The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// Linux specific malloc interception functions. -/// -//===----------------------------------------------------------------------===// - -#include "sanitizer_common/sanitizer_platform.h" -#if SANITIZER_LINUX - -#include "scudo_allocator.h" - -#include "interception/interception.h" - -using namespace __scudo; - -INTERCEPTOR(void, free, void *ptr) { -  scudoFree(ptr, FromMalloc); -} - -INTERCEPTOR(void, cfree, void *ptr) { -  scudoFree(ptr, FromMalloc); -} - -INTERCEPTOR(void*, malloc, uptr size) { -  return scudoMalloc(size, FromMalloc); -} - -INTERCEPTOR(void*, realloc, void *ptr, uptr size) { -  return scudoRealloc(ptr, size); -} - -INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) { -  return scudoCalloc(nmemb, size); -} - -INTERCEPTOR(void*, valloc, uptr size) { -  return scudoValloc(size); -} - -INTERCEPTOR(void*, memalign, uptr alignment, uptr size) { -  return scudoMemalign(alignment, size); -} - -INTERCEPTOR(void*, __libc_memalign, uptr alignment, uptr size) { -  return scudoMemalign(alignment, size); -} - -INTERCEPTOR(void*, pvalloc, uptr size) { -  return scudoPvalloc(size); -} - -INTERCEPTOR(void*, aligned_alloc, uptr alignment, uptr size) { -  return scudoAlignedAlloc(alignment, size); -} - -INTERCEPTOR(int, posix_memalign, void **memptr, uptr alignment, uptr size) { -  return scudoPosixMemalign(memptr, alignment, size); -} - -INTERCEPTOR(uptr, malloc_usable_size, void *ptr) { -  return scudoMallocUsableSize(ptr); -} - -INTERCEPTOR(int, mallopt, int cmd, int value) { -  return -1; -} - -#endif  // SANITIZER_LINUX diff --git a/lib/scudo/scudo_interface_internal.h b/lib/scudo/scudo_interface_internal.h index 3f39e0c4ee0bb..3e520a50c83b4 100644 --- a/lib/scudo/scudo_interface_internal.h +++ b/lib/scudo/scudo_interface_internal.h @@ -14,9 +14,20 @@  #ifndef SCUDO_INTERFACE_INTERNAL_H_  #define SCUDO_INTERFACE_INTERNAL_H_ +#include "sanitizer_common/sanitizer_internal_defs.h" + +using __sanitizer::uptr; +using __sanitizer::s32; +  extern "C" { +SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE +const char* __scudo_default_options(); + +SANITIZER_INTERFACE_ATTRIBUTE +void __scudo_set_rss_limit(uptr LimitMb, s32 HardLimit); +  SANITIZER_INTERFACE_ATTRIBUTE -void __scudo_set_rss_limit(unsigned long LimitMb, int HardLimit);  // NOLINT +void __scudo_print_stats();  }  // extern "C"  #endif  // SCUDO_INTERFACE_INTERNAL_H_ diff --git a/lib/scudo/scudo_malloc.cpp b/lib/scudo/scudo_malloc.cpp new file mode 100644 index 0000000000000..91a77b3658235 --- /dev/null +++ b/lib/scudo/scudo_malloc.cpp @@ -0,0 +1,85 @@ +//===-- scudo_malloc.cpp ----------------------------------------*- C++ -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// Interceptors for malloc related functions. +/// +//===----------------------------------------------------------------------===// + +#include "scudo_allocator.h" + +#include "interception/interception.h" +#include "sanitizer_common/sanitizer_platform_interceptors.h" + +#include <stddef.h> + +using namespace __scudo; + +extern "C" { +INTERCEPTOR_ATTRIBUTE void free(void *ptr) { +  scudoDeallocate(ptr, 0, 0, FromMalloc); +} + +INTERCEPTOR_ATTRIBUTE void *malloc(size_t size) { +  return scudoAllocate(size, 0, FromMalloc); +} + +INTERCEPTOR_ATTRIBUTE void *realloc(void *ptr, size_t size) { +  return scudoRealloc(ptr, size); +} + +INTERCEPTOR_ATTRIBUTE void *calloc(size_t nmemb, size_t size) { +  return scudoCalloc(nmemb, size); +} + +INTERCEPTOR_ATTRIBUTE void *valloc(size_t size) { +  return scudoValloc(size); +} + +INTERCEPTOR_ATTRIBUTE +int posix_memalign(void **memptr, size_t alignment, size_t size) { +  return scudoPosixMemalign(memptr, alignment, size); +} + +#if SANITIZER_INTERCEPT_CFREE +INTERCEPTOR_ATTRIBUTE void cfree(void *ptr) ALIAS("free"); +#endif + +#if SANITIZER_INTERCEPT_MEMALIGN +INTERCEPTOR_ATTRIBUTE void *memalign(size_t alignment, size_t size) { +  return scudoAllocate(size, alignment, FromMemalign); +} + +INTERCEPTOR_ATTRIBUTE +void *__libc_memalign(size_t alignment, size_t size) ALIAS("memalign"); +#endif + +#if SANITIZER_INTERCEPT_PVALLOC +INTERCEPTOR_ATTRIBUTE void *pvalloc(size_t size) { +  return scudoPvalloc(size); +} +#endif + +#if SANITIZER_INTERCEPT_ALIGNED_ALLOC +INTERCEPTOR_ATTRIBUTE void *aligned_alloc(size_t alignment, size_t size) { +  return scudoAlignedAlloc(alignment, size); +} +#endif + +#if SANITIZER_INTERCEPT_MALLOC_USABLE_SIZE +INTERCEPTOR_ATTRIBUTE size_t malloc_usable_size(void *ptr) { +  return scudoMallocUsableSize(ptr); +} +#endif + +#if SANITIZER_INTERCEPT_MALLOPT_AND_MALLINFO +INTERCEPTOR_ATTRIBUTE int mallopt(int cmd, int value) { +  return -1; +} +#endif +}  // extern "C" diff --git a/lib/scudo/scudo_new_delete.cpp b/lib/scudo/scudo_new_delete.cpp index c5a1abbed82ba..daa3b47dc7272 100644 --- a/lib/scudo/scudo_new_delete.cpp +++ b/lib/scudo/scudo_new_delete.cpp @@ -12,6 +12,7 @@  //===----------------------------------------------------------------------===//  #include "scudo_allocator.h" +#include "scudo_errors.h"  #include "interception/interception.h" @@ -24,51 +25,84 @@ using namespace __scudo;  // Fake std::nothrow_t to avoid including <new>.  namespace std {  struct nothrow_t {}; +enum class align_val_t: size_t {};  }  // namespace std  // TODO(alekseys): throw std::bad_alloc instead of dying on OOM. +#define OPERATOR_NEW_BODY_ALIGN(Type, Align, NoThrow)              \ +  void *Ptr = scudoAllocate(size, static_cast<uptr>(Align), Type); \ +  if (!NoThrow && UNLIKELY(!Ptr)) reportOutOfMemory(size);         \ +  return Ptr; +#define OPERATOR_NEW_BODY(Type, NoThrow) \ +  OPERATOR_NEW_BODY_ALIGN(Type, 0, NoThrow) + +CXX_OPERATOR_ATTRIBUTE +void *operator new(size_t size) +{ OPERATOR_NEW_BODY(FromNew, /*NoThrow=*/false); } +CXX_OPERATOR_ATTRIBUTE +void *operator new[](size_t size) +{ OPERATOR_NEW_BODY(FromNewArray, /*NoThrow=*/false); } +CXX_OPERATOR_ATTRIBUTE +void *operator new(size_t size, std::nothrow_t const&) +{ OPERATOR_NEW_BODY(FromNew, /*NoThrow=*/true); } +CXX_OPERATOR_ATTRIBUTE +void *operator new[](size_t size, std::nothrow_t const&) +{ OPERATOR_NEW_BODY(FromNewArray, /*NoThrow=*/true); } +CXX_OPERATOR_ATTRIBUTE +void *operator new(size_t size, std::align_val_t align) +{ OPERATOR_NEW_BODY_ALIGN(FromNew, align, /*NoThrow=*/false); } +CXX_OPERATOR_ATTRIBUTE +void *operator new[](size_t size, std::align_val_t align) +{ OPERATOR_NEW_BODY_ALIGN(FromNewArray, align, /*NoThrow=*/false); } +CXX_OPERATOR_ATTRIBUTE +void *operator new(size_t size, std::align_val_t align, std::nothrow_t const&) +{ OPERATOR_NEW_BODY_ALIGN(FromNew, align, /*NoThrow=*/true); }  CXX_OPERATOR_ATTRIBUTE -void *operator new(size_t size) { -  void *res = scudoMalloc(size, FromNew); -  if (UNLIKELY(!res)) DieOnFailure::OnOOM(); -  return res; -} -CXX_OPERATOR_ATTRIBUTE -void *operator new[](size_t size) { -  void *res = scudoMalloc(size, FromNewArray); -  if (UNLIKELY(!res)) DieOnFailure::OnOOM(); -  return res; -} -CXX_OPERATOR_ATTRIBUTE -void *operator new(size_t size, std::nothrow_t const&) { -  return scudoMalloc(size, FromNew); -} -CXX_OPERATOR_ATTRIBUTE -void *operator new[](size_t size, std::nothrow_t const&) { -  return scudoMalloc(size, FromNewArray); -} +void *operator new[](size_t size, std::align_val_t align, std::nothrow_t const&) +{ OPERATOR_NEW_BODY_ALIGN(FromNewArray, align, /*NoThrow=*/true); } +#define OPERATOR_DELETE_BODY(Type) \ +  scudoDeallocate(ptr, 0, 0, Type); +#define OPERATOR_DELETE_BODY_SIZE(Type) \ +  scudoDeallocate(ptr, size, 0, Type); +#define OPERATOR_DELETE_BODY_ALIGN(Type) \ +  scudoDeallocate(ptr, 0, static_cast<uptr>(align), Type); +#define OPERATOR_DELETE_BODY_SIZE_ALIGN(Type) \ +  scudoDeallocate(ptr, size, static_cast<uptr>(align), Type); + +CXX_OPERATOR_ATTRIBUTE +void operator delete(void *ptr) NOEXCEPT +{ OPERATOR_DELETE_BODY(FromNew); } +CXX_OPERATOR_ATTRIBUTE +void operator delete[](void *ptr) NOEXCEPT +{ OPERATOR_DELETE_BODY(FromNewArray); } +CXX_OPERATOR_ATTRIBUTE +void operator delete(void *ptr, std::nothrow_t const&) +{ OPERATOR_DELETE_BODY(FromNew); } +CXX_OPERATOR_ATTRIBUTE +void operator delete[](void *ptr, std::nothrow_t const&) +{ OPERATOR_DELETE_BODY(FromNewArray); } +CXX_OPERATOR_ATTRIBUTE +void operator delete(void *ptr, size_t size) NOEXCEPT +{ OPERATOR_DELETE_BODY_SIZE(FromNew); } +CXX_OPERATOR_ATTRIBUTE +void operator delete[](void *ptr, size_t size) NOEXCEPT +{ OPERATOR_DELETE_BODY_SIZE(FromNewArray); }  CXX_OPERATOR_ATTRIBUTE -void operator delete(void *ptr) NOEXCEPT { -  return scudoFree(ptr, FromNew); -} +void operator delete(void *ptr, std::align_val_t align) NOEXCEPT +{ OPERATOR_DELETE_BODY_ALIGN(FromNew); }  CXX_OPERATOR_ATTRIBUTE -void operator delete[](void *ptr) NOEXCEPT { -  return scudoFree(ptr, FromNewArray); -} +void operator delete[](void *ptr, std::align_val_t align) NOEXCEPT +{ OPERATOR_DELETE_BODY_ALIGN(FromNewArray); }  CXX_OPERATOR_ATTRIBUTE -void operator delete(void *ptr, std::nothrow_t const&) NOEXCEPT { -  return scudoFree(ptr, FromNew); -} +void operator delete(void *ptr, std::align_val_t align, std::nothrow_t const&) +{ OPERATOR_DELETE_BODY_ALIGN(FromNew); }  CXX_OPERATOR_ATTRIBUTE -void operator delete[](void *ptr, std::nothrow_t const&) NOEXCEPT { -  return scudoFree(ptr, FromNewArray); -} +void operator delete[](void *ptr, std::align_val_t align, std::nothrow_t const&) +{ OPERATOR_DELETE_BODY_ALIGN(FromNewArray); }  CXX_OPERATOR_ATTRIBUTE -void operator delete(void *ptr, size_t size) NOEXCEPT { -  scudoSizedFree(ptr, size, FromNew); -} +void operator delete(void *ptr, size_t size, std::align_val_t align) NOEXCEPT +{ OPERATOR_DELETE_BODY_SIZE_ALIGN(FromNew); }  CXX_OPERATOR_ATTRIBUTE -void operator delete[](void *ptr, size_t size) NOEXCEPT { -  scudoSizedFree(ptr, size, FromNewArray); -} +void operator delete[](void *ptr, size_t size, std::align_val_t align) NOEXCEPT +{ OPERATOR_DELETE_BODY_SIZE_ALIGN(FromNewArray); } diff --git a/lib/scudo/scudo_platform.h b/lib/scudo/scudo_platform.h index e1c9c32e9a623..3a6f4be69dbd9 100644 --- a/lib/scudo/scudo_platform.h +++ b/lib/scudo/scudo_platform.h @@ -43,7 +43,11 @@  // Maximum number of TSDs that can be created for the Shared model.  #ifndef SCUDO_SHARED_TSD_POOL_SIZE -# define SCUDO_SHARED_TSD_POOL_SIZE 32U +# if SANITIZER_ANDROID +#  define SCUDO_SHARED_TSD_POOL_SIZE 2U +# else +#  define SCUDO_SHARED_TSD_POOL_SIZE 32U +# endif  // SANITIZER_ANDROID  #endif  // SCUDO_SHARED_TSD_POOL_SIZE  // The following allows the public interface functions to be disabled. @@ -51,6 +55,16 @@  # define SCUDO_CAN_USE_PUBLIC_INTERFACE 1  #endif +// Hooks in the allocation & deallocation paths can become a security concern if +// implemented improperly, or if overwritten by an attacker. Use with caution. +#ifndef SCUDO_CAN_USE_HOOKS +# if SANITIZER_FUCHSIA +#  define SCUDO_CAN_USE_HOOKS 1 +# else +#  define SCUDO_CAN_USE_HOOKS 0 +# endif  // SANITIZER_FUCHSIA +#endif  // SCUDO_CAN_USE_HOOKS +  namespace __scudo {  #if SANITIZER_CAN_USE_ALLOCATOR64 diff --git a/lib/scudo/scudo_termination.cpp b/lib/scudo/scudo_termination.cpp index c441ff3c126ac..4237d3bc18653 100644 --- a/lib/scudo/scudo_termination.cpp +++ b/lib/scudo/scudo_termination.cpp @@ -35,7 +35,7 @@ void SetCheckFailedCallback(CheckFailedCallbackType callback) {}  void NORETURN CheckFailed(const char *File, int Line, const char *Condition,                            u64 Value1, u64 Value2) { -  __scudo::dieWithMessage("Scudo CHECK failed: %s:%d %s (%lld, %lld)\n", +  __scudo::dieWithMessage("CHECK failed at %s:%d %s (%lld, %lld)\n",                            File, Line, Condition, Value1, Value2);  } diff --git a/lib/scudo/scudo_tsd.h b/lib/scudo/scudo_tsd.h index 80464b5ea1e4a..2bd78716af694 100644 --- a/lib/scudo/scudo_tsd.h +++ b/lib/scudo/scudo_tsd.h @@ -23,11 +23,11 @@  namespace __scudo { -struct ALIGNED(64) ScudoTSD { -  AllocatorCache Cache; +struct ALIGNED(SANITIZER_CACHE_LINE_SIZE) ScudoTSD { +  AllocatorCacheT Cache;    uptr QuarantineCachePlaceHolder[4]; -  void init(bool Shared); +  void init();    void commitBack();    INLINE bool tryLock() { @@ -36,29 +36,23 @@ struct ALIGNED(64) ScudoTSD {        return true;      }      if (atomic_load_relaxed(&Precedence) == 0) -      atomic_store_relaxed(&Precedence, MonotonicNanoTime()); +      atomic_store_relaxed(&Precedence, static_cast<uptr>( +          MonotonicNanoTime() >> FIRST_32_SECOND_64(16, 0)));      return false;    }    INLINE void lock() { -    Mutex.Lock();      atomic_store_relaxed(&Precedence, 0); +    Mutex.Lock();    } -  INLINE void unlock() { -    if (!UnlockRequired) -      return; -    Mutex.Unlock(); -  } +  INLINE void unlock() { Mutex.Unlock(); } -  INLINE u64 getPrecedence() { -    return atomic_load_relaxed(&Precedence); -  } +  INLINE uptr getPrecedence() { return atomic_load_relaxed(&Precedence); }   private: -  bool UnlockRequired;    StaticSpinMutex Mutex; -  atomic_uint64_t Precedence; +  atomic_uintptr_t Precedence;  };  void initThread(bool MinimalInit); diff --git a/lib/scudo/scudo_tsd_exclusive.cpp b/lib/scudo/scudo_tsd_exclusive.cpp index 1084dfac91e1b..74e797580be79 100644 --- a/lib/scudo/scudo_tsd_exclusive.cpp +++ b/lib/scudo/scudo_tsd_exclusive.cpp @@ -50,7 +50,7 @@ static void teardownThread(void *Ptr) {  static void initOnce() {    CHECK_EQ(pthread_key_create(&PThreadKey, teardownThread), 0);    initScudo(); -  FallbackTSD.init(/*Shared=*/true); +  FallbackTSD.init();  }  void initThread(bool MinimalInit) { @@ -59,7 +59,7 @@ void initThread(bool MinimalInit) {      return;    CHECK_EQ(pthread_setspecific(PThreadKey, reinterpret_cast<void *>(        GetPthreadDestructorIterations())), 0); -  TSD.init(/*Shared=*/false); +  TSD.init();    ScudoThreadState = ThreadInitialized;  } diff --git a/lib/scudo/scudo_tsd_exclusive.inc b/lib/scudo/scudo_tsd_exclusive.inc index 567b6a1edd12b..1fa9dcdfd20dc 100644 --- a/lib/scudo/scudo_tsd_exclusive.inc +++ b/lib/scudo/scudo_tsd_exclusive.inc @@ -35,11 +35,13 @@ ALWAYS_INLINE void initThreadMaybe(bool MinimalInit = false) {    initThread(MinimalInit);  } -ALWAYS_INLINE ScudoTSD *getTSDAndLock() { +ALWAYS_INLINE ScudoTSD *getTSDAndLock(bool *UnlockRequired) {    if (UNLIKELY(ScudoThreadState != ThreadInitialized)) {      FallbackTSD.lock(); +    *UnlockRequired = true;      return &FallbackTSD;    } +  *UnlockRequired = false;    return &TSD;  } diff --git a/lib/scudo/scudo_tsd_shared.cpp b/lib/scudo/scudo_tsd_shared.cpp index 3e13e5d3a109b..8853894c00a2f 100644 --- a/lib/scudo/scudo_tsd_shared.cpp +++ b/lib/scudo/scudo_tsd_shared.cpp @@ -23,6 +23,13 @@ pthread_key_t PThreadKey;  static atomic_uint32_t CurrentIndex;  static ScudoTSD *TSDs;  static u32 NumberOfTSDs; +static u32 CoPrimes[SCUDO_SHARED_TSD_POOL_SIZE]; +static u32 NumberOfCoPrimes = 0; + +#if SANITIZER_LINUX && !SANITIZER_ANDROID +__attribute__((tls_model("initial-exec"))) +THREADLOCAL ScudoTSD *CurrentTSD; +#endif  static void initOnce() {    CHECK_EQ(pthread_key_create(&PThreadKey, NULL), 0); @@ -31,13 +38,21 @@ static void initOnce() {                       static_cast<u32>(SCUDO_SHARED_TSD_POOL_SIZE));    TSDs = reinterpret_cast<ScudoTSD *>(        MmapOrDie(sizeof(ScudoTSD) * NumberOfTSDs, "ScudoTSDs")); -  for (u32 i = 0; i < NumberOfTSDs; i++) -    TSDs[i].init(/*Shared=*/true); +  for (u32 I = 0; I < NumberOfTSDs; I++) { +    TSDs[I].init(); +    u32 A = I + 1; +    u32 B = NumberOfTSDs; +    while (B != 0) { const u32 T = A; A = B; B = T % B; } +    if (A == 1) +      CoPrimes[NumberOfCoPrimes++] = I + 1; +  }  }  ALWAYS_INLINE void setCurrentTSD(ScudoTSD *TSD) {  #if SANITIZER_ANDROID    *get_android_tls_ptr() = reinterpret_cast<uptr>(TSD); +#elif SANITIZER_LINUX +  CurrentTSD = TSD;  #else    CHECK_EQ(pthread_setspecific(PThreadKey, reinterpret_cast<void *>(TSD)), 0);  #endif  // SANITIZER_ANDROID @@ -50,34 +65,42 @@ void initThread(bool MinimalInit) {    setCurrentTSD(&TSDs[Index % NumberOfTSDs]);  } -ScudoTSD *getTSDAndLockSlow() { -  ScudoTSD *TSD; +ScudoTSD *getTSDAndLockSlow(ScudoTSD *TSD) {    if (NumberOfTSDs > 1) { -    // Go through all the contexts and find the first unlocked one. -    for (u32 i = 0; i < NumberOfTSDs; i++) { -      TSD = &TSDs[i]; -      if (TSD->tryLock()) { -        setCurrentTSD(TSD); -        return TSD; +    // Use the Precedence of the current TSD as our random seed. Since we are in +    // the slow path, it means that tryLock failed, and as a result it's very +    // likely that said Precedence is non-zero. +    u32 RandState = static_cast<u32>(TSD->getPrecedence()); +    const u32 R = Rand(&RandState); +    const u32 Inc = CoPrimes[R % NumberOfCoPrimes]; +    u32 Index = R % NumberOfTSDs; +    uptr LowestPrecedence = UINTPTR_MAX; +    ScudoTSD *CandidateTSD = nullptr; +    // Go randomly through at most 4 contexts and find a candidate. +    for (u32 I = 0; I < Min(4U, NumberOfTSDs); I++) { +      if (TSDs[Index].tryLock()) { +        setCurrentTSD(&TSDs[Index]); +        return &TSDs[Index];        } -    } -    // No luck, find the one with the lowest Precedence, and slow lock it. -    u64 LowestPrecedence = UINT64_MAX; -    for (u32 i = 0; i < NumberOfTSDs; i++) { -      u64 Precedence = TSDs[i].getPrecedence(); -      if (Precedence && Precedence < LowestPrecedence) { -        TSD = &TSDs[i]; +      const uptr Precedence = TSDs[Index].getPrecedence(); +      // A 0 precedence here means another thread just locked this TSD. +      if (UNLIKELY(Precedence == 0)) +        continue; +      if (Precedence < LowestPrecedence) { +        CandidateTSD = &TSDs[Index];          LowestPrecedence = Precedence;        } +      Index += Inc; +      if (Index >= NumberOfTSDs) +        Index -= NumberOfTSDs;      } -    if (LIKELY(LowestPrecedence != UINT64_MAX)) { -      TSD->lock(); -      setCurrentTSD(TSD); -      return TSD; +    if (CandidateTSD) { +      CandidateTSD->lock(); +      setCurrentTSD(CandidateTSD); +      return CandidateTSD;      }    }    // Last resort, stick with the current one. -  TSD = getCurrentTSD();    TSD->lock();    return TSD;  } diff --git a/lib/scudo/scudo_tsd_shared.inc b/lib/scudo/scudo_tsd_shared.inc index 79fcd651ed2da..9dad756b53861 100644 --- a/lib/scudo/scudo_tsd_shared.inc +++ b/lib/scudo/scudo_tsd_shared.inc @@ -19,9 +19,16 @@  extern pthread_key_t PThreadKey; +#if SANITIZER_LINUX && !SANITIZER_ANDROID +__attribute__((tls_model("initial-exec"))) +extern THREADLOCAL ScudoTSD *CurrentTSD; +#endif +  ALWAYS_INLINE ScudoTSD* getCurrentTSD() {  #if SANITIZER_ANDROID    return reinterpret_cast<ScudoTSD *>(*get_android_tls_ptr()); +#elif SANITIZER_LINUX +  return CurrentTSD;  #else    return reinterpret_cast<ScudoTSD *>(pthread_getspecific(PThreadKey));  #endif  // SANITIZER_ANDROID @@ -33,16 +40,17 @@ ALWAYS_INLINE void initThreadMaybe(bool MinimalInit = false) {    initThread(MinimalInit);  } -ScudoTSD *getTSDAndLockSlow(); +ScudoTSD *getTSDAndLockSlow(ScudoTSD *TSD); -ALWAYS_INLINE ScudoTSD *getTSDAndLock() { +ALWAYS_INLINE ScudoTSD *getTSDAndLock(bool *UnlockRequired) {    ScudoTSD *TSD = getCurrentTSD(); -  CHECK(TSD && "No TSD associated with the current thread!"); +  DCHECK(TSD && "No TSD associated with the current thread!"); +  *UnlockRequired = true;    // Try to lock the currently associated context.    if (TSD->tryLock())      return TSD;    // If it failed, go the slow path. -  return getTSDAndLockSlow(); +  return getTSDAndLockSlow(TSD);  }  #endif  // !SCUDO_TSD_EXCLUSIVE diff --git a/lib/scudo/scudo_utils.cpp b/lib/scudo/scudo_utils.cpp index 2f936bf9e780e..d5788d20ca46d 100644 --- a/lib/scudo/scudo_utils.cpp +++ b/lib/scudo/scudo_utils.cpp @@ -17,7 +17,10 @@  # include <cpuid.h>  #elif defined(__arm__) || defined(__aarch64__)  # include "sanitizer_common/sanitizer_getauxval.h" -# if SANITIZER_POSIX +# if SANITIZER_FUCHSIA +#  include <zircon/syscalls.h> +#  include <zircon/features.h> +# elif SANITIZER_POSIX  #  include "sanitizer_common/sanitizer_posix.h"  #  include <fcntl.h>  # endif @@ -38,12 +41,18 @@ extern int VSNPrintf(char *buff, int buff_length, const char *format,  namespace __scudo {  FORMAT(1, 2) void NORETURN dieWithMessage(const char *Format, ...) { +  static const char ScudoError[] = "Scudo ERROR: "; +  static constexpr uptr PrefixSize = sizeof(ScudoError) - 1;    // Our messages are tiny, 256 characters is more than enough.    char Message[256];    va_list Args;    va_start(Args, Format); -  VSNPrintf(Message, sizeof(Message), Format, Args); +  internal_memcpy(Message, ScudoError, PrefixSize); +  VSNPrintf(Message + PrefixSize, sizeof(Message) - PrefixSize, Format, Args);    va_end(Args); +  LogMessageOnPrintf(Message); +  if (common_flags()->abort_on_error) +    SetAbortMessage(Message);    RawWrite(Message);    Die();  } @@ -107,9 +116,17 @@ INLINE bool areBionicGlobalsInitialized() {  }  bool hasHardwareCRC32() { +#if SANITIZER_FUCHSIA +  u32 HWCap; +  zx_status_t Status = zx_system_get_features(ZX_FEATURE_KIND_CPU, &HWCap); +  if (Status != ZX_OK || (HWCap & ZX_ARM64_FEATURE_ISA_CRC32) == 0) +    return false; +  return true; +#else    if (&getauxval && areBionicGlobalsInitialized())      return !!(getauxval(AT_HWCAP) & HWCAP_CRC32);    return hasHardwareCRC32ARMPosix(); +#endif  // SANITIZER_FUCHSIA  }  #else  bool hasHardwareCRC32() { return false; } diff --git a/lib/stats/CMakeLists.txt b/lib/stats/CMakeLists.txt index 6be36a7cb5687..23c80843195d2 100644 --- a/lib/stats/CMakeLists.txt +++ b/lib/stats/CMakeLists.txt @@ -1,3 +1,6 @@ +set(STATS_HEADERS +  stats.h) +  include_directories(..)  add_custom_target(stats) @@ -22,8 +25,10 @@ add_compiler_rt_runtime(clang_rt.stats    ARCHS ${SANITIZER_COMMON_SUPPORTED_ARCH}    OS ${SANITIZER_COMMON_SUPPORTED_OS}    SOURCES stats.cc +  ADDITIONAL_HEADERS ${STATS_HEADERS}    OBJECT_LIBS RTSanitizerCommon                RTSanitizerCommonLibc +              RTSanitizerCommonSymbolizer    CFLAGS ${SANITIZER_COMMON_CFLAGS}    LINK_FLAGS ${SANITIZER_COMMON_LINK_FLAGS} ${WEAK_SYMBOL_LINK_FLAGS}    LINK_LIBS ${STATS_LINK_LIBS} @@ -34,6 +39,7 @@ add_compiler_rt_runtime(clang_rt.stats_client    ARCHS ${SANITIZER_COMMON_SUPPORTED_ARCH}    OS ${SANITIZER_COMMON_SUPPORTED_OS}    SOURCES stats_client.cc +  ADDITIONAL_HEADERS ${STATS_HEADERS}    CFLAGS ${SANITIZER_COMMON_CFLAGS}    LINK_FLAGS ${WEAK_SYMBOL_LINK_FLAGS}    PARENT_TARGET stats) diff --git a/lib/stats/stats.cc b/lib/stats/stats.cc index 6a6eb3a3cdbce..c7a9a38a612a4 100644 --- a/lib/stats/stats.cc +++ b/lib/stats/stats.cc @@ -42,7 +42,7 @@ void WriteLE(fd_t fd, uptr val) {  }  void OpenStatsFile(const char *path_env) { -  InternalScopedBuffer<char> path(kMaxPathLength); +  InternalMmapVector<char> path(kMaxPathLength);    SubstituteForFlagValue(path_env, path.data(), kMaxPathLength);    error_t err; diff --git a/lib/tsan/.clang-format b/lib/tsan/.clang-format index f6cb8ad931f54..560308c91deec 100644 --- a/lib/tsan/.clang-format +++ b/lib/tsan/.clang-format @@ -1 +1,2 @@  BasedOnStyle: Google +AllowShortIfStatementsOnASingleLine: false diff --git a/lib/tsan/CMakeLists.txt b/lib/tsan/CMakeLists.txt index 3697ecb213814..4a2ea3f4ac75c 100644 --- a/lib/tsan/CMakeLists.txt +++ b/lib/tsan/CMakeLists.txt @@ -5,7 +5,10 @@ include_directories(..)  set(TSAN_CFLAGS ${SANITIZER_COMMON_CFLAGS})  # SANITIZER_COMMON_CFLAGS contains -fPIC, but it's performance-critical for  # TSan runtime to be built with -fPIE to reduce the number of register spills. -append_list_if(COMPILER_RT_HAS_FPIE_FLAG -fPIE TSAN_CFLAGS) +# On FreeBSD however it provokes linkage issue thus we disable it. +if(NOT CMAKE_SYSTEM MATCHES "FreeBSD") +  append_list_if(COMPILER_RT_HAS_FPIE_FLAG -fPIE TSAN_CFLAGS) +endif()  append_rtti_flag(OFF TSAN_CFLAGS)  if(COMPILER_RT_TSAN_DEBUG_OUTPUT) @@ -77,14 +80,15 @@ set(TSAN_HEADERS    rtl/tsan_flags.inc    rtl/tsan_ignoreset.h    rtl/tsan_interceptors.h -  rtl/tsan_interface_ann.h    rtl/tsan_interface.h +  rtl/tsan_interface_ann.h    rtl/tsan_interface_inl.h    rtl/tsan_interface_java.h    rtl/tsan_mman.h    rtl/tsan_mutex.h    rtl/tsan_mutexset.h    rtl/tsan_platform.h +  rtl/tsan_ppc_regs.h    rtl/tsan_report.h    rtl/tsan_rtl.h    rtl/tsan_stack_trace.h @@ -111,18 +115,22 @@ if(APPLE)      OS ${TSAN_SUPPORTED_OS}      ARCHS ${TSAN_SUPPORTED_ARCH}      SOURCES ${TSAN_SOURCES} ${TSAN_CXX_SOURCES} ${TSAN_ASM_SOURCES} +    ADDITIONAL_HEADERS ${TSAN_HEADERS}      OBJECT_LIBS RTInterception                  RTSanitizerCommon                  RTSanitizerCommonLibc +                RTSanitizerCommonCoverage +                RTSanitizerCommonSymbolizer                  RTUbsan      CFLAGS ${TSAN_RTL_CFLAGS}      LINK_FLAGS ${SANITIZER_COMMON_LINK_FLAGS} ${WEAK_SYMBOL_LINK_FLAGS} -    LINK_LIBS ${TSAN_LINK_LIBS} +    LINK_LIBS ${TSAN_LINK_LIBS} objc      PARENT_TARGET tsan)    add_compiler_rt_object_libraries(RTTsan_dynamic      OS ${TSAN_SUPPORTED_OS}      ARCHS ${TSAN_SUPPORTED_ARCH}      SOURCES ${TSAN_SOURCES} ${TSAN_CXX_SOURCES} ${TSAN_ASM_SOURCES} +    ADDITIONAL_HEADERS ${TSAN_HEADERS}      CFLAGS ${TSAN_RTL_CFLAGS})    # Build and check Go runtime. @@ -134,6 +142,7 @@ if(APPLE)      WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/go      COMMENT "Checking TSan Go runtime..."      VERBATIM) +  set_target_properties(GotsanRuntimeCheck PROPERTIES FOLDER "Compiler-RT Misc")  else()    foreach(arch ${TSAN_SUPPORTED_ARCH})      if(arch STREQUAL "x86_64") @@ -151,6 +160,15 @@ else()        add_asm_sources(TSAN_ASM_SOURCES rtl/tsan_rtl_aarch64.S)      elseif(arch MATCHES "powerpc64|powerpc64le")        add_asm_sources(TSAN_ASM_SOURCES rtl/tsan_rtl_ppc64.S) +      # Sanity check for Go runtime. +      set(BUILDGO_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/go/buildgo.sh) +      add_custom_target(GotsanRuntimeCheck +	COMMAND env "CC=${CMAKE_C_COMPILER} ${CMAKE_C_COMPILER_ARG1}" +		IN_TMPDIR=1 SILENT=1 ${BUILDGO_SCRIPT} +	DEPENDS clang_rt.tsan-${arch} ${BUILDGO_SCRIPT} +	WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/go +	COMMENT "Checking TSan Go runtime..." +	VERBATIM)      elseif(arch MATCHES "mips64|mips64le")        add_asm_sources(TSAN_ASM_SOURCES rtl/tsan_rtl_mips64.S)      else() @@ -163,7 +181,10 @@ else()                $<TARGET_OBJECTS:RTInterception.${arch}>                $<TARGET_OBJECTS:RTSanitizerCommon.${arch}>                $<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}> +              $<TARGET_OBJECTS:RTSanitizerCommonCoverage.${arch}> +              $<TARGET_OBJECTS:RTSanitizerCommonSymbolizer.${arch}>                $<TARGET_OBJECTS:RTUbsan.${arch}> +      ADDITIONAL_HEADERS ${TSAN_HEADERS}        CFLAGS ${TSAN_RTL_CFLAGS}        PARENT_TARGET tsan)      add_compiler_rt_runtime(clang_rt.tsan_cxx @@ -171,6 +192,7 @@ else()        ARCHS ${arch}        SOURCES ${TSAN_CXX_SOURCES}                $<TARGET_OBJECTS:RTUbsan_cxx.${arch}> +      ADDITIONAL_HEADERS ${TSAN_HEADERS}        CFLAGS ${TSAN_RTL_CFLAGS}        PARENT_TARGET tsan)      list(APPEND TSAN_RUNTIME_LIBRARIES clang_rt.tsan-${arch} @@ -212,11 +234,13 @@ if(COMPILER_RT_LIBCXX_PATH AND      set(LIBCXX_PREFIX ${CMAKE_CURRENT_BINARY_DIR}/libcxx_tsan_${arch})      add_custom_libcxx(libcxx_tsan_${arch} ${LIBCXX_PREFIX}        DEPS ${TSAN_RUNTIME_LIBRARIES} -      CFLAGS ${TARGET_CFLAGS} -fsanitize=thread) -    list(APPEND libcxx_tsan_deps libcxx_tsan_${arch}) +      CFLAGS ${TARGET_CFLAGS} -fsanitize=thread +      USE_TOOLCHAIN) +    list(APPEND libcxx_tsan_deps libcxx_tsan_${arch}-build)    endforeach()    add_custom_target(libcxx_tsan DEPENDS ${libcxx_tsan_deps}) +  set_target_properties(libcxx_tsan PROPERTIES FOLDER "Compiler-RT Misc")  endif()  if(COMPILER_RT_INCLUDE_TESTS) diff --git a/lib/tsan/dd/CMakeLists.txt b/lib/tsan/dd/CMakeLists.txt index 07fc300535cd9..f2b8a6d173a42 100644 --- a/lib/tsan/dd/CMakeLists.txt +++ b/lib/tsan/dd/CMakeLists.txt @@ -17,6 +17,8 @@ append_list_if(COMPILER_RT_HAS_LIBRT rt DD_LINKLIBS)  append_list_if(COMPILER_RT_HAS_LIBPTHREAD pthread DD_LINKLIBS)  add_custom_target(dd) +set_target_properties(dd PROPERTIES FOLDER "Compiler-RT Misc") +  # Deadlock detector is currently supported on 64-bit Linux only.  if(CAN_TARGET_x86_64 AND UNIX AND NOT APPLE AND NOT ANDROID)    set(arch "x86_64") @@ -41,6 +43,7 @@ if(CAN_TARGET_x86_64 AND UNIX AND NOT APPLE AND NOT ANDROID)              $<TARGET_OBJECTS:RTInterception.${arch}>              $<TARGET_OBJECTS:RTSanitizerCommon.${arch}>              $<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}> +            $<TARGET_OBJECTS:RTSanitizerCommonSymbolizer.${arch}>      LINK_FLAGS ${SANITIZER_COMMON_LINK_FLAGS}      LINK_LIBS ${DD_LINKLIBS}      PARENT_TARGET dd) diff --git a/lib/tsan/go/buildgo.sh b/lib/tsan/go/buildgo.sh index 62ff0fc38ba96..7f570ca811391 100755 --- a/lib/tsan/go/buildgo.sh +++ b/lib/tsan/go/buildgo.sh @@ -35,12 +35,12 @@ SRCS="  	../../sanitizer_common/sanitizer_stackdepot.cc  	../../sanitizer_common/sanitizer_stacktrace.cc  	../../sanitizer_common/sanitizer_symbolizer.cc +	../../sanitizer_common/sanitizer_symbolizer_report.cc  	../../sanitizer_common/sanitizer_termination.cc  "  if [ "`uname -a | grep Linux`" != "" ]; then -	SUFFIX="linux_amd64" -	OSCFLAGS="-fPIC -ffreestanding -Wno-maybe-uninitialized -Wno-unused-const-variable -Werror -Wno-unknown-warning-option" +	OSCFLAGS="-fPIC -Wno-maybe-uninitialized"  	OSLDFLAGS="-lpthread -fPIC -fpie"  	SRCS="  		$SRCS @@ -52,7 +52,13 @@ if [ "`uname -a | grep Linux`" != "" ]; then  		../../sanitizer_common/sanitizer_linux.cc  		../../sanitizer_common/sanitizer_linux_libcdep.cc  		../../sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc -	" +		" +	if [ "`uname -a | grep ppc64le`" != "" ]; then +		SUFFIX="linux_ppc64le" +	elif [ "`uname -a | grep x86_64`" != "" ]; then +		SUFFIX="linux_amd64" +		OSCFLAGS="$OSCFLAGS -ffreestanding -Wno-unused-const-variable -Werror -Wno-unknown-warning-option" +	fi  elif [ "`uname -a | grep FreeBSD`" != "" ]; then  	SUFFIX="freebsd_amd64"  	OSCFLAGS="-fno-strict-aliasing -fPIC -Werror" @@ -62,8 +68,8 @@ elif [ "`uname -a | grep FreeBSD`" != "" ]; then  		../rtl/tsan_platform_linux.cc  		../../sanitizer_common/sanitizer_posix.cc  		../../sanitizer_common/sanitizer_posix_libcdep.cc +		../../sanitizer_common/sanitizer_procmaps_bsd.cc  		../../sanitizer_common/sanitizer_procmaps_common.cc -		../../sanitizer_common/sanitizer_procmaps_freebsd.cc  		../../sanitizer_common/sanitizer_linux.cc  		../../sanitizer_common/sanitizer_linux_libcdep.cc  		../../sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc @@ -77,15 +83,15 @@ elif [ "`uname -a | grep NetBSD`" != "" ]; then  		../rtl/tsan_platform_linux.cc  		../../sanitizer_common/sanitizer_posix.cc  		../../sanitizer_common/sanitizer_posix_libcdep.cc +		../../sanitizer_common/sanitizer_procmaps_bsd.cc  		../../sanitizer_common/sanitizer_procmaps_common.cc -		../../sanitizer_common/sanitizer_procmaps_freebsd.cc  		../../sanitizer_common/sanitizer_linux.cc  		../../sanitizer_common/sanitizer_linux_libcdep.cc  		../../sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc  	"  elif [ "`uname -a | grep Darwin`" != "" ]; then  	SUFFIX="darwin_amd64" -	OSCFLAGS="-fPIC -Wno-unused-const-variable -Wno-unknown-warning-option -isysroot $(xcodebuild -version -sdk macosx Path) -mmacosx-version-min=10.7" +	OSCFLAGS="-fPIC -Wno-unused-const-variable -Wno-unknown-warning-option -mmacosx-version-min=10.7"  	OSLDFLAGS="-lpthread -fPIC -fpie -mmacosx-version-min=10.7"  	SRCS="  		$SRCS @@ -132,7 +138,12 @@ done  FLAGS=" -I../rtl -I../.. -I../../sanitizer_common -I../../../include -std=c++11 -m64 -Wall -fno-exceptions -fno-rtti -DSANITIZER_GO=1 -DSANITIZER_DEADLOCK_DETECTOR_VERSION=2 $OSCFLAGS"  if [ "$DEBUG" = "" ]; then -	FLAGS="$FLAGS -DSANITIZER_DEBUG=0 -O3 -msse3 -fomit-frame-pointer" +	FLAGS="$FLAGS -DSANITIZER_DEBUG=0 -O3 -fomit-frame-pointer" +	if [ "$SUFFIX" = "linux_ppc64le" ]; then +		FLAGS="$FLAGS -mcpu=power8 -fno-function-sections" +	elif [ "$SUFFIX" = "linux_amd64" ]; then +		FLAGS="$FLAGS -msse3" +	fi  else  	FLAGS="$FLAGS -DSANITIZER_DEBUG=1 -g"  fi diff --git a/lib/tsan/go/test.c b/lib/tsan/go/test.c index b3e31b1feaa74..c484774caeb9f 100644 --- a/lib/tsan/go/test.c +++ b/lib/tsan/go/test.c @@ -11,6 +11,8 @@  //  //===----------------------------------------------------------------------===// +#include <sys/mman.h> +#include <errno.h>  #include <stdio.h>  #include <stdlib.h> @@ -44,7 +46,13 @@ void symbolize_cb(long cmd, void *ctx) {    }  } -char buf0[100<<10]; +/* + * See lib/tsan/rtl/tsan_platform.h for details of what the memory layout + * of Go programs looks like.  To prevent running over existing mappings, + * we pick an address slightly inside the Go heap region. + */ +void *go_heap = (void *)0xC011110000; +char *buf0;  void foobar() {}  void barfoo() {} @@ -54,6 +62,15 @@ int main(void) {    void *proc0 = 0;    __tsan_init(&thr0, &proc0, symbolize_cb);    current_proc = proc0; + +  // Allocate something resembling a heap in Go. +  buf0 = mmap(go_heap, 16384, PROT_READ | PROT_WRITE, +              MAP_PRIVATE | MAP_FIXED | MAP_ANON, -1, 0); +  if (buf0 == MAP_FAILED) { +    fprintf(stderr, "failed to allocate Go-like heap at %p; errno %d\n", +            go_heap, errno); +    return 1; +  }    char *buf = (char*)((unsigned long)buf0 + (64<<10) - 1 & ~((64<<10) - 1));    __tsan_map_shadow(buf, 4096);    __tsan_malloc(thr0, (char*)&barfoo + 1, buf, 10); diff --git a/lib/tsan/go/tsan_go.cc b/lib/tsan/go/tsan_go.cc index d7a9e0b679628..5f2507b7df1d3 100644 --- a/lib/tsan/go/tsan_go.cc +++ b/lib/tsan/go/tsan_go.cc @@ -282,11 +282,3 @@ void __tsan_report_count(u64 *pn) {  }  // extern "C"  }  // namespace __tsan - -namespace __sanitizer { - -void SymbolizerPrepareForSandboxing() { -  // Nothing to do here for Go. -} - -}  // namespace __sanitizer diff --git a/lib/tsan/rtl/tsan_debugging.cc b/lib/tsan/rtl/tsan_debugging.cc index a44b13632c61d..9e5465d37557a 100644 --- a/lib/tsan/rtl/tsan_debugging.cc +++ b/lib/tsan/rtl/tsan_debugging.cc @@ -83,6 +83,13 @@ int __tsan_get_report_data(void *report, const char **description, int *count,  }  SANITIZER_INTERFACE_ATTRIBUTE +int __tsan_get_report_tag(void *report, uptr *tag) { +  const ReportDesc *rep = (ReportDesc *)report; +  *tag = rep->tag; +  return 1; +} + +SANITIZER_INTERFACE_ATTRIBUTE  int __tsan_get_report_stack(void *report, uptr idx, void **trace,                              uptr trace_size) {    const ReportDesc *rep = (ReportDesc *)report; diff --git a/lib/tsan/rtl/tsan_interceptors.cc b/lib/tsan/rtl/tsan_interceptors.cc index d92976ad6e9ef..901997b3e85df 100644 --- a/lib/tsan/rtl/tsan_interceptors.cc +++ b/lib/tsan/rtl/tsan_interceptors.cc @@ -569,10 +569,8 @@ TSAN_INTERCEPTOR(int, sigsetjmp, void *env);  #define TSAN_INTERCEPTOR_SETJMP TSAN_INTERCEPTOR_SETJMP__(setjmp_symname)  #define TSAN_INTERCEPTOR_SIGSETJMP TSAN_INTERCEPTOR_SETJMP__(sigsetjmp_symname) -#define TSAN_STRING_SETJMP_(x) # x -#define TSAN_STRING_SETJMP__(x) TSAN_STRING_SETJMP_(x) -#define TSAN_STRING_SETJMP TSAN_STRING_SETJMP__(setjmp_symname) -#define TSAN_STRING_SIGSETJMP TSAN_STRING_SETJMP__(sigsetjmp_symname) +#define TSAN_STRING_SETJMP SANITIZER_STRINGIFY(setjmp_symname) +#define TSAN_STRING_SIGSETJMP SANITIZER_STRINGIFY(sigsetjmp_symname)  // Not called.  Merely to satisfy TSAN_INTERCEPT().  extern "C" SANITIZER_INTERFACE_ATTRIBUTE @@ -597,7 +595,7 @@ extern "C" int TSAN_INTERCEPTOR_SIGSETJMP(void *env) {    return 0;  } -#if !SANITIEZER_NETBSD +#if !SANITIZER_NETBSD  extern "C" SANITIZER_INTERFACE_ATTRIBUTE  int __interceptor___sigsetjmp(void *env);  extern "C" int __interceptor___sigsetjmp(void *env) { @@ -609,13 +607,13 @@ extern "C" int __interceptor___sigsetjmp(void *env) {  extern "C" int setjmp_symname(void *env);  extern "C" int _setjmp(void *env);  extern "C" int sigsetjmp_symname(void *env); -#if !SANITIEZER_NETBSD +#if !SANITIZER_NETBSD  extern "C" int __sigsetjmp(void *env);  #endif  DEFINE_REAL(int, setjmp_symname, void *env)  DEFINE_REAL(int, _setjmp, void *env)  DEFINE_REAL(int, sigsetjmp_symname, void *env) -#if !SANITIEZER_NETBSD +#if !SANITIZER_NETBSD  DEFINE_REAL(int, __sigsetjmp, void *env)  #endif  #endif  // SANITIZER_MAC @@ -762,16 +760,14 @@ static bool fix_mmap_addr(void **addr, long_t sz, int flags) {    return true;  } -TSAN_INTERCEPTOR(void *, mmap, void *addr, SIZE_T sz, int prot, int flags, -                 int fd, OFF_T off) { -  SCOPED_TSAN_INTERCEPTOR(mmap, addr, sz, prot, flags, fd, off); -  if (!fix_mmap_addr(&addr, sz, flags)) -    return MAP_FAILED; -  void *res = REAL(mmap)(addr, sz, prot, flags, fd, off); +template <class Mmap> +static void *mmap_interceptor(ThreadState *thr, uptr pc, Mmap real_mmap, +                              void *addr, SIZE_T sz, int prot, int flags, +                              int fd, OFF64_T off) { +  if (!fix_mmap_addr(&addr, sz, flags)) return MAP_FAILED; +  void *res = real_mmap(addr, sz, prot, flags, fd, off);    if (res != MAP_FAILED) { -    if (fd > 0) -      FdAccess(thr, pc, fd); - +    if (fd > 0) FdAccess(thr, pc, fd);      if (thr->ignore_reads_and_writes == 0)        MemoryRangeImitateWrite(thr, pc, (uptr)res, sz);      else @@ -780,29 +776,6 @@ TSAN_INTERCEPTOR(void *, mmap, void *addr, SIZE_T sz, int prot, int flags,    return res;  } -#if SANITIZER_LINUX -TSAN_INTERCEPTOR(void *, mmap64, void *addr, SIZE_T sz, int prot, int flags, -                 int fd, OFF64_T off) { -  SCOPED_TSAN_INTERCEPTOR(mmap64, addr, sz, prot, flags, fd, off); -  if (!fix_mmap_addr(&addr, sz, flags)) -    return MAP_FAILED; -  void *res = REAL(mmap64)(addr, sz, prot, flags, fd, off); -  if (res != MAP_FAILED) { -    if (fd > 0) -      FdAccess(thr, pc, fd); - -    if (thr->ignore_reads_and_writes == 0) -      MemoryRangeImitateWrite(thr, pc, (uptr)res, sz); -    else -      MemoryResetRange(thr, pc, (uptr)res, sz); -  } -  return res; -} -#define TSAN_MAYBE_INTERCEPT_MMAP64 TSAN_INTERCEPT(mmap64) -#else -#define TSAN_MAYBE_INTERCEPT_MMAP64 -#endif -  TSAN_INTERCEPTOR(int, munmap, void *addr, long_t sz) {    SCOPED_TSAN_INTERCEPTOR(munmap, addr, sz);    if (sz != 0) { @@ -932,7 +905,7 @@ void DestroyThreadState() {  }  }  // namespace __tsan -#if !SANITIZER_MAC && !SANITIZER_NETBSD +#if !SANITIZER_MAC && !SANITIZER_NETBSD && !SANITIZER_FREEBSD  static void thread_finalize(void *v) {    uptr iter = (uptr)v;    if (iter > 1) { @@ -963,7 +936,7 @@ extern "C" void *__tsan_thread_start_func(void *arg) {      ThreadState *thr = cur_thread();      // Thread-local state is not initialized yet.      ScopedIgnoreInterceptors ignore; -#if !SANITIZER_MAC && !SANITIZER_NETBSD +#if !SANITIZER_MAC && !SANITIZER_NETBSD && !SANITIZER_FREEBSD      ThreadIgnoreBegin(thr, 0);      if (pthread_setspecific(interceptor_ctx()->finalize_key,                              (void *)GetPthreadDestructorIterations())) { @@ -1763,12 +1736,6 @@ TSAN_INTERCEPTOR(void, abort, int fake) {    REAL(abort)(fake);  } -TSAN_INTERCEPTOR(int, puts, const char *s) { -  SCOPED_TSAN_INTERCEPTOR(puts, s); -  MemoryAccessRange(thr, pc, (uptr)s, internal_strlen(s), false); -  return REAL(puts)(s); -} -  TSAN_INTERCEPTOR(int, rmdir, char *path) {    SCOPED_TSAN_INTERCEPTOR(rmdir, path);    Release(thr, pc, Dir2addr(path)); @@ -2313,6 +2280,13 @@ static void HandleRecvmsg(ThreadState *thr, uptr pc,    MutexInvalidAccess(((TsanInterceptorContext *)ctx)->thr, \                       ((TsanInterceptorContext *)ctx)->pc, (uptr)m) +#define COMMON_INTERCEPTOR_MMAP_IMPL(ctx, mmap, addr, sz, prot, flags, fd,  \ +                                     off)                                   \ +  do {                                                                      \ +    return mmap_interceptor(thr, pc, REAL(mmap), addr, sz, prot, flags, fd, \ +                            off);                                           \ +  } while (false) +  #if !SANITIZER_MAC  #define COMMON_INTERCEPTOR_HANDLE_RECVMSG(ctx, msg) \    HandleRecvmsg(((TsanInterceptorContext *)ctx)->thr, \ @@ -2426,7 +2400,7 @@ struct ScopedSyscall {    }  }; -#if !SANITIZER_FREEBSD && !SANITIZER_MAC && !SANITIZER_NETBSD +#if !SANITIZER_FREEBSD && !SANITIZER_MAC  static void syscall_access_range(uptr pc, uptr p, uptr s, bool write) {    TSAN_SYSCALL();    MemoryAccessRange(thr, pc, p, s, write); @@ -2519,6 +2493,7 @@ static void syscall_post_fork(uptr pc, int pid) {    syscall_post_fork(GET_CALLER_PC(), res)  #include "sanitizer_common/sanitizer_common_syscalls.inc" +#include "sanitizer_common/sanitizer_syscalls_netbsd.inc"  #ifdef NEED_TLS_GET_ADDR  // Define own interceptor instead of sanitizer_common's for three reasons: @@ -2536,7 +2511,8 @@ TSAN_INTERCEPTOR(void *, __tls_get_addr, void *arg) {    ThreadState *thr = cur_thread();    if (!thr)      return res; -  DTLS::DTV *dtv = DTLS_on_tls_get_addr(arg, res, thr->tls_addr, thr->tls_size); +  DTLS::DTV *dtv = DTLS_on_tls_get_addr(arg, res, thr->tls_addr, +                                        thr->tls_addr + thr->tls_size);    if (!dtv)      return res;    // New DTLS block has been allocated. @@ -2556,22 +2532,33 @@ TSAN_INTERCEPTOR(void, _lwp_exit) {  #define TSAN_MAYBE_INTERCEPT__LWP_EXIT  #endif -TSAN_INTERCEPTOR_NETBSD_ALIAS(int, cond_init, void *c, void *a); -TSAN_INTERCEPTOR_NETBSD_ALIAS(int, cond_signal, void *c); -TSAN_INTERCEPTOR_NETBSD_ALIAS(int, cond_broadcast, void *c); -TSAN_INTERCEPTOR_NETBSD_ALIAS(int, cond_wait, void *c, void *m); -TSAN_INTERCEPTOR_NETBSD_ALIAS(int, cond_destroy, void *c); -TSAN_INTERCEPTOR_NETBSD_ALIAS(int, mutex_init, void *m, void *a); -TSAN_INTERCEPTOR_NETBSD_ALIAS(int, mutex_destroy, void *m); -TSAN_INTERCEPTOR_NETBSD_ALIAS(int, mutex_trylock, void *m); -TSAN_INTERCEPTOR_NETBSD_ALIAS(int, rwlock_init, void *m, void *a); -TSAN_INTERCEPTOR_NETBSD_ALIAS(int, rwlock_destroy, void *m); -TSAN_INTERCEPTOR_NETBSD_ALIAS(int, rwlock_rdlock, void *m); -TSAN_INTERCEPTOR_NETBSD_ALIAS(int, rwlock_tryrdlock, void *m); -TSAN_INTERCEPTOR_NETBSD_ALIAS(int, rwlock_wrlock, void *m); -TSAN_INTERCEPTOR_NETBSD_ALIAS(int, rwlock_trywrlock, void *m); -TSAN_INTERCEPTOR_NETBSD_ALIAS(int, rwlock_unlock, void *m); -TSAN_INTERCEPTOR_NETBSD_ALIAS_THR(int, once, void *o, void (*f)()); +#if SANITIZER_FREEBSD +TSAN_INTERCEPTOR(void, thr_exit, tid_t *state) { +  SCOPED_TSAN_INTERCEPTOR(thr_exit, state); +  DestroyThreadState(); +  REAL(thr_exit(state)); +} +#define TSAN_MAYBE_INTERCEPT_THR_EXIT TSAN_INTERCEPT(thr_exit) +#else +#define TSAN_MAYBE_INTERCEPT_THR_EXIT +#endif + +TSAN_INTERCEPTOR_NETBSD_ALIAS(int, cond_init, void *c, void *a) +TSAN_INTERCEPTOR_NETBSD_ALIAS(int, cond_signal, void *c) +TSAN_INTERCEPTOR_NETBSD_ALIAS(int, cond_broadcast, void *c) +TSAN_INTERCEPTOR_NETBSD_ALIAS(int, cond_wait, void *c, void *m) +TSAN_INTERCEPTOR_NETBSD_ALIAS(int, cond_destroy, void *c) +TSAN_INTERCEPTOR_NETBSD_ALIAS(int, mutex_init, void *m, void *a) +TSAN_INTERCEPTOR_NETBSD_ALIAS(int, mutex_destroy, void *m) +TSAN_INTERCEPTOR_NETBSD_ALIAS(int, mutex_trylock, void *m) +TSAN_INTERCEPTOR_NETBSD_ALIAS(int, rwlock_init, void *m, void *a) +TSAN_INTERCEPTOR_NETBSD_ALIAS(int, rwlock_destroy, void *m) +TSAN_INTERCEPTOR_NETBSD_ALIAS(int, rwlock_rdlock, void *m) +TSAN_INTERCEPTOR_NETBSD_ALIAS(int, rwlock_tryrdlock, void *m) +TSAN_INTERCEPTOR_NETBSD_ALIAS(int, rwlock_wrlock, void *m) +TSAN_INTERCEPTOR_NETBSD_ALIAS(int, rwlock_trywrlock, void *m) +TSAN_INTERCEPTOR_NETBSD_ALIAS(int, rwlock_unlock, void *m) +TSAN_INTERCEPTOR_NETBSD_ALIAS_THR(int, once, void *o, void (*f)())  namespace __tsan { @@ -2635,8 +2622,6 @@ void InitializeInterceptors() {    TSAN_INTERCEPT(realloc);    TSAN_INTERCEPT(free);    TSAN_INTERCEPT(cfree); -  TSAN_INTERCEPT(mmap); -  TSAN_MAYBE_INTERCEPT_MMAP64;    TSAN_INTERCEPT(munmap);    TSAN_MAYBE_INTERCEPT_MEMALIGN;    TSAN_INTERCEPT(valloc); @@ -2715,10 +2700,7 @@ void InitializeInterceptors() {    TSAN_INTERCEPT(unlink);    TSAN_INTERCEPT(tmpfile);    TSAN_MAYBE_INTERCEPT_TMPFILE64; -  TSAN_INTERCEPT(fread); -  TSAN_INTERCEPT(fwrite);    TSAN_INTERCEPT(abort); -  TSAN_INTERCEPT(puts);    TSAN_INTERCEPT(rmdir);    TSAN_INTERCEPT(closedir); @@ -2750,6 +2732,7 @@ void InitializeInterceptors() {  #endif    TSAN_MAYBE_INTERCEPT__LWP_EXIT; +  TSAN_MAYBE_INTERCEPT_THR_EXIT;  #if !SANITIZER_MAC && !SANITIZER_ANDROID    // Need to setup it, because interceptors check that the function is resolved. @@ -2762,7 +2745,7 @@ void InitializeInterceptors() {      Die();    } -#if !SANITIZER_MAC && !SANITIZER_NETBSD +#if !SANITIZER_MAC && !SANITIZER_NETBSD && !SANITIZER_FREEBSD    if (pthread_key_create(&interceptor_ctx()->finalize_key, &thread_finalize)) {      Printf("ThreadSanitizer: failed to create thread key\n");      Die(); diff --git a/lib/tsan/rtl/tsan_interceptors_mac.cc b/lib/tsan/rtl/tsan_interceptors_mac.cc index 3b3a4a2815c37..b58e6b7071cf1 100644 --- a/lib/tsan/rtl/tsan_interceptors_mac.cc +++ b/lib/tsan/rtl/tsan_interceptors_mac.cc @@ -294,6 +294,43 @@ TSAN_INTERCEPTOR(void, xpc_connection_cancel, xpc_connection_t connection) {  #endif  // #if defined(__has_include) && __has_include(<xpc/xpc.h>) +// Is the Obj-C object a tagged pointer (i.e. isn't really a valid pointer and +// contains data in the pointers bits instead)? +static bool IsTaggedObjCPointer(void *obj) { +  const uptr kPossibleTaggedBits = 0x8000000000000001ull; +  return ((uptr)obj & kPossibleTaggedBits) != 0; +} + +// Return an address on which we can synchronize (Acquire and Release) for a +// Obj-C tagged pointer (which is not a valid pointer). Ideally should be a +// derived address from 'obj', but for now just return the same global address. +// TODO(kubamracek): Return different address for different pointers. +static uptr SyncAddressForTaggedPointer(void *obj) { +  (void)obj; +  static u64 addr; +  return (uptr)&addr; +} + +// Address on which we can synchronize for an Objective-C object. Supports +// tagged pointers. +static uptr SyncAddressForObjCObject(void *obj) { +  if (IsTaggedObjCPointer(obj)) return SyncAddressForTaggedPointer(obj); +  return (uptr)obj; +} + +TSAN_INTERCEPTOR(int, objc_sync_enter, void *obj) { +  SCOPED_TSAN_INTERCEPTOR(objc_sync_enter, obj); +  int result = REAL(objc_sync_enter)(obj); +  if (obj) Acquire(thr, pc, SyncAddressForObjCObject(obj)); +  return result; +} + +TSAN_INTERCEPTOR(int, objc_sync_exit, void *obj) { +  SCOPED_TSAN_INTERCEPTOR(objc_sync_enter, obj); +  if (obj) Release(thr, pc, SyncAddressForObjCObject(obj)); +  return REAL(objc_sync_exit)(obj); +} +  // On macOS, libc++ is always linked dynamically, so intercepting works the  // usual way.  #define STDCXX_INTERCEPTOR TSAN_INTERCEPTOR diff --git a/lib/tsan/rtl/tsan_interface.h b/lib/tsan/rtl/tsan_interface.h index a80a48991cbaa..203f6b106a96e 100644 --- a/lib/tsan/rtl/tsan_interface.h +++ b/lib/tsan/rtl/tsan_interface.h @@ -117,6 +117,19 @@ int __tsan_get_report_data(void *report, const char **description, int *count,                             int *unique_tid_count, void **sleep_trace,                             uptr trace_size); +/// Retrieves the "tag" from a report (for external-race report types). External +/// races can be associated with a tag which give them more meaning. For example +/// tag value '1' means "Swift access race". Tag value '0' indicated a plain +/// external race. +/// +/// \param report opaque pointer to the current report (obtained as argument in +///               __tsan_on_report, or from __tsan_get_current_report) +/// \param [out] tag points to storage that will be filled with the tag value +/// +/// \returns non-zero value on success, zero on failure +SANITIZER_INTERFACE_ATTRIBUTE +int __tsan_get_report_tag(void *report, uptr *tag); +  // Returns information about stack traces included in the report.  SANITIZER_INTERFACE_ATTRIBUTE  int __tsan_get_report_stack(void *report, uptr idx, void **trace, diff --git a/lib/tsan/rtl/tsan_malloc_mac.cc b/lib/tsan/rtl/tsan_malloc_mac.cc index 455c95df6c505..3cc30724da858 100644 --- a/lib/tsan/rtl/tsan_malloc_mac.cc +++ b/lib/tsan/rtl/tsan_malloc_mac.cc @@ -15,6 +15,7 @@  #include "sanitizer_common/sanitizer_platform.h"  #if SANITIZER_MAC +#include "sanitizer_common/sanitizer_errno.h"  #include "tsan_interceptors.h"  #include "tsan_stack_trace.h" @@ -39,6 +40,15 @@ using namespace __tsan;    if (cur_thread()->in_symbolizer) return InternalCalloc(count, size); \    SCOPED_INTERCEPTOR_RAW(calloc, size, count);                         \    void *p = user_calloc(thr, pc, size, count) +#define COMMON_MALLOC_POSIX_MEMALIGN(memptr, alignment, size)      \ +  if (cur_thread()->in_symbolizer) {                               \ +    void *p = InternalAlloc(size, nullptr, alignment);             \ +    if (!p) return errno_ENOMEM;                                   \ +    *memptr = p;                                                   \ +    return 0;                                                      \ +  }                                                                \ +  SCOPED_INTERCEPTOR_RAW(posix_memalign, memptr, alignment, size); \ +  int res = user_posix_memalign(thr, pc, memptr, alignment, size);  #define COMMON_MALLOC_VALLOC(size)                            \    if (cur_thread()->in_symbolizer)                            \      return InternalAlloc(size, nullptr, GetPageSizeCached()); \ diff --git a/lib/tsan/rtl/tsan_mman.cc b/lib/tsan/rtl/tsan_mman.cc index 19680238bf763..b160a9736d5d8 100644 --- a/lib/tsan/rtl/tsan_mman.cc +++ b/lib/tsan/rtl/tsan_mman.cc @@ -12,6 +12,7 @@  //===----------------------------------------------------------------------===//  #include "sanitizer_common/sanitizer_allocator_checks.h"  #include "sanitizer_common/sanitizer_allocator_interface.h" +#include "sanitizer_common/sanitizer_allocator_report.h"  #include "sanitizer_common/sanitizer_common.h"  #include "sanitizer_common/sanitizer_errno.h"  #include "sanitizer_common/sanitizer_placement_new.h" @@ -150,13 +151,24 @@ static void SignalUnsafeCall(ThreadState *thr, uptr pc) {    OutputReport(thr, rep);  } +static constexpr uptr kMaxAllowedMallocSize = 1ull << 40; +  void *user_alloc_internal(ThreadState *thr, uptr pc, uptr sz, uptr align,                            bool signal) { -  if ((sz >= (1ull << 40)) || (align >= (1ull << 40))) -    return Allocator::FailureHandler::OnBadRequest(); +  if (sz >= kMaxAllowedMallocSize || align >= kMaxAllowedMallocSize) { +    if (AllocatorMayReturnNull()) +      return nullptr; +    GET_STACK_TRACE_FATAL(thr, pc); +    ReportAllocationSizeTooBig(sz, kMaxAllowedMallocSize, &stack); +  }    void *p = allocator()->Allocate(&thr->proc()->alloc_cache, sz, align); -  if (UNLIKELY(p == 0)) -    return 0; +  if (UNLIKELY(!p)) { +    SetAllocatorOutOfMemory(); +    if (AllocatorMayReturnNull()) +      return nullptr; +    GET_STACK_TRACE_FATAL(thr, pc); +    ReportOutOfMemory(sz, &stack); +  }    if (ctx && ctx->initialized)      OnUserAlloc(thr, pc, (uptr)p, sz, true);    if (signal) @@ -178,8 +190,12 @@ void *user_alloc(ThreadState *thr, uptr pc, uptr sz) {  }  void *user_calloc(ThreadState *thr, uptr pc, uptr size, uptr n) { -  if (UNLIKELY(CheckForCallocOverflow(size, n))) -    return SetErrnoOnNull(Allocator::FailureHandler::OnBadRequest()); +  if (UNLIKELY(CheckForCallocOverflow(size, n))) { +    if (AllocatorMayReturnNull()) +      return SetErrnoOnNull(nullptr); +    GET_STACK_TRACE_FATAL(thr, pc); +    ReportCallocOverflow(n, size, &stack); +  }    void *p = user_alloc_internal(thr, pc, n * size);    if (p)      internal_memset(p, 0, n * size); @@ -224,7 +240,10 @@ void *user_realloc(ThreadState *thr, uptr pc, void *p, uptr sz) {  void *user_memalign(ThreadState *thr, uptr pc, uptr align, uptr sz) {    if (UNLIKELY(!IsPowerOfTwo(align))) {      errno = errno_EINVAL; -    return Allocator::FailureHandler::OnBadRequest(); +    if (AllocatorMayReturnNull()) +      return nullptr; +    GET_STACK_TRACE_FATAL(thr, pc); +    ReportInvalidAllocationAlignment(align, &stack);    }    return SetErrnoOnNull(user_alloc_internal(thr, pc, sz, align));  } @@ -232,11 +251,14 @@ void *user_memalign(ThreadState *thr, uptr pc, uptr align, uptr sz) {  int user_posix_memalign(ThreadState *thr, uptr pc, void **memptr, uptr align,                          uptr sz) {    if (UNLIKELY(!CheckPosixMemalignAlignment(align))) { -    Allocator::FailureHandler::OnBadRequest(); -    return errno_EINVAL; +    if (AllocatorMayReturnNull()) +      return errno_EINVAL; +    GET_STACK_TRACE_FATAL(thr, pc); +    ReportInvalidPosixMemalignAlignment(align, &stack);    }    void *ptr = user_alloc_internal(thr, pc, sz, align);    if (UNLIKELY(!ptr)) +    // OOM error is already taken care of by user_alloc_internal.      return errno_ENOMEM;    CHECK(IsAligned((uptr)ptr, align));    *memptr = ptr; @@ -246,7 +268,10 @@ int user_posix_memalign(ThreadState *thr, uptr pc, void **memptr, uptr align,  void *user_aligned_alloc(ThreadState *thr, uptr pc, uptr align, uptr sz) {    if (UNLIKELY(!CheckAlignedAllocAlignmentAndSize(align, sz))) {      errno = errno_EINVAL; -    return Allocator::FailureHandler::OnBadRequest(); +    if (AllocatorMayReturnNull()) +      return nullptr; +    GET_STACK_TRACE_FATAL(thr, pc); +    ReportInvalidAlignedAllocAlignment(sz, align, &stack);    }    return SetErrnoOnNull(user_alloc_internal(thr, pc, sz, align));  } @@ -259,7 +284,10 @@ void *user_pvalloc(ThreadState *thr, uptr pc, uptr sz) {    uptr PageSize = GetPageSizeCached();    if (UNLIKELY(CheckForPvallocOverflow(sz, PageSize))) {      errno = errno_ENOMEM; -    return Allocator::FailureHandler::OnBadRequest(); +    if (AllocatorMayReturnNull()) +      return nullptr; +    GET_STACK_TRACE_FATAL(thr, pc); +    ReportPvallocOverflow(sz, &stack);    }    // pvalloc(0) should allocate one page.    sz = sz ? RoundUpTo(sz, PageSize) : PageSize; diff --git a/lib/tsan/rtl/tsan_new_delete.cc b/lib/tsan/rtl/tsan_new_delete.cc index a1bb22690e0f4..4f52d3d71eb66 100644 --- a/lib/tsan/rtl/tsan_new_delete.cc +++ b/lib/tsan/rtl/tsan_new_delete.cc @@ -13,8 +13,10 @@  //===----------------------------------------------------------------------===//  #include "interception/interception.h"  #include "sanitizer_common/sanitizer_allocator.h" +#include "sanitizer_common/sanitizer_allocator_report.h"  #include "sanitizer_common/sanitizer_internal_defs.h"  #include "tsan_interceptors.h" +#include "tsan_rtl.h"  using namespace __tsan;  // NOLINT @@ -34,7 +36,10 @@ DECLARE_REAL(void, free, void *ptr)    {  \      SCOPED_INTERCEPTOR_RAW(mangled_name, size); \      p = user_alloc(thr, pc, size); \ -    if (!nothrow && UNLIKELY(!p)) DieOnFailure::OnOOM(); \ +    if (!nothrow && UNLIKELY(!p)) { \ +      GET_STACK_TRACE_FATAL(thr, pc); \ +      ReportOutOfMemory(size, &stack); \ +    } \    }  \    invoke_malloc_hook(p, size);  \    return p; @@ -46,7 +51,10 @@ DECLARE_REAL(void, free, void *ptr)    {  \      SCOPED_INTERCEPTOR_RAW(mangled_name, size); \      p = user_memalign(thr, pc, (uptr)align, size); \ -    if (!nothrow && UNLIKELY(!p)) DieOnFailure::OnOOM(); \ +    if (!nothrow && UNLIKELY(!p)) { \ +      GET_STACK_TRACE_FATAL(thr, pc); \ +      ReportOutOfMemory(size, &stack); \ +    } \    }  \    invoke_malloc_hook(p, size);  \    return p; diff --git a/lib/tsan/rtl/tsan_platform.h b/lib/tsan/rtl/tsan_platform.h index bfac70df12d9b..6b3e6bac27cb7 100644 --- a/lib/tsan/rtl/tsan_platform.h +++ b/lib/tsan/rtl/tsan_platform.h @@ -79,25 +79,27 @@ struct Mapping {  #define TSAN_MID_APP_RANGE 1  #elif defined(__mips64)  /* -C/C++ on linux/mips64 -0100 0000 00 - 0200 0000 00: main binary -0200 0000 00 - 1400 0000 00: - -1400 0000 00 - 2400 0000 00: shadow -2400 0000 00 - 3000 0000 00: - -3000 0000 00 - 4000 0000 00: metainfo (memory blocks and sync objects) -4000 0000 00 - 6000 0000 00: - -6000 0000 00 - 6200 0000 00: traces -6200 0000 00 - fe00 0000 00: - -fe00 0000 00 - ff00 0000 00: heap -ff00 0000 00 - ff80 0000 00: - -ff80 0000 00 - ffff ffff ff: modules and main thread stack +C/C++ on linux/mips64 (40-bit VMA) +0000 0000 00 - 0100 0000 00: -                                           (4 GB) +0100 0000 00 - 0200 0000 00: main binary                                 (4 GB) +0200 0000 00 - 2000 0000 00: -                                         (120 GB) +2000 0000 00 - 4000 0000 00: shadow                                    (128 GB) +4000 0000 00 - 5000 0000 00: metainfo (memory blocks and sync objects)  (64 GB) +5000 0000 00 - aa00 0000 00: -                                         (360 GB) +aa00 0000 00 - ab00 0000 00: main binary (PIE)                           (4 GB) +ab00 0000 00 - b000 0000 00: -                                          (20 GB) +b000 0000 00 - b200 0000 00: traces                                      (8 GB) +b200 0000 00 - fe00 0000 00: -                                         (304 GB) +fe00 0000 00 - ff00 0000 00: heap                                        (4 GB) +ff00 0000 00 - ff80 0000 00: -                                           (2 GB) +ff80 0000 00 - ffff ffff ff: modules and main thread stack              (<2 GB)  */  struct Mapping {    static const uptr kMetaShadowBeg = 0x4000000000ull;    static const uptr kMetaShadowEnd = 0x5000000000ull;    static const uptr kTraceMemBeg   = 0xb000000000ull;    static const uptr kTraceMemEnd   = 0xb200000000ull; -  static const uptr kShadowBeg     = 0x2400000000ull; +  static const uptr kShadowBeg     = 0x2000000000ull;    static const uptr kShadowEnd     = 0x4000000000ull;    static const uptr kHeapMemBeg    = 0xfe00000000ull;    static const uptr kHeapMemEnd    = 0xff00000000ull; @@ -353,9 +355,9 @@ struct Mapping47 {  #define TSAN_RUNTIME_VMA 1  #endif -#elif SANITIZER_GO && !SANITIZER_WINDOWS +#elif SANITIZER_GO && !SANITIZER_WINDOWS && defined(__x86_64__) -/* Go on linux, darwin and freebsd +/* Go on linux, darwin and freebsd on x86_64  0000 0000 1000 - 0000 1000 0000: executable  0000 1000 0000 - 00c0 0000 0000: -  00c0 0000 0000 - 00e0 0000 0000: heap @@ -404,6 +406,61 @@ struct Mapping {    static const uptr kAppMemEnd     = 0x00e000000000ull;  }; +#elif SANITIZER_GO && defined(__powerpc64__) + +/* Only Mapping46 and Mapping47 are currently supported for powercp64 on Go. */ + +/* Go on linux/powerpc64 (46-bit VMA) +0000 0000 1000 - 0000 1000 0000: executable +0000 1000 0000 - 00c0 0000 0000: - +00c0 0000 0000 - 00e0 0000 0000: heap +00e0 0000 0000 - 2000 0000 0000: - +2000 0000 0000 - 2380 0000 0000: shadow +2380 0000 0000 - 2400 0000 0000: - +2400 0000 0000 - 3400 0000 0000: metainfo (memory blocks and sync objects) +3400 0000 0000 - 3600 0000 0000: - +3600 0000 0000 - 3800 0000 0000: traces +3800 0000 0000 - 4000 0000 0000: - +*/ + +struct Mapping46 { +  static const uptr kMetaShadowBeg = 0x240000000000ull; +  static const uptr kMetaShadowEnd = 0x340000000000ull; +  static const uptr kTraceMemBeg   = 0x360000000000ull; +  static const uptr kTraceMemEnd   = 0x380000000000ull; +  static const uptr kShadowBeg     = 0x200000000000ull; +  static const uptr kShadowEnd     = 0x238000000000ull; +  static const uptr kAppMemBeg     = 0x000000001000ull; +  static const uptr kAppMemEnd     = 0x00e000000000ull; +}; + +/* Go on linux/powerpc64 (47-bit VMA) +0000 0000 1000 - 0000 1000 0000: executable +0000 1000 0000 - 00c0 0000 0000: - +00c0 0000 0000 - 00e0 0000 0000: heap +00e0 0000 0000 - 2000 0000 0000: - +2000 0000 0000 - 3000 0000 0000: shadow +3000 0000 0000 - 3000 0000 0000: - +3000 0000 0000 - 4000 0000 0000: metainfo (memory blocks and sync objects) +4000 0000 0000 - 6000 0000 0000: - +6000 0000 0000 - 6200 0000 0000: traces +6200 0000 0000 - 8000 0000 0000: - +*/ + +struct Mapping47 { +  static const uptr kMetaShadowBeg = 0x300000000000ull; +  static const uptr kMetaShadowEnd = 0x400000000000ull; +  static const uptr kTraceMemBeg   = 0x600000000000ull; +  static const uptr kTraceMemEnd   = 0x620000000000ull; +  static const uptr kShadowBeg     = 0x200000000000ull; +  static const uptr kShadowEnd     = 0x300000000000ull; +  static const uptr kAppMemBeg     = 0x000000001000ull; +  static const uptr kAppMemEnd     = 0x00e000000000ull; +}; + +// Indicates the runtime will define the memory regions at runtime. +#define TSAN_RUNTIME_VMA 1 +  #else  # error "Unknown platform"  #endif @@ -476,7 +533,9 @@ uptr MappingArchImpl(void) {    return 0;  #elif defined(__powerpc64__)    switch (vmaSize) { +#if !SANITIZER_GO      case 44: return MappingImpl<Mapping44, Type>(); +#endif      case 46: return MappingImpl<Mapping46, Type>();      case 47: return MappingImpl<Mapping47, Type>();    } @@ -631,7 +690,9 @@ bool IsAppMem(uptr mem) {    return false;  #elif defined(__powerpc64__)    switch (vmaSize) { +#if !SANITIZER_GO      case 44: return IsAppMemImpl<Mapping44>(mem); +#endif      case 46: return IsAppMemImpl<Mapping46>(mem);      case 47: return IsAppMemImpl<Mapping47>(mem);    } @@ -660,7 +721,9 @@ bool IsShadowMem(uptr mem) {    return false;  #elif defined(__powerpc64__)    switch (vmaSize) { +#if !SANITIZER_GO      case 44: return IsShadowMemImpl<Mapping44>(mem); +#endif      case 46: return IsShadowMemImpl<Mapping46>(mem);      case 47: return IsShadowMemImpl<Mapping47>(mem);    } @@ -689,7 +752,9 @@ bool IsMetaMem(uptr mem) {    return false;  #elif defined(__powerpc64__)    switch (vmaSize) { +#if !SANITIZER_GO      case 44: return IsMetaMemImpl<Mapping44>(mem); +#endif      case 46: return IsMetaMemImpl<Mapping46>(mem);      case 47: return IsMetaMemImpl<Mapping47>(mem);    } @@ -728,7 +793,9 @@ uptr MemToShadow(uptr x) {    return 0;  #elif defined(__powerpc64__)    switch (vmaSize) { +#if !SANITIZER_GO      case 44: return MemToShadowImpl<Mapping44>(x); +#endif      case 46: return MemToShadowImpl<Mapping46>(x);      case 47: return MemToShadowImpl<Mapping47>(x);    } @@ -769,7 +836,9 @@ u32 *MemToMeta(uptr x) {    return 0;  #elif defined(__powerpc64__)    switch (vmaSize) { +#if !SANITIZER_GO      case 44: return MemToMetaImpl<Mapping44>(x); +#endif      case 46: return MemToMetaImpl<Mapping46>(x);      case 47: return MemToMetaImpl<Mapping47>(x);    } @@ -823,7 +892,9 @@ uptr ShadowToMem(uptr s) {    return 0;  #elif defined(__powerpc64__)    switch (vmaSize) { +#if !SANITIZER_GO      case 44: return ShadowToMemImpl<Mapping44>(s); +#endif      case 46: return ShadowToMemImpl<Mapping46>(s);      case 47: return ShadowToMemImpl<Mapping47>(s);    } @@ -860,7 +931,9 @@ uptr GetThreadTrace(int tid) {    return 0;  #elif defined(__powerpc64__)    switch (vmaSize) { +#if !SANITIZER_GO      case 44: return GetThreadTraceImpl<Mapping44>(tid); +#endif      case 46: return GetThreadTraceImpl<Mapping46>(tid);      case 47: return GetThreadTraceImpl<Mapping47>(tid);    } @@ -892,7 +965,9 @@ uptr GetThreadTraceHeader(int tid) {    return 0;  #elif defined(__powerpc64__)    switch (vmaSize) { +#if !SANITIZER_GO      case 44: return GetThreadTraceHeaderImpl<Mapping44>(tid); +#endif      case 46: return GetThreadTraceHeaderImpl<Mapping46>(tid);      case 47: return GetThreadTraceHeaderImpl<Mapping47>(tid);    } diff --git a/lib/tsan/rtl/tsan_platform_linux.cc b/lib/tsan/rtl/tsan_platform_linux.cc index e14d5f575a2e3..de989b7808835 100644 --- a/lib/tsan/rtl/tsan_platform_linux.cc +++ b/lib/tsan/rtl/tsan_platform_linux.cc @@ -168,11 +168,11 @@ static void MapRodata() {    fd_t fd = openrv;    // Fill the file with kShadowRodata.    const uptr kMarkerSize = 512 * 1024 / sizeof(u64); -  InternalScopedBuffer<u64> marker(kMarkerSize); +  InternalMmapVector<u64> marker(kMarkerSize);    // volatile to prevent insertion of memset    for (volatile u64 *p = marker.data(); p < marker.data() + kMarkerSize; p++)      *p = kShadowRodata; -  internal_write(fd, marker.data(), marker.size()); +  internal_write(fd, marker.data(), marker.size() * sizeof(u64));    // Map the file into memory.    uptr page = internal_mmap(0, GetPageSizeCached(), PROT_READ | PROT_WRITE,                              MAP_PRIVATE | MAP_ANONYMOUS, fd, 0); @@ -191,8 +191,9 @@ static void MapRodata() {        // Assume it's .rodata        char *shadow_start = (char *)MemToShadow(segment.start);        char *shadow_end = (char *)MemToShadow(segment.end); -      for (char *p = shadow_start; p < shadow_end; p += marker.size()) { -        internal_mmap(p, Min<uptr>(marker.size(), shadow_end - p), +      for (char *p = shadow_start; p < shadow_end; +           p += marker.size() * sizeof(u64)) { +        internal_mmap(p, Min<uptr>(marker.size() * sizeof(u64), shadow_end - p),                        PROT_READ, MAP_PRIVATE | MAP_FIXED, fd, 0);        }      } @@ -213,15 +214,23 @@ void InitializePlatformEarly() {  #if defined(__aarch64__)    if (vmaSize != 39 && vmaSize != 42 && vmaSize != 48) {      Printf("FATAL: ThreadSanitizer: unsupported VMA range\n"); -    Printf("FATAL: Found %d - Supported 39, 42 and 48\n", vmaSize); +    Printf("FATAL: Found %zd - Supported 39, 42 and 48\n", vmaSize);      Die();    }  #elif defined(__powerpc64__) +# if !SANITIZER_GO    if (vmaSize != 44 && vmaSize != 46 && vmaSize != 47) {      Printf("FATAL: ThreadSanitizer: unsupported VMA range\n"); -    Printf("FATAL: Found %d - Supported 44, 46, and 47\n", vmaSize); +    Printf("FATAL: Found %zd - Supported 44, 46, and 47\n", vmaSize);      Die();    } +# else +  if (vmaSize != 46 && vmaSize != 47) { +    Printf("FATAL: ThreadSanitizer: unsupported VMA range\n"); +    Printf("FATAL: Found %zd - Supported 46, and 47\n", vmaSize); +    Die(); +  } +# endif  #endif  #endif  } diff --git a/lib/tsan/rtl/tsan_platform_posix.cc b/lib/tsan/rtl/tsan_platform_posix.cc index e4f90a811c352..c38dcc7f2c1c1 100644 --- a/lib/tsan/rtl/tsan_platform_posix.cc +++ b/lib/tsan/rtl/tsan_platform_posix.cc @@ -16,6 +16,7 @@  #if SANITIZER_POSIX  #include "sanitizer_common/sanitizer_common.h" +#include "sanitizer_common/sanitizer_errno.h"  #include "sanitizer_common/sanitizer_libc.h"  #include "sanitizer_common/sanitizer_procmaps.h"  #include "tsan_platform.h" @@ -23,16 +24,39 @@  namespace __tsan { +static const char kShadowMemoryMappingWarning[] = +    "FATAL: %s can not madvise shadow region [%zx, %zx] with %s (errno: %d)\n"; +static const char kShadowMemoryMappingHint[] = +    "HINT: if %s is not supported in your environment, you may set " +    "TSAN_OPTIONS=%s=0\n"; + +static void NoHugePagesInShadow(uptr addr, uptr size) { +  if (common_flags()->no_huge_pages_for_shadow) +    if (!NoHugePagesInRegion(addr, size)) { +      Printf(kShadowMemoryMappingWarning, SanitizerToolName, addr, addr + size, +             "MADV_NOHUGEPAGE", errno); +      Printf(kShadowMemoryMappingHint, "MADV_NOHUGEPAGE", +             "no_huge_pages_for_shadow"); +      Die(); +    } +} + +static void DontDumpShadow(uptr addr, uptr size) { +  if (common_flags()->use_madv_dontdump) +    if (!DontDumpShadowMemory(addr, size)) { +      Printf(kShadowMemoryMappingWarning, SanitizerToolName, addr, addr + size, +             "MADV_DONTDUMP", errno); +      Printf(kShadowMemoryMappingHint, "MADV_DONTDUMP", "use_madv_dontdump"); +      Die(); +    } +} +  #if !SANITIZER_GO  void InitializeShadowMemory() {    // Map memory shadow. -  uptr shadow = -      (uptr)MmapFixedNoReserve(ShadowBeg(), ShadowEnd() - ShadowBeg(), -                               "shadow"); -  if (shadow != ShadowBeg()) { +  if (!MmapFixedNoReserve(ShadowBeg(), ShadowEnd() - ShadowBeg(), "shadow")) {      Printf("FATAL: ThreadSanitizer can not mmap the shadow memory\n"); -    Printf("FATAL: Make sure to compile with -fPIE and " -               "to link with -pie (%p, %p).\n", shadow, ShadowBeg()); +    Printf("FATAL: Make sure to compile with -fPIE and to link with -pie.\n");      Die();    }    // This memory range is used for thread stacks and large user mmaps. @@ -74,30 +98,23 @@ void InitializeShadowMemory() {      DCHECK(0);    }  #endif -  NoHugePagesInRegion(MemToShadow(kMadviseRangeBeg), +  NoHugePagesInShadow(MemToShadow(kMadviseRangeBeg),                        kMadviseRangeSize * kShadowMultiplier); -  // Meta shadow is compressing and we don't flush it, -  // so it makes sense to mark it as NOHUGEPAGE to not over-allocate memory. -  // On one program it reduces memory consumption from 5GB to 2.5GB. -  NoHugePagesInRegion(MetaShadowBeg(), MetaShadowEnd() - MetaShadowBeg()); -  if (common_flags()->use_madv_dontdump) -    DontDumpShadowMemory(ShadowBeg(), ShadowEnd() - ShadowBeg()); +  DontDumpShadow(ShadowBeg(), ShadowEnd() - ShadowBeg());    DPrintf("memory shadow: %zx-%zx (%zuGB)\n",        ShadowBeg(), ShadowEnd(),        (ShadowEnd() - ShadowBeg()) >> 30);    // Map meta shadow. -  uptr meta_size = MetaShadowEnd() - MetaShadowBeg(); -  uptr meta = -      (uptr)MmapFixedNoReserve(MetaShadowBeg(), meta_size, "meta shadow"); -  if (meta != MetaShadowBeg()) { +  const uptr meta = MetaShadowBeg(); +  const uptr meta_size = MetaShadowEnd() - meta; +  if (!MmapFixedNoReserve(meta, meta_size, "meta shadow")) {      Printf("FATAL: ThreadSanitizer can not mmap the shadow memory\n"); -    Printf("FATAL: Make sure to compile with -fPIE and " -               "to link with -pie (%p, %p).\n", meta, MetaShadowBeg()); +    Printf("FATAL: Make sure to compile with -fPIE and to link with -pie.\n");      Die();    } -  if (common_flags()->use_madv_dontdump) -    DontDumpShadowMemory(meta, meta_size); +  NoHugePagesInShadow(meta, meta_size); +  DontDumpShadow(meta, meta_size);    DPrintf("meta shadow: %zx-%zx (%zuGB)\n",        meta, meta + meta_size, meta_size >> 30); diff --git a/lib/tsan/rtl/tsan_rtl.cc b/lib/tsan/rtl/tsan_rtl.cc index 17b820977c266..5841222927b32 100644 --- a/lib/tsan/rtl/tsan_rtl.cc +++ b/lib/tsan/rtl/tsan_rtl.cc @@ -105,8 +105,8 @@ Context::Context()    , racy_stacks()    , racy_addresses()    , fired_suppressions_mtx(MutexTypeFired, StatMtxFired) -  , fired_suppressions(8)    , clock_alloc("clock allocator") { +  fired_suppressions.reserve(8);  }  // The objects are allocated in TLS, so one may rely on zero-initialization. @@ -140,7 +140,7 @@ static void MemoryProfiler(Context *ctx, fd_t fd, int i) {    uptr n_threads;    uptr n_running_threads;    ctx->thread_registry->GetNumberOfThreads(&n_threads, &n_running_threads); -  InternalScopedBuffer<char> buf(4096); +  InternalMmapVector<char> buf(4096);    WriteMemoryProfile(buf.data(), buf.size(), n_threads, n_running_threads);    WriteToFile(fd, buf.data(), internal_strlen(buf.data()));  } @@ -246,7 +246,8 @@ void MapShadow(uptr addr, uptr size) {    const uptr kPageSize = GetPageSizeCached();    uptr shadow_begin = RoundDownTo((uptr)MemToShadow(addr), kPageSize);    uptr shadow_end = RoundUpTo((uptr)MemToShadow(addr + size), kPageSize); -  MmapFixedNoReserve(shadow_begin, shadow_end - shadow_begin, "shadow"); +  if (!MmapFixedNoReserve(shadow_begin, shadow_end - shadow_begin, "shadow")) +    Die();    // Meta shadow is 2:1, so tread carefully.    static bool data_mapped = false; @@ -258,7 +259,8 @@ void MapShadow(uptr addr, uptr size) {    if (!data_mapped) {      // First call maps data+bss.      data_mapped = true; -    MmapFixedNoReserve(meta_begin, meta_end - meta_begin, "meta shadow"); +    if (!MmapFixedNoReserve(meta_begin, meta_end - meta_begin, "meta shadow")) +      Die();    } else {      // Mapping continous heap.      // Windows wants 64K alignment. @@ -268,7 +270,8 @@ void MapShadow(uptr addr, uptr size) {        return;      if (meta_begin < mapped_meta_end)        meta_begin = mapped_meta_end; -    MmapFixedNoReserve(meta_begin, meta_end - meta_begin, "meta shadow"); +    if (!MmapFixedNoReserve(meta_begin, meta_end - meta_begin, "meta shadow")) +      Die();      mapped_meta_end = meta_end;    }    VPrintf(2, "mapped meta shadow for (%p-%p) at (%p-%p)\n", @@ -280,10 +283,9 @@ void MapThreadTrace(uptr addr, uptr size, const char *name) {    CHECK_GE(addr, TraceMemBeg());    CHECK_LE(addr + size, TraceMemEnd());    CHECK_EQ(addr, addr & ~((64 << 10) - 1));  // windows wants 64K alignment -  uptr addr1 = (uptr)MmapFixedNoReserve(addr, size, name); -  if (addr1 != addr) { -    Printf("FATAL: ThreadSanitizer can not mmap thread trace (%p/%p->%p)\n", -        addr, size, addr1); +  if (!MmapFixedNoReserve(addr, size, name)) { +    Printf("FATAL: ThreadSanitizer can not mmap thread trace (%p/%p)\n", +        addr, size);      Die();    }  } @@ -354,6 +356,7 @@ void Initialize(ThreadState *thr) {    ctx = new(ctx_placeholder) Context;    const char *options = GetEnv(SANITIZER_GO ? "GORACE" : "TSAN_OPTIONS");    CacheBinaryName(); +  CheckASLR();    InitializeFlags(&ctx->flags, options);    AvoidCVE_2016_2143();    InitializePlatformEarly(); @@ -547,6 +550,10 @@ u32 CurrentStackId(ThreadState *thr, uptr pc) {  }  void TraceSwitch(ThreadState *thr) { +#if !SANITIZER_GO +  if (ctx->after_multithreaded_fork) +    return; +#endif    thr->nomalloc++;    Trace *thr_trace = ThreadTrace(thr->tid);    Lock l(&thr_trace->mtx); @@ -918,7 +925,8 @@ static void MemoryRangeSet(ThreadState *thr, uptr pc, uptr addr, uptr size,      u64 *p1 = p;      p = RoundDown(end, kPageSize);      UnmapOrDie((void*)p1, (uptr)p - (uptr)p1); -    MmapFixedNoReserve((uptr)p1, (uptr)p - (uptr)p1); +    if (!MmapFixedNoReserve((uptr)p1, (uptr)p - (uptr)p1)) +      Die();      // Set the ending.      while (p < end) {        *p++ = val; diff --git a/lib/tsan/rtl/tsan_rtl.h b/lib/tsan/rtl/tsan_rtl.h index 7d44ccae98932..523b69aaa6bc3 100644 --- a/lib/tsan/rtl/tsan_rtl.h +++ b/lib/tsan/rtl/tsan_rtl.h @@ -520,7 +520,9 @@ struct Context {    Context();    bool initialized; +#if !SANITIZER_GO    bool after_multithreaded_fork; +#endif    MetaMap metamap; @@ -648,6 +650,10 @@ void ObtainCurrentStack(ThreadState *thr, uptr toppc, StackTraceTy *stack,    ExtractTagFromStack(stack, tag);  } +#define GET_STACK_TRACE_FATAL(thr, pc) \ +  VarSizeStackTrace stack; \ +  ObtainCurrentStack(thr, pc, &stack); \ +  stack.ReverseOrder();  #if TSAN_COLLECT_STATS  void StatAggregate(u64 *dst, u64 *src); diff --git a/lib/tsan/rtl/tsan_rtl_mutex.cc b/lib/tsan/rtl/tsan_rtl_mutex.cc index 152b965ad5351..c61d02b7a7662 100644 --- a/lib/tsan/rtl/tsan_rtl_mutex.cc +++ b/lib/tsan/rtl/tsan_rtl_mutex.cc @@ -104,7 +104,7 @@ void MutexDestroy(ThreadState *thr, uptr pc, uptr addr, u32 flagz) {      unlock_locked = true;    }    u64 mid = s->GetId(); -  u32 last_lock = s->last_lock; +  u64 last_lock = s->last_lock;    if (!unlock_locked)      s->Reset(thr->proc());  // must not reset it before the report is printed    s->mtx.Unlock(); @@ -114,7 +114,7 @@ void MutexDestroy(ThreadState *thr, uptr pc, uptr addr, u32 flagz) {      rep.AddMutex(mid);      VarSizeStackTrace trace;      ObtainCurrentStack(thr, pc, &trace); -    rep.AddStack(trace); +    rep.AddStack(trace, true);      FastState last(last_lock);      RestoreStack(last.tid(), last.epoch(), &trace, 0);      rep.AddStack(trace, true); @@ -361,7 +361,7 @@ void MutexReadOrWriteUnlock(ThreadState *thr, uptr pc, uptr addr) {      if (s->recursion == 0) {        StatInc(thr, StatMutexUnlock);        s->owner_tid = SyncVar::kInvalidTid; -      ReleaseImpl(thr, pc, &s->clock); +      ReleaseStoreImpl(thr, pc, &s->clock);      } else {        StatInc(thr, StatMutexRecUnlock);      } diff --git a/lib/tsan/rtl/tsan_rtl_report.cc b/lib/tsan/rtl/tsan_rtl_report.cc index cc582ab50190c..febb6cef2d39f 100644 --- a/lib/tsan/rtl/tsan_rtl_report.cc +++ b/lib/tsan/rtl/tsan_rtl_report.cc @@ -649,8 +649,8 @@ void ReportRace(ThreadState *thr) {      // callback. Most likely, TraceTopPC will now return a EventTypeFuncExit      // event. Later we subtract -1 from it (in GetPreviousInstructionPc)      // and the resulting PC has kExternalPCBit set, so we pass it to -    // __tsan_symbolize_external. __tsan_symbolize_external is within its rights -    // to crash since the PC is completely bogus. +    // __tsan_symbolize_external_ex. __tsan_symbolize_external_ex is within its +    // rights to crash since the PC is completely bogus.      // test/tsan/double_race.cc contains a test case for this.      toppc = 0;    } diff --git a/lib/tsan/rtl/tsan_stack_trace.cc b/lib/tsan/rtl/tsan_stack_trace.cc index ceca3f8e8738d..a0dee19e246e2 100644 --- a/lib/tsan/rtl/tsan_stack_trace.cc +++ b/lib/tsan/rtl/tsan_stack_trace.cc @@ -43,4 +43,9 @@ void VarSizeStackTrace::Init(const uptr *pcs, uptr cnt, uptr extra_top_pc) {      trace_buffer[cnt] = extra_top_pc;  } +void VarSizeStackTrace::ReverseOrder() { +  for (u32 i = 0; i < (size >> 1); i++) +    Swap(trace_buffer[i], trace_buffer[size - 1 - i]); +} +  }  // namespace __tsan diff --git a/lib/tsan/rtl/tsan_stack_trace.h b/lib/tsan/rtl/tsan_stack_trace.h index 5bf89bb7584f8..f69b57464bcf3 100644 --- a/lib/tsan/rtl/tsan_stack_trace.h +++ b/lib/tsan/rtl/tsan_stack_trace.h @@ -27,6 +27,10 @@ struct VarSizeStackTrace : public StackTrace {    ~VarSizeStackTrace();    void Init(const uptr *pcs, uptr cnt, uptr extra_top_pc = 0); +  // Reverses the current stack trace order, the top frame goes to the bottom, +  // the last frame goes to the top. +  void ReverseOrder(); +   private:    void ResizeBuffer(uptr new_size); diff --git a/lib/tsan/rtl/tsan_suppressions.cc b/lib/tsan/rtl/tsan_suppressions.cc index e39702b7d22a2..be38f331ad965 100644 --- a/lib/tsan/rtl/tsan_suppressions.cc +++ b/lib/tsan/rtl/tsan_suppressions.cc @@ -152,7 +152,7 @@ uptr IsSuppressed(ReportType typ, const ReportLocation *loc, Suppression **sp) {  }  void PrintMatchedSuppressions() { -  InternalMmapVector<Suppression *> matched(1); +  InternalMmapVector<Suppression *> matched;    CHECK(suppression_ctx);    suppression_ctx->GetMatched(&matched);    if (!matched.size()) diff --git a/lib/tsan/rtl/tsan_symbolize.cc b/lib/tsan/rtl/tsan_symbolize.cc index b2423951795f2..27f0e01c7fbe9 100644 --- a/lib/tsan/rtl/tsan_symbolize.cc +++ b/lib/tsan/rtl/tsan_symbolize.cc @@ -36,6 +36,7 @@ void ExitSymbolizer() {    thr->ignore_interceptors--;  } +// Legacy API.  // May be overriden by JIT/JAVA/etc,  // whatever produces PCs marked with kExternalPCBit.  SANITIZER_WEAK_DEFAULT_IMPL @@ -45,9 +46,49 @@ bool __tsan_symbolize_external(uptr pc, char *func_buf, uptr func_siz,    return false;  } +// New API: call __tsan_symbolize_external_ex only when it exists. +// Once old clients are gone, provide dummy implementation. +SANITIZER_WEAK_DEFAULT_IMPL +void __tsan_symbolize_external_ex(uptr pc, +                                  void (*add_frame)(void *, const char *, +                                                    const char *, int, int), +                                  void *ctx) {} + +struct SymbolizedStackBuilder { +  SymbolizedStack *head; +  SymbolizedStack *tail; +  uptr addr; +}; + +static void AddFrame(void *ctx, const char *function_name, const char *file, +                     int line, int column) { +  SymbolizedStackBuilder *ssb = (struct SymbolizedStackBuilder *)ctx; +  if (ssb->tail) { +    ssb->tail->next = SymbolizedStack::New(ssb->addr); +    ssb->tail = ssb->tail->next; +  } else { +    ssb->head = ssb->tail = SymbolizedStack::New(ssb->addr); +  } +  AddressInfo *info = &ssb->tail->info; +  if (function_name) { +    info->function = internal_strdup(function_name); +  } +  if (file) { +    info->file = internal_strdup(file); +  } +  info->line = line; +  info->column = column; +} +  SymbolizedStack *SymbolizeCode(uptr addr) {    // Check if PC comes from non-native land.    if (addr & kExternalPCBit) { +    SymbolizedStackBuilder ssb = {nullptr, nullptr, addr}; +    __tsan_symbolize_external_ex(addr, AddFrame, &ssb); +    if (ssb.head) +      return ssb.head; +    // Legacy code: remove along with the declaration above +    // once all clients using this API are gone.      // Declare static to not consume too much stack space.      // We symbolize reports in a single thread, so this is fine.      static char func_buf[1024]; diff --git a/lib/tsan/rtl/tsan_sync.cc b/lib/tsan/rtl/tsan_sync.cc index 44ae558fa1b26..ba3953375ee9e 100644 --- a/lib/tsan/rtl/tsan_sync.cc +++ b/lib/tsan/rtl/tsan_sync.cc @@ -176,7 +176,8 @@ void MetaMap::ResetRange(Processor *proc, uptr p, uptr sz) {    uptr metap = (uptr)MemToMeta(p0);    uptr metasz = sz0 / kMetaRatio;    UnmapOrDie((void*)metap, metasz); -  MmapFixedNoReserve(metap, metasz); +  if (!MmapFixedNoReserve(metap, metasz)) +    Die();  }  MBlock* MetaMap::GetBlock(uptr p) { diff --git a/lib/tsan/tests/CMakeLists.txt b/lib/tsan/tests/CMakeLists.txt index ad8d02ed331f3..352319f101092 100644 --- a/lib/tsan/tests/CMakeLists.txt +++ b/lib/tsan/tests/CMakeLists.txt @@ -22,6 +22,8 @@ if(APPLE)      $<TARGET_OBJECTS:RTInterception.osx>      $<TARGET_OBJECTS:RTSanitizerCommon.osx>      $<TARGET_OBJECTS:RTSanitizerCommonLibc.osx> +    $<TARGET_OBJECTS:RTSanitizerCommonCoverage.osx> +    $<TARGET_OBJECTS:RTSanitizerCommonSymbolizer.osx>      $<TARGET_OBJECTS:RTUbsan.osx>)    set(TSAN_TEST_RUNTIME RTTsanTest)    add_library(${TSAN_TEST_RUNTIME} STATIC ${TSAN_TEST_RUNTIME_OBJECTS}) @@ -32,6 +34,7 @@ if(APPLE)    list(APPEND TSAN_UNITTEST_CFLAGS ${DARWIN_osx_CFLAGS})    set(LINK_FLAGS "-lc++") +  list(APPEND LINK_FLAGS ${DARWIN_osx_LINK_FLAGS})    add_weak_symbols("ubsan" LINK_FLAGS)    add_weak_symbols("sanitizer_common" LINK_FLAGS)  else() diff --git a/lib/tsan/tests/unit/tsan_mman_test.cc b/lib/tsan/tests/unit/tsan_mman_test.cc index 05ae4286704c9..26e13a55ce1c3 100644 --- a/lib/tsan/tests/unit/tsan_mman_test.cc +++ b/lib/tsan/tests/unit/tsan_mman_test.cc @@ -153,29 +153,12 @@ TEST(Mman, Valloc) {    EXPECT_NE(p, (void*)0);    EXPECT_EQ(page_size, __sanitizer_get_allocated_size(p));    user_free(thr, 0, p); - -  EXPECT_DEATH(p = user_pvalloc(thr, 0, (uptr)-(page_size - 1)), -               "allocator is terminating the process instead of returning 0"); -  EXPECT_DEATH(p = user_pvalloc(thr, 0, (uptr)-1), -               "allocator is terminating the process instead of returning 0");  }  #if !SANITIZER_DEBUG  // EXPECT_DEATH clones a thread with 4K stack,  // which is overflown by tsan memory accesses functions in debug mode. -TEST(Mman, CallocOverflow) { -  ThreadState *thr = cur_thread(); -  uptr pc = 0; -  size_t kArraySize = 4096; -  volatile size_t kMaxSizeT = std::numeric_limits<size_t>::max(); -  volatile size_t kArraySize2 = kMaxSizeT / kArraySize + 10; -  volatile void *p = NULL; -  EXPECT_DEATH(p = user_calloc(thr, pc, kArraySize, kArraySize2), -               "allocator is terminating the process instead of returning 0"); -  EXPECT_EQ(0L, p); -} -  TEST(Mman, Memalign) {    ThreadState *thr = cur_thread(); @@ -183,12 +166,16 @@ TEST(Mman, Memalign) {    EXPECT_NE(p, (void*)0);    user_free(thr, 0, p); +  // TODO(alekseyshl): Remove this death test when memalign is verified by +  // tests in sanitizer_common.    p = NULL;    EXPECT_DEATH(p = user_memalign(thr, 0, 7, 100), -               "allocator is terminating the process instead of returning 0"); +               "invalid-allocation-alignment");    EXPECT_EQ(0L, p);  } +#endif +  TEST(Mman, PosixMemalign) {    ThreadState *thr = cur_thread(); @@ -197,16 +184,6 @@ TEST(Mman, PosixMemalign) {    EXPECT_NE(p, (void*)0);    EXPECT_EQ(res, 0);    user_free(thr, 0, p); - -  p = NULL; -  // Alignment is not a power of two, although is a multiple of sizeof(void*). -  EXPECT_DEATH(res = user_posix_memalign(thr, 0, &p, 3 * sizeof(p), 100), -               "allocator is terminating the process instead of returning 0"); -  EXPECT_EQ(0L, p); -  // Alignment is not a multiple of sizeof(void*), although is a power of 2. -  EXPECT_DEATH(res = user_posix_memalign(thr, 0, &p, 2, 100), -               "allocator is terminating the process instead of returning 0"); -  EXPECT_EQ(0L, p);  }  TEST(Mman, AlignedAlloc) { @@ -215,18 +192,6 @@ TEST(Mman, AlignedAlloc) {    void *p = user_aligned_alloc(thr, 0, 8, 64);    EXPECT_NE(p, (void*)0);    user_free(thr, 0, p); - -  p = NULL; -  // Alignement is not a power of 2. -  EXPECT_DEATH(p = user_aligned_alloc(thr, 0, 7, 100), -               "allocator is terminating the process instead of returning 0"); -  EXPECT_EQ(0L, p); -  // Size is not a multiple of alignment. -  EXPECT_DEATH(p = user_aligned_alloc(thr, 0, 8, 100), -               "allocator is terminating the process instead of returning 0"); -  EXPECT_EQ(0L, p);  } -#endif -  }  // namespace __tsan diff --git a/lib/ubsan/CMakeLists.txt b/lib/ubsan/CMakeLists.txt index ea4f6e895ec00..ab118ae4a5216 100644 --- a/lib/ubsan/CMakeLists.txt +++ b/lib/ubsan/CMakeLists.txt @@ -5,21 +5,35 @@ set(UBSAN_SOURCES    ubsan_init.cc    ubsan_flags.cc    ubsan_handlers.cc -  ubsan_value.cc -  ) +  ubsan_monitor.cc +  ubsan_value.cc)  set(UBSAN_STANDALONE_SOURCES    ubsan_diag_standalone.cc    ubsan_init_standalone.cc -  ubsan_signals_standalone.cc -  ) +  ubsan_signals_standalone.cc)  set(UBSAN_CXXABI_SOURCES    ubsan_handlers_cxx.cc    ubsan_type_hash.cc    ubsan_type_hash_itanium.cc -  ubsan_type_hash_win.cc -  ) +  ubsan_type_hash_win.cc) + +set(UBSAN_HEADERS +  ubsan_checks.inc +  ubsan_diag.h +  ubsan_flags.h +  ubsan_flags.inc +  ubsan_handlers.h +  ubsan_handlers_cxx.h +  ubsan_init.h +  ubsan_interface.inc +  ubsan_monitor.h +  ubsan_platform.h +  ubsan_signals_standalone.h +  ubsan_type_hash.h +  ubsan_value.h +)  include_directories(..) @@ -55,6 +69,7 @@ if(APPLE)      OS ${SANITIZER_COMMON_SUPPORTED_OS}      ARCHS ${UBSAN_COMMON_SUPPORTED_ARCH}      SOURCES ${UBSAN_COMMON_SOURCES} +    ADDITIONAL_HEADERS ${UBSAN_HEADERS}      CFLAGS ${UBSAN_CXXFLAGS})    if(COMPILER_RT_HAS_UBSAN) @@ -63,6 +78,7 @@ if(APPLE)        OS ${SANITIZER_COMMON_SUPPORTED_OS}        ARCHS ${UBSAN_SUPPORTED_ARCH}        SOURCES ${UBSAN_STANDALONE_SOURCES} +      ADDITIONAL_HEADERS ${UBSAN_HEADERS}        CFLAGS ${UBSAN_STANDALONE_CFLAGS})      add_weak_symbols("ubsan" WEAK_SYMBOL_LINK_FLAGS) @@ -76,6 +92,8 @@ if(APPLE)                    RTUbsan_standalone                    RTSanitizerCommon                    RTSanitizerCommonLibc +                  RTSanitizerCommonCoverage +                  RTSanitizerCommonSymbolizer                    RTInterception        LINK_FLAGS ${WEAK_SYMBOL_LINK_FLAGS}        PARENT_TARGET ubsan) @@ -88,6 +106,8 @@ if(APPLE)                    RTUbsan_standalone                    RTSanitizerCommonNoHooks                    RTSanitizerCommonLibcNoHooks +                  RTSanitizerCommonCoverage +                  RTSanitizerCommonSymbolizerNoHooks                    RTInterception        LINK_FLAGS ${WEAK_SYMBOL_LINK_FLAGS}        PARENT_TARGET ubsan) @@ -97,7 +117,9 @@ else()    # Common parts of UBSan runtime.    add_compiler_rt_object_libraries(RTUbsan      ARCHS ${UBSAN_COMMON_SUPPORTED_ARCH} -    SOURCES ${UBSAN_SOURCES} CFLAGS ${UBSAN_CFLAGS}) +    SOURCES ${UBSAN_SOURCES} +    ADDITIONAL_HEADERS ${UBSAN_HEADERS} +    CFLAGS ${UBSAN_CFLAGS})    if(SANITIZER_CAN_USE_CXXABI)      # C++-specific parts of UBSan runtime. Requires a C++ ABI library. @@ -110,7 +132,9 @@ else()    add_compiler_rt_object_libraries(RTUbsan_cxx      ARCHS ${UBSAN_COMMON_SUPPORTED_ARCH} -    SOURCES ${UBSAN_CXX_SOURCES} CFLAGS ${UBSAN_CXXFLAGS}) +    SOURCES ${UBSAN_CXX_SOURCES} +    ADDITIONAL_HEADERS ${UBSAN_HEADERS} +    CFLAGS ${UBSAN_CXXFLAGS})    if (WIN32)      add_compiler_rt_object_libraries(UbsanWeakInterception @@ -145,14 +169,19 @@ else()      add_compiler_rt_object_libraries(RTUbsan_standalone        ARCHS ${UBSAN_SUPPORTED_ARCH}        SOURCES ${UBSAN_STANDALONE_SOURCES} +      ADDITIONAL_HEADERS ${UBSAN_HEADERS}        CFLAGS ${UBSAN_STANDALONE_CFLAGS})      # Standalone UBSan runtimes.      add_compiler_rt_runtime(clang_rt.ubsan_standalone        STATIC        ARCHS ${UBSAN_SUPPORTED_ARCH} +      SOURCES ubsan_init_standalone_preinit.cc +      ADDITIONAL_HEADERS ${UBSAN_HEADERS}        OBJECT_LIBS RTSanitizerCommon                RTSanitizerCommonLibc +              RTSanitizerCommonCoverage +              RTSanitizerCommonSymbolizer                RTUbsan                RTUbsan_standalone                RTInterception @@ -166,12 +195,14 @@ else()        CFLAGS ${UBSAN_CXXFLAGS}        PARENT_TARGET ubsan) -    if (UNIX) +    if (FUCHSIA OR UNIX)        add_compiler_rt_runtime(clang_rt.ubsan_standalone          SHARED          ARCHS ${UBSAN_SUPPORTED_ARCH}          OBJECT_LIBS RTSanitizerCommon                RTSanitizerCommonLibc +              RTSanitizerCommonCoverage +              RTSanitizerCommonSymbolizer                RTUbsan                RTUbsan_cxx                RTUbsan_standalone diff --git a/lib/ubsan/ubsan_diag.cc b/lib/ubsan/ubsan_diag.cc index d5b68407bb375..df4f13cbe2f59 100644 --- a/lib/ubsan/ubsan_diag.cc +++ b/lib/ubsan/ubsan_diag.cc @@ -16,6 +16,7 @@  #include "ubsan_diag.h"  #include "ubsan_init.h"  #include "ubsan_flags.h" +#include "ubsan_monitor.h"  #include "sanitizer_common/sanitizer_placement_new.h"  #include "sanitizer_common/sanitizer_report_decorator.h"  #include "sanitizer_common/sanitizer_stacktrace.h" @@ -340,6 +341,13 @@ Diag::~Diag() {    Decorator Decor;    InternalScopedString Buffer(1024); +  // Prepare a report that a monitor process can inspect. +  if (Level == DL_Error) { +    RenderText(&Buffer, Message, Args); +    UndefinedBehaviorReport UBR{ConvertTypeToString(ET), Loc, Buffer}; +    Buffer.clear(); +  } +    Buffer.append(Decor.Bold());    RenderLocation(&Buffer, Loc);    Buffer.append(":"); diff --git a/lib/ubsan/ubsan_diag.h b/lib/ubsan/ubsan_diag.h index 7370b1b62421b..d9ea410c358ca 100644 --- a/lib/ubsan/ubsan_diag.h +++ b/lib/ubsan/ubsan_diag.h @@ -121,6 +121,12 @@ public:    const char *getName() const { return Name; }  }; +enum class ErrorType { +#define UBSAN_CHECK(Name, SummaryKind, FSanitizeFlagName) Name, +#include "ubsan_checks.inc" +#undef UBSAN_CHECK +}; +  /// \brief Representation of an in-flight diagnostic.  ///  /// Temporary \c Diag instances are created by the handler routines to @@ -133,6 +139,9 @@ class Diag {    /// The diagnostic level.    DiagLevel Level; +  /// The error type. +  ErrorType ET; +    /// The message which will be emitted, with %0, %1, ... placeholders for    /// arguments.    const char *Message; @@ -197,8 +206,9 @@ private:    Diag &operator=(const Diag &);  public: -  Diag(Location Loc, DiagLevel Level, const char *Message) -    : Loc(Loc), Level(Level), Message(Message), NumArgs(0), NumRanges(0) {} +  Diag(Location Loc, DiagLevel Level, ErrorType ET, const char *Message) +      : Loc(Loc), Level(Level), ET(ET), Message(Message), NumArgs(0), +        NumRanges(0) {}    ~Diag();    Diag &operator<<(const char *Str) { return AddArg(Str); } @@ -219,12 +229,6 @@ struct ReportOptions {    uptr bp;  }; -enum class ErrorType { -#define UBSAN_CHECK(Name, SummaryKind, FSanitizeFlagName) Name, -#include "ubsan_checks.inc" -#undef UBSAN_CHECK -}; -  bool ignoreReport(SourceLocation SLoc, ReportOptions Opts, ErrorType ET);  #define GET_REPORT_OPTIONS(unrecoverable_handler) \ diff --git a/lib/ubsan/ubsan_flags.cc b/lib/ubsan/ubsan_flags.cc index c4fb278c83674..7b6784b8278f6 100644 --- a/lib/ubsan/ubsan_flags.cc +++ b/lib/ubsan/ubsan_flags.cc @@ -26,6 +26,15 @@ const char *MaybeCallUbsanDefaultOptions() {    return (&__ubsan_default_options) ? __ubsan_default_options() : "";  } +static const char *GetFlag(const char *flag) { +  // We cannot call getenv() from inside a preinit array initializer +  if (SANITIZER_CAN_USE_PREINIT_ARRAY) { +    return GetEnv(flag); +  } else { +    return getenv(flag); +  } +} +  Flags ubsan_flags;  void Flags::SetDefaults() { @@ -47,7 +56,7 @@ void InitializeFlags() {      CommonFlags cf;      cf.CopyFrom(*common_flags());      cf.print_summary = false; -    cf.external_symbolizer_path = getenv("UBSAN_SYMBOLIZER_PATH"); +    cf.external_symbolizer_path = GetFlag("UBSAN_SYMBOLIZER_PATH");      OverrideCommonFlags(cf);    } @@ -61,7 +70,7 @@ void InitializeFlags() {    // Override from user-specified string.    parser.ParseString(MaybeCallUbsanDefaultOptions());    // Override from environment variable. -  parser.ParseString(getenv("UBSAN_OPTIONS")); +  parser.ParseString(GetFlag("UBSAN_OPTIONS"));    InitializeCommonFlags();    if (Verbosity()) ReportUnrecognizedFlags(); diff --git a/lib/ubsan/ubsan_flags.inc b/lib/ubsan/ubsan_flags.inc index d171a98e17309..1638a054e8f0d 100644 --- a/lib/ubsan/ubsan_flags.inc +++ b/lib/ubsan/ubsan_flags.inc @@ -24,3 +24,6 @@ UBSAN_FLAG(bool, print_stacktrace, false,  UBSAN_FLAG(const char *, suppressions, "", "Suppressions file name.")  UBSAN_FLAG(bool, report_error_type, false,          "Print specific error type instead of 'undefined-behavior' in summary.") +UBSAN_FLAG(bool, silence_unsigned_overflow, false, +	"Do not print error reports for unsigned integer overflow. " +	"Used to provide fuzzing signal without blowing up logs.") diff --git a/lib/ubsan/ubsan_handlers.cc b/lib/ubsan/ubsan_handlers.cc index bcda746a1783c..49c6bcacbe277 100644 --- a/lib/ubsan/ubsan_handlers.cc +++ b/lib/ubsan/ubsan_handlers.cc @@ -15,6 +15,8 @@  #if CAN_SANITIZE_UB  #include "ubsan_handlers.h"  #include "ubsan_diag.h" +#include "ubsan_flags.h" +#include "ubsan_monitor.h"  #include "sanitizer_common/sanitizer_common.h" @@ -70,17 +72,17 @@ static void handleTypeMismatchImpl(TypeMismatchData *Data, ValueHandle Pointer,    switch (ET) {    case ErrorType::NullPointerUse: -    Diag(Loc, DL_Error, "%0 null pointer of type %1") +    Diag(Loc, DL_Error, ET, "%0 null pointer of type %1")          << TypeCheckKinds[Data->TypeCheckKind] << Data->Type;      break;    case ErrorType::MisalignedPointerUse: -    Diag(Loc, DL_Error, "%0 misaligned address %1 for type %3, " +    Diag(Loc, DL_Error, ET, "%0 misaligned address %1 for type %3, "                          "which requires %2 byte alignment")          << TypeCheckKinds[Data->TypeCheckKind] << (void *)Pointer << Alignment          << Data->Type;      break;    case ErrorType::InsufficientObjectSize: -    Diag(Loc, DL_Error, "%0 address %1 with insufficient space " +    Diag(Loc, DL_Error, ET, "%0 address %1 with insufficient space "                          "for an object of type %2")          << TypeCheckKinds[Data->TypeCheckKind] << (void *)Pointer << Data->Type;      break; @@ -89,7 +91,7 @@ static void handleTypeMismatchImpl(TypeMismatchData *Data, ValueHandle Pointer,    }    if (Pointer) -    Diag(Pointer, DL_Note, "pointer points here"); +    Diag(Pointer, DL_Note, ET, "pointer points here");  }  void __ubsan::__ubsan_handle_type_mismatch_v1(TypeMismatchData *Data, @@ -117,12 +119,15 @@ static void handleIntegerOverflowImpl(OverflowData *Data, ValueHandle LHS,    if (ignoreReport(Loc, Opts, ET))      return; +  if (!IsSigned && flags()->silence_unsigned_overflow) +    return; +    ScopedReport R(Opts, Loc, ET); -  Diag(Loc, DL_Error, "%0 integer overflow: " -                      "%1 %2 %3 cannot be represented in type %4") -    << (IsSigned ? "signed" : "unsigned") -    << Value(Data->Type, LHS) << Operator << RHS << Data->Type; +  Diag(Loc, DL_Error, ET, "%0 integer overflow: " +                          "%1 %2 %3 cannot be represented in type %4") +      << (IsSigned ? "signed" : "unsigned") << Value(Data->Type, LHS) +      << Operator << RHS << Data->Type;  }  #define UBSAN_OVERFLOW_HANDLER(handler_name, op, unrecoverable)                \ @@ -151,15 +156,18 @@ static void handleNegateOverflowImpl(OverflowData *Data, ValueHandle OldVal,    if (ignoreReport(Loc, Opts, ET))      return; +  if (!IsSigned && flags()->silence_unsigned_overflow) +    return; +    ScopedReport R(Opts, Loc, ET);    if (IsSigned) -    Diag(Loc, DL_Error, +    Diag(Loc, DL_Error, ET,           "negation of %0 cannot be represented in type %1; "           "cast to an unsigned type to negate this value to itself")          << Value(Data->Type, OldVal) << Data->Type;    else -    Diag(Loc, DL_Error, "negation of %0 cannot be represented in type %1") +    Diag(Loc, DL_Error, ET, "negation of %0 cannot be represented in type %1")          << Value(Data->Type, OldVal) << Data->Type;  } @@ -196,11 +204,12 @@ static void handleDivremOverflowImpl(OverflowData *Data, ValueHandle LHS,    switch (ET) {    case ErrorType::SignedIntegerOverflow: -    Diag(Loc, DL_Error, "division of %0 by -1 cannot be represented in type %1") +    Diag(Loc, DL_Error, ET, +         "division of %0 by -1 cannot be represented in type %1")          << LHSVal << Data->Type;      break;    default: -    Diag(Loc, DL_Error, "division by zero"); +    Diag(Loc, DL_Error, ET, "division by zero");      break;    }  } @@ -239,15 +248,16 @@ static void handleShiftOutOfBoundsImpl(ShiftOutOfBoundsData *Data,    if (ET == ErrorType::InvalidShiftExponent) {      if (RHSVal.isNegative()) -      Diag(Loc, DL_Error, "shift exponent %0 is negative") << RHSVal; +      Diag(Loc, DL_Error, ET, "shift exponent %0 is negative") << RHSVal;      else -      Diag(Loc, DL_Error, "shift exponent %0 is too large for %1-bit type %2") +      Diag(Loc, DL_Error, ET, +           "shift exponent %0 is too large for %1-bit type %2")            << RHSVal << Data->LHSType.getIntegerBitWidth() << Data->LHSType;    } else {      if (LHSVal.isNegative()) -      Diag(Loc, DL_Error, "left shift of negative value %0") << LHSVal; +      Diag(Loc, DL_Error, ET, "left shift of negative value %0") << LHSVal;      else -      Diag(Loc, DL_Error, +      Diag(Loc, DL_Error, ET,             "left shift of %0 by %1 places cannot be represented in type %2")            << LHSVal << RHSVal << Data->LHSType;    } @@ -279,7 +289,7 @@ static void handleOutOfBoundsImpl(OutOfBoundsData *Data, ValueHandle Index,    ScopedReport R(Opts, Loc, ET);    Value IndexVal(Data->IndexType, Index); -  Diag(Loc, DL_Error, "index %0 out of bounds for type %1") +  Diag(Loc, DL_Error, ET, "index %0 out of bounds for type %1")      << IndexVal << Data->ArrayType;  } @@ -297,8 +307,10 @@ void __ubsan::__ubsan_handle_out_of_bounds_abort(OutOfBoundsData *Data,  static void handleBuiltinUnreachableImpl(UnreachableData *Data,                                           ReportOptions Opts) { -  ScopedReport R(Opts, Data->Loc, ErrorType::UnreachableCall); -  Diag(Data->Loc, DL_Error, "execution reached an unreachable program point"); +  ErrorType ET = ErrorType::UnreachableCall; +  ScopedReport R(Opts, Data->Loc, ET); +  Diag(Data->Loc, DL_Error, ET, +       "execution reached an unreachable program point");  }  void __ubsan::__ubsan_handle_builtin_unreachable(UnreachableData *Data) { @@ -308,8 +320,9 @@ void __ubsan::__ubsan_handle_builtin_unreachable(UnreachableData *Data) {  }  static void handleMissingReturnImpl(UnreachableData *Data, ReportOptions Opts) { -  ScopedReport R(Opts, Data->Loc, ErrorType::MissingReturn); -  Diag(Data->Loc, DL_Error, +  ErrorType ET = ErrorType::MissingReturn; +  ScopedReport R(Opts, Data->Loc, ET); +  Diag(Data->Loc, DL_Error, ET,         "execution reached the end of a value-returning function "         "without returning a value");  } @@ -330,9 +343,9 @@ static void handleVLABoundNotPositive(VLABoundData *Data, ValueHandle Bound,    ScopedReport R(Opts, Loc, ET); -  Diag(Loc, DL_Error, "variable length array bound evaluates to " -                      "non-positive value %0") -    << Value(Data->Type, Bound); +  Diag(Loc, DL_Error, ET, "variable length array bound evaluates to " +                          "non-positive value %0") +      << Value(Data->Type, Bound);  }  void __ubsan::__ubsan_handle_vla_bound_not_positive(VLABoundData *Data, @@ -390,7 +403,7 @@ static void handleFloatCastOverflow(void *DataPtr, ValueHandle From,    ScopedReport R(Opts, Loc, ET); -  Diag(Loc, DL_Error, +  Diag(Loc, DL_Error, ET,         "%0 is outside the range of representable values of type %2")        << Value(*FromType, From) << *FromType << *ToType;  } @@ -421,9 +434,9 @@ static void handleLoadInvalidValue(InvalidValueData *Data, ValueHandle Val,    ScopedReport R(Opts, Loc, ET); -  Diag(Loc, DL_Error, +  Diag(Loc, DL_Error, ET,         "load of value %0, which is not a valid value for type %1") -    << Value(Data->Type, Val) << Data->Type; +      << Value(Data->Type, Val) << Data->Type;  }  void __ubsan::__ubsan_handle_load_invalid_value(InvalidValueData *Data, @@ -447,7 +460,7 @@ static void handleInvalidBuiltin(InvalidBuiltinData *Data, ReportOptions Opts) {    ScopedReport R(Opts, Loc, ET); -  Diag(Loc, DL_Error, +  Diag(Loc, DL_Error, ET,         "passing zero to %0, which is not a valid argument")      << ((Data->Kind == BCK_CTZPassedZero) ? "ctz()" : "clz()");  } @@ -478,10 +491,10 @@ static void handleFunctionTypeMismatch(FunctionTypeMismatchData *Data,    if (!FName)      FName = "(unknown)"; -  Diag(CallLoc, DL_Error, +  Diag(CallLoc, DL_Error, ET,         "call to function %0 through pointer to incorrect function type %1")        << FName << Data->Type; -  Diag(FLoc, DL_Note, "%0 defined here") << FName; +  Diag(FLoc, DL_Note, ET, "%0 defined here") << FName;  }  void @@ -511,10 +524,10 @@ static void handleNonNullReturn(NonNullReturnData *Data, SourceLocation *LocPtr,    ScopedReport R(Opts, Loc, ET); -  Diag(Loc, DL_Error, "null pointer returned from function declared to never " -                      "return null"); +  Diag(Loc, DL_Error, ET, +       "null pointer returned from function declared to never return null");    if (!Data->AttrLoc.isInvalid()) -    Diag(Data->AttrLoc, DL_Note, "%0 specified here") +    Diag(Data->AttrLoc, DL_Note, ET, "%0 specified here")          << (IsAttr ? "returns_nonnull attribute"                     : "_Nonnull return type annotation");  } @@ -555,12 +568,12 @@ static void handleNonNullArg(NonNullArgData *Data, ReportOptions Opts,    ScopedReport R(Opts, Loc, ET); -  Diag(Loc, DL_Error, +  Diag(Loc, DL_Error, ET,         "null pointer passed as argument %0, which is declared to "         "never be null")        << Data->ArgIndex;    if (!Data->AttrLoc.isInvalid()) -    Diag(Data->AttrLoc, DL_Note, "%0 specified here") +    Diag(Data->AttrLoc, DL_Note, ET, "%0 specified here")          << (IsAttr ? "nonnull attribute" : "_Nonnull type annotation");  } @@ -600,14 +613,15 @@ static void handlePointerOverflowImpl(PointerOverflowData *Data,    if ((sptr(Base) >= 0) == (sptr(Result) >= 0)) {      if (Base > Result) -      Diag(Loc, DL_Error, "addition of unsigned offset to %0 overflowed to %1") +      Diag(Loc, DL_Error, ET, +           "addition of unsigned offset to %0 overflowed to %1")            << (void *)Base << (void *)Result;      else -      Diag(Loc, DL_Error, +      Diag(Loc, DL_Error, ET,             "subtraction of unsigned offset from %0 overflowed to %1")            << (void *)Base << (void *)Result;    } else { -    Diag(Loc, DL_Error, +    Diag(Loc, DL_Error, ET,           "pointer index expression with base %0 overflowed to %1")          << (void *)Base << (void *)Result;    } @@ -630,7 +644,7 @@ void __ubsan::__ubsan_handle_pointer_overflow_abort(PointerOverflowData *Data,  static void handleCFIBadIcall(CFICheckFailData *Data, ValueHandle Function,                                ReportOptions Opts) { -  if (Data->CheckKind != CFITCK_ICall) +  if (Data->CheckKind != CFITCK_ICall && Data->CheckKind != CFITCK_NVMFCall)      Die();    SourceLocation Loc = Data->Loc.acquire(); @@ -641,15 +655,33 @@ static void handleCFIBadIcall(CFICheckFailData *Data, ValueHandle Function,    ScopedReport R(Opts, Loc, ET); -  Diag(Loc, DL_Error, "control flow integrity check for type %0 failed during " -                      "indirect function call") -      << Data->Type; +  const char *CheckKindStr = Data->CheckKind == CFITCK_NVMFCall +                                 ? "non-virtual pointer to member function call" +                                 : "indirect function call"; +  Diag(Loc, DL_Error, ET, +       "control flow integrity check for type %0 failed during %1") +      << Data->Type << CheckKindStr;    SymbolizedStackHolder FLoc(getSymbolizedLocation(Function));    const char *FName = FLoc.get()->info.function;    if (!FName)      FName = "(unknown)"; -  Diag(FLoc, DL_Note, "%0 defined here") << FName; +  Diag(FLoc, DL_Note, ET, "%0 defined here") << FName; + +  // If the failure involved different DSOs for the check location and icall +  // target, report the DSO names. +  const char *DstModule = FLoc.get()->info.module; +  if (!DstModule) +    DstModule = "(unknown)"; + +  const char *SrcModule = Symbolizer::GetOrInit()->GetModuleNameForPc(Opts.pc); +  if (!SrcModule) +    SrcModule = "(unknown)"; + +  if (internal_strcmp(SrcModule, DstModule)) +    Diag(Loc, DL_Note, ET, +         "check failed in %0, destination function located in %1") +        << SrcModule << DstModule;  }  namespace __ubsan { @@ -685,7 +717,7 @@ void __ubsan::__ubsan_handle_cfi_check_fail(CFICheckFailData *Data,                                              ValueHandle Value,                                              uptr ValidVtable) {    GET_REPORT_OPTIONS(false); -  if (Data->CheckKind == CFITCK_ICall) +  if (Data->CheckKind == CFITCK_ICall || Data->CheckKind == CFITCK_NVMFCall)      handleCFIBadIcall(Data, Value, Opts);    else      __ubsan_handle_cfi_bad_type(Data, Value, ValidVtable, Opts); @@ -695,7 +727,7 @@ void __ubsan::__ubsan_handle_cfi_check_fail_abort(CFICheckFailData *Data,                                                    ValueHandle Value,                                                    uptr ValidVtable) {    GET_REPORT_OPTIONS(true); -  if (Data->CheckKind == CFITCK_ICall) +  if (Data->CheckKind == CFITCK_ICall || Data->CheckKind == CFITCK_NVMFCall)      handleCFIBadIcall(Data, Value, Opts);    else      __ubsan_handle_cfi_bad_type(Data, Value, ValidVtable, Opts); diff --git a/lib/ubsan/ubsan_handlers.h b/lib/ubsan/ubsan_handlers.h index 311776b9f22c5..ed3c8f0b1b0ef 100644 --- a/lib/ubsan/ubsan_handlers.h +++ b/lib/ubsan/ubsan_handlers.h @@ -181,6 +181,8 @@ enum CFITypeCheckKind : unsigned char {    CFITCK_DerivedCast,    CFITCK_UnrelatedCast,    CFITCK_ICall, +  CFITCK_NVMFCall, +  CFITCK_VMFCall,  };  struct CFICheckFailData { diff --git a/lib/ubsan/ubsan_handlers_cxx.cc b/lib/ubsan/ubsan_handlers_cxx.cc index e15abc64ecca1..85a3e8dad4c55 100644 --- a/lib/ubsan/ubsan_handlers_cxx.cc +++ b/lib/ubsan/ubsan_handlers_cxx.cc @@ -50,29 +50,30 @@ static bool HandleDynamicTypeCacheMiss(    ScopedReport R(Opts, Loc, ET); -  Diag(Loc, DL_Error, +  Diag(Loc, DL_Error, ET,         "%0 address %1 which does not point to an object of type %2")      << TypeCheckKinds[Data->TypeCheckKind] << (void*)Pointer << Data->Type;    // If possible, say what type it actually points to.    if (!DTI.isValid()) {      if (DTI.getOffset() < -VptrMaxOffsetToTop || DTI.getOffset() > VptrMaxOffsetToTop) { -      Diag(Pointer, DL_Note, "object has a possibly invalid vptr: abs(offset to top) too big") +      Diag(Pointer, DL_Note, ET, +           "object has a possibly invalid vptr: abs(offset to top) too big")            << TypeName(DTI.getMostDerivedTypeName())            << Range(Pointer, Pointer + sizeof(uptr), "possibly invalid vptr");      } else { -      Diag(Pointer, DL_Note, "object has invalid vptr") +      Diag(Pointer, DL_Note, ET, "object has invalid vptr")            << TypeName(DTI.getMostDerivedTypeName())            << Range(Pointer, Pointer + sizeof(uptr), "invalid vptr");      }    } else if (!DTI.getOffset()) -    Diag(Pointer, DL_Note, "object is of type %0") +    Diag(Pointer, DL_Note, ET, "object is of type %0")          << TypeName(DTI.getMostDerivedTypeName())          << Range(Pointer, Pointer + sizeof(uptr), "vptr for %0");    else      // FIXME: Find the type at the specified offset, and include that      //        in the note. -    Diag(Pointer - DTI.getOffset(), DL_Note, +    Diag(Pointer - DTI.getOffset(), DL_Note, ET,           "object is base class subobject at offset %0 within object of type %1")          << DTI.getOffset() << TypeName(DTI.getMostDerivedTypeName())          << TypeName(DTI.getSubobjectTypeName()) @@ -122,25 +123,39 @@ void __ubsan_handle_cfi_bad_type(CFICheckFailData *Data, ValueHandle Vtable,    case CFITCK_UnrelatedCast:      CheckKindStr = "cast to unrelated type";      break; +  case CFITCK_VMFCall: +    CheckKindStr = "virtual pointer to member function call"; +    break;    case CFITCK_ICall: +  case CFITCK_NVMFCall:      Die();    } -  Diag(Loc, DL_Error, "control flow integrity check for type %0 failed during " -                      "%1 (vtable address %2)") +  Diag(Loc, DL_Error, ET, +       "control flow integrity check for type %0 failed during " +       "%1 (vtable address %2)")        << Data->Type << CheckKindStr << (void *)Vtable;    // If possible, say what type it actually points to. -  if (!DTI.isValid()) { -    const char *module = Symbolizer::GetOrInit()->GetModuleNameForPc(Vtable); -    if (module) -      Diag(Vtable, DL_Note, "invalid vtable in module %0") << module; -    else -      Diag(Vtable, DL_Note, "invalid vtable"); -  } else { -    Diag(Vtable, DL_Note, "vtable is of type %0") +  if (!DTI.isValid()) +    Diag(Vtable, DL_Note, ET, "invalid vtable"); +  else +    Diag(Vtable, DL_Note, ET, "vtable is of type %0")          << TypeName(DTI.getMostDerivedTypeName()); -  } + +  // If the failure involved different DSOs for the check location and vtable, +  // report the DSO names. +  const char *DstModule = Symbolizer::GetOrInit()->GetModuleNameForPc(Vtable); +  if (!DstModule) +    DstModule = "(unknown)"; + +  const char *SrcModule = Symbolizer::GetOrInit()->GetModuleNameForPc(Opts.pc); +  if (!SrcModule) +    SrcModule = "(unknown)"; + +  if (internal_strcmp(SrcModule, DstModule)) +    Diag(Loc, DL_Note, ET, "check failed in %0, vtable located in %1") +        << SrcModule << DstModule;  }  }  // namespace __ubsan diff --git a/lib/ubsan/ubsan_init_standalone_preinit.cc b/lib/ubsan/ubsan_init_standalone_preinit.cc new file mode 100644 index 0000000000000..5e75c17ae79ac --- /dev/null +++ b/lib/ubsan/ubsan_init_standalone_preinit.cc @@ -0,0 +1,36 @@ +//===-- ubsan_init_standalone_preinit.cc ---------------------------------===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Initialization of standalone UBSan runtime. +// +//===----------------------------------------------------------------------===// + +#include "ubsan_platform.h" +#if !CAN_SANITIZE_UB +#error "UBSan is not supported on this platform!" +#endif + +#include "sanitizer_common/sanitizer_internal_defs.h" +#include "ubsan_init.h" +#include "ubsan_signals_standalone.h" + +#if SANITIZER_CAN_USE_PREINIT_ARRAY + +namespace __ubsan { + +static void PreInitAsStandalone() { +  InitAsStandalone(); +  InitializeDeadlySignals(); +} + +} // namespace __ubsan + +__attribute__((section(".preinit_array"), used)) void (*__local_ubsan_preinit)( +    void) = __ubsan::PreInitAsStandalone; +#endif // SANITIZER_CAN_USE_PREINIT_ARRAY diff --git a/lib/ubsan/ubsan_interface.inc b/lib/ubsan/ubsan_interface.inc index 9beb3e2ff9530..782c621a2b47c 100644 --- a/lib/ubsan/ubsan_interface.inc +++ b/lib/ubsan/ubsan_interface.inc @@ -52,3 +52,5 @@ INTERFACE_FUNCTION(__ubsan_handle_type_mismatch_v1_abort)  INTERFACE_FUNCTION(__ubsan_handle_vla_bound_not_positive)  INTERFACE_FUNCTION(__ubsan_handle_vla_bound_not_positive_abort)  INTERFACE_WEAK_FUNCTION(__ubsan_default_options) +INTERFACE_FUNCTION(__ubsan_on_report) +INTERFACE_FUNCTION(__ubsan_get_current_report_data) diff --git a/lib/ubsan/ubsan_monitor.cc b/lib/ubsan/ubsan_monitor.cc new file mode 100644 index 0000000000000..e2b39845ce3c2 --- /dev/null +++ b/lib/ubsan/ubsan_monitor.cc @@ -0,0 +1,76 @@ +//===-- ubsan_monitor.cc ----------------------------------------*- C++ -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Hooks which allow a monitor process to inspect UBSan's diagnostics. +// +//===----------------------------------------------------------------------===// + +#include "ubsan_monitor.h" + +using namespace __ubsan; + +UndefinedBehaviorReport::UndefinedBehaviorReport(const char *IssueKind, +                                                 Location &Loc, +                                                 InternalScopedString &Msg) +    : IssueKind(IssueKind), Loc(Loc), Buffer(Msg.length() + 1) { +  // We have the common sanitizer reporting lock, so it's safe to register a +  // new UB report. +  RegisterUndefinedBehaviorReport(this); + +  // Make a copy of the diagnostic. +  Buffer.append("%s", Msg.data()); + +  // Let the monitor know that a report is available. +  __ubsan_on_report(); +} + +static UndefinedBehaviorReport *CurrentUBR; + +void __ubsan::RegisterUndefinedBehaviorReport(UndefinedBehaviorReport *UBR) { +  CurrentUBR = UBR; +} + +SANITIZER_WEAK_DEFAULT_IMPL +void __ubsan::__ubsan_on_report(void) {} + +void __ubsan::__ubsan_get_current_report_data(const char **OutIssueKind, +                                              const char **OutMessage, +                                              const char **OutFilename, +                                              unsigned *OutLine, +                                              unsigned *OutCol, +                                              char **OutMemoryAddr) { +  if (!OutIssueKind || !OutMessage || !OutFilename || !OutLine || !OutCol || +      !OutMemoryAddr) +    UNREACHABLE("Invalid arguments passed to __ubsan_get_current_report_data"); + +  InternalScopedString &Buf = CurrentUBR->Buffer; + +  // Ensure that the first character of the diagnostic text can't start with a +  // lowercase letter. +  char FirstChar = Buf.data()[0]; +  if (FirstChar >= 'a' && FirstChar <= 'z') +    Buf.data()[0] = FirstChar - 'a' + 'A'; + +  *OutIssueKind = CurrentUBR->IssueKind; +  *OutMessage = Buf.data(); +  if (!CurrentUBR->Loc.isSourceLocation()) { +    *OutFilename = "<unknown>"; +    *OutLine = *OutCol = 0; +  } else { +    SourceLocation SL = CurrentUBR->Loc.getSourceLocation(); +    *OutFilename = SL.getFilename(); +    *OutLine = SL.getLine(); +    *OutCol = SL.getColumn(); +  } + +  if (CurrentUBR->Loc.isMemoryLocation()) +    *OutMemoryAddr = (char *)CurrentUBR->Loc.getMemoryLocation(); +  else +    *OutMemoryAddr = nullptr; +} diff --git a/lib/ubsan/ubsan_monitor.h b/lib/ubsan/ubsan_monitor.h new file mode 100644 index 0000000000000..7159cbb2c5874 --- /dev/null +++ b/lib/ubsan/ubsan_monitor.h @@ -0,0 +1,49 @@ +//===-- ubsan_monitor.h -----------------------------------------*- C++ -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Hooks which allow a monitor process to inspect UBSan's diagnostics. +// +//===----------------------------------------------------------------------===// + +#ifndef UBSAN_MONITOR_H +#define UBSAN_MONITOR_H + +#include "ubsan_diag.h" +#include "ubsan_value.h" + +namespace __ubsan { + +struct UndefinedBehaviorReport { +  const char *IssueKind; +  Location &Loc; +  InternalScopedString Buffer; + +  UndefinedBehaviorReport(const char *IssueKind, Location &Loc, +                          InternalScopedString &Msg); +}; + +SANITIZER_INTERFACE_ATTRIBUTE void +RegisterUndefinedBehaviorReport(UndefinedBehaviorReport *UBR); + +/// Called after a report is prepared. This serves to alert monitor processes +/// that a UB report is available. +extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __ubsan_on_report(void); + +/// Used by the monitor process to extract information from a UB report. The +/// data is only available until the next time __ubsan_on_report is called. The +/// caller is responsible for copying and preserving the data if needed. +extern "C" SANITIZER_INTERFACE_ATTRIBUTE void +__ubsan_get_current_report_data(const char **OutIssueKind, +                                const char **OutMessage, +                                const char **OutFilename, unsigned *OutLine, +                                unsigned *OutCol, char **OutMemoryAddr); + +} // end namespace __ubsan + +#endif // UBSAN_MONITOR_H diff --git a/lib/ubsan/ubsan_platform.h b/lib/ubsan/ubsan_platform.h index 72eb4199960ef..45a4aa7720815 100644 --- a/lib/ubsan/ubsan_platform.h +++ b/lib/ubsan/ubsan_platform.h @@ -14,13 +14,10 @@  #define UBSAN_PLATFORM_H  // Other platforms should be easy to add, and probably work as-is. -#if (defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) ||       \ -     defined(__NetBSD__)) &&                                                   \ -    (defined(__x86_64__) || defined(__i386__) || defined(__arm__) ||           \ -     defined(__aarch64__) || defined(__mips__) || defined(__powerpc64__) ||    \ -     defined(__s390__)) || (defined(__sun__) && defined(__svr4__)) -# define CAN_SANITIZE_UB 1 -#elif defined(_WIN32) || defined(__Fuchsia__) +#if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) ||        \ +    defined(__NetBSD__) || defined(__OpenBSD__) || \ +    (defined(__sun__) && defined(__svr4__)) || \ +    defined(_WIN32) || defined(__Fuchsia__) || defined(__rtems__)  # define CAN_SANITIZE_UB 1  #else  # define CAN_SANITIZE_UB 0 diff --git a/lib/ubsan/ubsan_signals_standalone.cc b/lib/ubsan/ubsan_signals_standalone.cc index 4c6646dd8b0b0..5e77c60b1dbb5 100644 --- a/lib/ubsan/ubsan_signals_standalone.cc +++ b/lib/ubsan/ubsan_signals_standalone.cc @@ -13,20 +13,34 @@  //===----------------------------------------------------------------------===//  #include "ubsan_platform.h" +#include "sanitizer_common/sanitizer_platform.h"  #if CAN_SANITIZE_UB  #include "interception/interception.h"  #include "sanitizer_common/sanitizer_stacktrace.h"  #include "ubsan_diag.h"  #include "ubsan_init.h" +// Interception of signals breaks too many things on Android. +// * It requires that ubsan is the first dependency of the main executable for +// the interceptors to work correctly. This complicates deployment, as it +// prevents us from enabling ubsan on random platform modules independently. +// * For this to work with ART VM, ubsan signal handler has to be set after the +// debuggerd handler, but before the ART handler. +// * Interceptors don't work at all when ubsan runtime is loaded late, ex. when +// it is part of an APK that does not use wrap.sh method. +#if SANITIZER_FUCHSIA || SANITIZER_ANDROID + +namespace __ubsan { +void InitializeDeadlySignals() {} +} + +#else +  #define COMMON_INTERCEPT_FUNCTION(name) INTERCEPT_FUNCTION(name)  #include "sanitizer_common/sanitizer_signal_interceptors.inc"  namespace __ubsan { -#if SANITIZER_FUCHSIA -void InitializeDeadlySignals() {} -#else  static void OnStackUnwind(const SignalContext &sig, const void *,                            BufferedStackTrace *stack) {    GetStackTrace(stack, kStackTraceMax, sig.pc, sig.bp, sig.context, @@ -46,8 +60,9 @@ void InitializeDeadlySignals() {    InitializeSignalInterceptors();    InstallDeadlySignalHandlers(&UBsanOnDeadlySignal);  } -#endif  } // namespace __ubsan +#endif +  #endif // CAN_SANITIZE_UB diff --git a/lib/ubsan/ubsan_win_weak_interception.cc b/lib/ubsan/ubsan_win_weak_interception.cc index 353719eefacf7..c28577057c085 100644 --- a/lib/ubsan/ubsan_win_weak_interception.cc +++ b/lib/ubsan/ubsan_win_weak_interception.cc @@ -14,6 +14,7 @@  #ifdef SANITIZER_DYNAMIC  #include "sanitizer_common/sanitizer_win_weak_interception.h"  #include "ubsan_flags.h" +#include "ubsan_monitor.h"  // Check if strong definitions for weak functions are present in the main  // executable. If that is the case, override dll functions to point to strong  // implementations. diff --git a/lib/ubsan_minimal/CMakeLists.txt b/lib/ubsan_minimal/CMakeLists.txt index 54860a3d27645..b70246845f849 100644 --- a/lib/ubsan_minimal/CMakeLists.txt +++ b/lib/ubsan_minimal/CMakeLists.txt @@ -44,7 +44,7 @@ if(COMPILER_RT_HAS_UBSAN_MINIMAL)      LINK_LIBS ${UBSAN_DYNAMIC_LIBS}      PARENT_TARGET ubsan-minimal) -  if (UNIX AND NOT APPLE) +  if (SANITIZER_USE_SYMBOLS AND NOT APPLE)      set(ARCHS_FOR_SYMBOLS ${UBSAN_SUPPORTED_ARCH})      list(REMOVE_ITEM ARCHS_FOR_SYMBOLS i386 i686)      add_sanitizer_rt_symbols(clang_rt.ubsan_minimal diff --git a/lib/ubsan_minimal/ubsan_minimal_handlers.cc b/lib/ubsan_minimal/ubsan_minimal_handlers.cc index 5a5675c983fe6..f25a75a863c4e 100644 --- a/lib/ubsan_minimal/ubsan_minimal_handlers.cc +++ b/lib/ubsan_minimal/ubsan_minimal_handlers.cc @@ -61,6 +61,19 @@ static void abort_with_message(const char *msg) {  static void abort_with_message(const char *) { abort(); }  #endif +#if SANITIZER_DEBUG +namespace __sanitizer { +// The DCHECK macro needs this symbol to be defined. +void NORETURN CheckFailed(const char *file, int, const char *cond, u64, u64) { +  message("Sanitizer CHECK failed: "); +  message(file); +  message(":?? : "); // FIXME: Show line number. +  message(cond); +  abort(); +} +} // namespace __sanitizer +#endif +  #define INTERFACE extern "C" __attribute__((visibility("default")))  // FIXME: add caller pc to the error message (possibly as "ubsan: error-type diff --git a/lib/xray/CMakeLists.txt b/lib/xray/CMakeLists.txt index 5547600b943ae..8e18f55658f8d 100644 --- a/lib/xray/CMakeLists.txt +++ b/lib/xray/CMakeLists.txt @@ -1,16 +1,29 @@ -# Build for the XRay runtime support library. +# Build for all components of the XRay runtime support library.  # XRay runtime library implementation files.  set(XRAY_SOURCES -  xray_inmemory_log.cc -  xray_init.cc -  xray_flags.cc -  xray_interface.cc -  xray_buffer_queue.cc -  xray_log_interface.cc -  xray_fdr_logging.cc -  xray_utils.cc) +    xray_init.cc +    xray_flags.cc +    xray_interface.cc +    xray_log_interface.cc +    xray_utils.cc) +# Implementation files for all XRay modes. +set(XRAY_FDR_MODE_SOURCES +    xray_fdr_flags.cc +    xray_buffer_queue.cc +    xray_fdr_logging.cc) + +set(XRAY_BASIC_MODE_SOURCES +    xray_basic_flags.cc +    xray_basic_logging.cc) + +set(XRAY_PROFILING_MODE_SOURCES +    xray_profile_collector.cc +    xray_profiling.cc +    xray_profiling_flags.cc) + +# Implementation files for all XRay architectures.  set(x86_64_SOURCES      xray_x86_64.cc      xray_trampoline_x86_64.S) @@ -23,8 +36,8 @@ set(armhf_SOURCES      ${arm_SOURCES})  set(aarch64_SOURCES -  xray_AArch64.cc -  xray_trampoline_AArch64.S) +    xray_AArch64.cc +    xray_trampoline_AArch64.S)  set(mips_SOURCES      xray_mips.cc @@ -47,11 +60,68 @@ set(powerpc64le_SOURCES      xray_trampoline_powerpc64.cc      xray_trampoline_powerpc64_asm.S) +set(XRAY_IMPL_HEADERS +  xray_allocator.h +  xray_basic_flags.h +  xray_basic_flags.inc +  xray_basic_logging.h +  xray_buffer_queue.h +  xray_defs.h +  xray_fdr_flags.h +  xray_fdr_flags.inc +  xray_fdr_log_records.h +  xray_fdr_logging.h +  xray_flags.h +  xray_flags.inc +  xray_function_call_trie.h +  xray_interface_internal.h +  xray_powerpc64.inc +  xray_profile_collector.h +  xray_profiling_flags.h +  xray_profiling_flags.inc +  xray_recursion_guard.h +  xray_segmented_array.h +  xray_tsc.h +  xray_utils.h +  xray_x86_64.inc) + +# Create list of all source files for +# consumption by tests. +set(XRAY_ALL_SOURCE_FILES +  ${XRAY_SOURCES} +  ${XRAY_FDR_MODE_SOURCES} +  ${XRAY_BASIC_MODE_SOURCES} +  ${XRAY_PROFILING_MODE_SOURCES} +  ${x86_64_SOURCES} +  ${arm_SOURCES} +  ${armhf_SOURCES} +  ${mips_SOURCES} +  ${mipsel_SOURCES} +  ${mips64_SOURCES} +  ${mips64el_SOURCES} +  ${powerpc64le_SOURCES} +  ${XRAY_IMPL_HEADERS} +) +list(REMOVE_DUPLICATES XRAY_ALL_SOURCE_FILES) +# Make list that uses absolute paths +set(XRAY_ALL_SOURCE_FILES_ABS_PATHS "") +foreach (src_file ${XRAY_ALL_SOURCE_FILES}) +  list(APPEND +    XRAY_ALL_SOURCE_FILES_ABS_PATHS +    "${CMAKE_CURRENT_SOURCE_DIR}/${src_file}") +endforeach() + + +# Now put it all together...  include_directories(..)  include_directories(../../include)  set(XRAY_CFLAGS ${SANITIZER_COMMON_CFLAGS})  set(XRAY_COMMON_DEFINITIONS XRAY_HAS_EXCEPTIONS=1) + +# We don't need RTTI in XRay, so turn that off. +append_rtti_flag(OFF XRAY_CFLAGS) +  append_list_if(    COMPILER_RT_HAS_XRAY_COMPILER_FLAG XRAY_SUPPORTED=1 XRAY_COMMON_DEFINITIONS)  append_list_if( @@ -60,10 +130,13 @@ append_list_if(  add_compiler_rt_component(xray)  set(XRAY_COMMON_RUNTIME_OBJECT_LIBS -    RTXray      RTSanitizerCommon      RTSanitizerCommonLibc) +if (TARGET cxx-headers OR HAVE_LIBCXX) +  set(XRAY_DEPS cxx-headers) +endif() +  if (APPLE)    set(XRAY_LINK_LIBS ${SANITIZER_COMMON_LINK_LIBS})    add_asm_sources(XRAY_ASM_SOURCES xray_trampoline_x86_64.S) @@ -75,8 +148,34 @@ if (APPLE)      OS ${XRAY_SUPPORTED_OS}      ARCHS ${XRAY_SUPPORTED_ARCH}      SOURCES ${x86_64_SOURCES} +    ADDITIONAL_HEADERS ${XRAY_IMPL_HEADERS} +    CFLAGS ${XRAY_CFLAGS} +    DEFS ${XRAY_COMMON_DEFINITIONS} +    DEPS ${XRAY_DEPS}) +  add_compiler_rt_object_libraries(RTXrayFDR +    OS ${XRAY_SUPPORTED_OS} +    ARCHS ${XRAY_SUPPORTED_ARCH} +    SOURCES ${XRAY_FDR_MODE_SOURCES} +    ADDITIONAL_HEADERS ${XRAY_IMPL_HEADERS}      CFLAGS ${XRAY_CFLAGS} -    DEFS ${XRAY_COMMON_DEFINITIONS}) +    DEFS ${XRAY_COMMON_DEFINITIONS} +    DEPS ${XRAY_DEPS}) +  add_compiler_rt_object_libraries(RTXrayBASIC +    OS ${XRAY_SUPPORTED_OS} +    ARCHS ${XRAY_SUPPORTED_ARCH} +    SOURCES ${XRAY_BASIC_MODE_SOURCES} +    ADDITIONAL_HEADERS ${XRAY_IMPL_HEADERS} +    CFLAGS ${XRAY_CFLAGS} +    DEFS ${XRAY_COMMON_DEFINITIONS} +    DEPS ${XRAY_DEPS}) +  add_compiler_rt_object_libraries(RTXrayPROFILING +    OS ${XRAY_SUPPORTED_OS} +    ARCHS ${XRAY_SUPPORTED_ARCH} +    SOURCES ${XRAY_PROFILING_MODE_SOURCES} +    ADDITIONAL_HEADERS ${XRAY_IMPL_HEADERS} +    CFLAGS ${XRAY_CFLAGS} +    DEFS ${XRAY_COMMON_DEFINITIONS} +    DEPS ${XRAY_DEPS})    # We only support running on osx for now.    add_compiler_rt_runtime(clang_rt.xray @@ -91,24 +190,104 @@ if (APPLE)      LINK_FLAGS ${SANITIZER_COMMON_LINK_FLAGS} ${WEAK_SYMBOL_LINK_FLAGS}      LINK_LIBS ${XRAY_LINK_LIBS}      PARENT_TARGET xray) -else() -foreach(arch ${XRAY_SUPPORTED_ARCH}) -  if(CAN_TARGET_${arch}) +  add_compiler_rt_runtime(clang_rt.xray-fdr +    STATIC +    OS ${XRAY_SUPPORTED_OS} +    ARCHS ${XRAY_SUPPORTED_ARCH} +    OBJECT_LIBS RTXrayFDR +    CFLAGS ${XRAY_CFLAGS} +    DEFS ${XRAY_COMMON_DEFINITIONS} +    LINK_FLAGS ${SANITIZER_COMMON_LINK_FLAGS} ${WEAK_SYMBOL_LINK_FLAGS} +    LINK_LIBS ${XRAY_LINK_LIBS} +    PARENT_TARGET xray) +  add_compiler_rt_runtime(clang_rt.xray-basic +    STATIC +    OS ${XRAY_SUPPORTED_OS} +    ARCHS ${XRAY_SUPPORTED_ARCH} +    OBJECT_LIBS RTXrayBASIC +    CFLAGS ${XRAY_CFLAGS} +    DEFS ${XRAY_COMMON_DEFINITIONS} +    LINK_FLAGS ${SANITIZER_COMMON_LINK_FLAGS} ${WEAK_SYMBOL_LINK_FLAGS} +    LINK_LIBS ${XRAY_LINK_LIBS} +    PARENT_TARGET xray) +  add_compiler_rt_runtime(clang_rt.xray-profiling +    STATIC +    OS ${XRAY_SUPPORTED_OS} +    ARCHS ${XRAY_SUPPORTED_ARCH} +    OBJECT_LIBS RTXrayPROFILING +    CFLAGS ${XRAY_CFLAGS} +    DEFS ${XRAY_COMMON_DEFINITIONS} +    LINK_FLAGS ${SANITIZER_COMMON_LINK_FLAGS} ${WEAK_SYMBOL_LINK_FLAGS} +    LINK_LIBS ${XRAY_LINK_LIBS} +    PARENT_TARGET xray) +else() # not Apple +  foreach(arch ${XRAY_SUPPORTED_ARCH}) +    if(NOT CAN_TARGET_${arch}) +      continue() +    endif()      add_compiler_rt_object_libraries(RTXray        ARCHS ${arch} -      SOURCES ${XRAY_SOURCES} CFLAGS ${XRAY_CFLAGS} -      DEFS ${XRAY_COMMON_DEFINITIONS}) +      SOURCES ${XRAY_SOURCES} ${${arch}_SOURCES} +      ADDITIONAL_HEADERS ${XRAY_IMPL_HEADERS} +      CFLAGS ${XRAY_CFLAGS} +      DEFS ${XRAY_COMMON_DEFINITIONS} +      DEPS ${XRAY_DEPS}) +    add_compiler_rt_object_libraries(RTXrayFDR +      ARCHS ${arch} +      SOURCES ${XRAY_FDR_MODE_SOURCES} +      ADDITIONAL_HEADERS ${XRAY_IMPL_HEADERS} +      CFLAGS ${XRAY_CFLAGS} +      DEFS ${XRAY_COMMON_DEFINITIONS} +      DEPS ${XRAY_DEPS}) +    add_compiler_rt_object_libraries(RTXrayBASIC +      ARCHS ${arch} +      SOURCES ${XRAY_BASIC_MODE_SOURCES} +      ADDITIONAL_HEADERS ${XRAY_IMPL_HEADERS} +      CFLAGS ${XRAY_CFLAGS} +      DEFS ${XRAY_COMMON_DEFINITIONS} +      DEPS ${XRAY_DEPS}) +    add_compiler_rt_object_libraries(RTXrayPROFILING +      ARCHS ${arch} +      SOURCES ${XRAY_PROFILING_MODE_SOURCES} +      ADDITIONAL_HEADERS ${XRAY_IMPL_HEADERS} +      CFLAGS ${XRAY_CFLAGS} +      DEFS ${XRAY_COMMON_DEFINITIONS} +      DEPS ${XRAY_DEPS}) + +    # Common XRay archive for instrumented binaries.      add_compiler_rt_runtime(clang_rt.xray       STATIC       ARCHS ${arch} -     SOURCES ${${arch}_SOURCES}       CFLAGS ${XRAY_CFLAGS}       DEFS ${XRAY_COMMON_DEFINITIONS} -     OBJECT_LIBS ${XRAY_COMMON_RUNTIME_OBJECT_LIBS} +     OBJECT_LIBS ${XRAY_COMMON_RUNTIME_OBJECT_LIBS} RTXray       PARENT_TARGET xray) -  endif() -endforeach() -endif() +    # FDR mode runtime archive (addon for clang_rt.xray) +    add_compiler_rt_runtime(clang_rt.xray-fdr +      STATIC +      ARCHS ${arch} +      CFLAGS ${XRAY_CFLAGS} +      DEFS ${XRAY_COMMON_DEFINITIONS} +      OBJECT_LIBS RTXrayFDR +      PARENT_TARGET xray) +    # Basic mode runtime archive (addon for clang_rt.xray) +    add_compiler_rt_runtime(clang_rt.xray-basic +      STATIC +      ARCHS ${arch} +      CFLAGS ${XRAY_CFLAGS} +      DEFS ${XRAY_COMMON_DEFINITIONS} +      OBJECT_LIBS RTXrayBASIC +      PARENT_TARGET xray) +   # Profiler Mode runtime +   add_compiler_rt_runtime(clang_rt.xray-profiling +     STATIC +     ARCHS ${arch} +     CFLAGS ${XRAY_CFLAGS} +     DEFS ${XRAY_COMMON_DEFINITIONS} +     OBJECT_LIBS RTXrayPROFILING +     PARENT_TARGET xray) +  endforeach() +endif() # not Apple  if(COMPILER_RT_INCLUDE_TESTS)    add_subdirectory(tests) diff --git a/lib/xray/tests/CMakeLists.txt b/lib/xray/tests/CMakeLists.txt index e54e63f27890c..11f373167d247 100644 --- a/lib/xray/tests/CMakeLists.txt +++ b/lib/xray/tests/CMakeLists.txt @@ -3,6 +3,18 @@ include_directories(..)  add_custom_target(XRayUnitTests)  set_target_properties(XRayUnitTests PROPERTIES FOLDER "XRay unittests") +# Sanity check XRAY_ALL_SOURCE_FILES_ABS_PATHS +list(LENGTH XRAY_ALL_SOURCE_FILES_ABS_PATHS XASFAP_LENGTH) +if (${XASFAP_LENGTH} EQUAL 0) +  message(FATAL_ERROR "XRAY_ALL_SOURCE_FILES_ABS_PATHS cannot be empty") +endif() +unset(XASFAP_LENGTH) +foreach (src_file ${XRAY_ALL_SOURCE_FILES_ABS_PATHS}) +  if (NOT EXISTS "${src_file}") +    message(FATAL_ERROR "Source file \"${src_file}\" does not exist") +  endif() +endforeach() +  set(XRAY_UNITTEST_CFLAGS    ${XRAY_CFLAGS}    ${COMPILER_RT_UNITTEST_CFLAGS} @@ -11,27 +23,77 @@ set(XRAY_UNITTEST_CFLAGS    -I${COMPILER_RT_SOURCE_DIR}/lib/xray    -I${COMPILER_RT_SOURCE_DIR}/lib) +function(add_xray_lib library) +  add_library(${library} STATIC ${ARGN}) +  set_target_properties(${library} PROPERTIES +    ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} +    FOLDER "Compiler-RT Runtime tests") +endfunction() + +function(get_xray_lib_for_arch arch lib) +  if(APPLE) +    set(tgt_name "RTXRay.test.osx") +  else() +    set(tgt_name "RTXRay.test.${arch}") +  endif() +  set(${lib} "${tgt_name}" PARENT_SCOPE) +endfunction() +  set(XRAY_TEST_ARCH ${XRAY_SUPPORTED_ARCH}) +set(XRAY_UNITTEST_LINK_FLAGS +  ${CMAKE_THREAD_LIBS_INIT} +	-l${SANITIZER_CXX_ABI_LIBRARY} +  -fxray-instrument +  ) +if (NOT APPLE) +  append_list_if(COMPILER_RT_HAS_LIBM -lm XRAY_UNITTEST_LINK_FLAGS) +  append_list_if(COMPILER_RT_HAS_LIBRT -lrt XRAY_UNITTEST_LINK_FLAGS) +  append_list_if(COMPILER_RT_HAS_LIBDL -ldl XRAY_UNITTEST_LINK_FLAGS) +  append_list_if(COMPILER_RT_HAS_LIBPTHREAD -pthread XRAY_UNITTEST_LINK_FLAGS) +endif() +  macro(add_xray_unittest testname)    cmake_parse_arguments(TEST "" "" "SOURCES;HEADERS" ${ARGN})    if(UNIX AND NOT APPLE) +    set(CMAKE_DL_LIBS_INIT "")      foreach(arch ${XRAY_TEST_ARCH})        set(TEST_OBJECTS) +      get_xray_lib_for_arch(${arch} XRAY_RUNTIME_LIBS)        generate_compiler_rt_tests(TEST_OBJECTS          XRayUnitTests "${testname}-${arch}-Test" "${arch}"          SOURCES ${TEST_SOURCES} ${COMPILER_RT_GTEST_SOURCE} +        # Note that any change in the implementations will cause all the unit +        # tests to be re-built. This is by design, but may be cumbersome during +        # the build/test cycle. +        COMPILE_DEPS ${TEST_SOURCES} ${COMPILER_RT_GTEST_SOURCE} +        ${XRAY_HEADERS} ${XRAY_ALL_SOURCE_FILES_ABS_PATHS} +        RUNTIME "${XRAY_RUNTIME_LIBS}"          DEPS gtest xray llvm-xray          CFLAGS ${XRAY_UNITTEST_CFLAGS} -        LINK_FLAGS -fxray-instrument -          ${TARGET_LINK_FLAGS} -          -lstdc++ -lm ${CMAKE_THREAD_LIBS_INIT} -          -lpthread -          -ldl -lrt) -      set_target_properties(XRayUnitTests PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) +        LINK_FLAGS ${TARGET_LINK_FLAGS} ${XRAY_UNITTEST_LINK_FLAGS}) +      set_target_properties(XRayUnitTests +        PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})      endforeach()    endif()  endmacro()  if(COMPILER_RT_CAN_EXECUTE_TESTS) +  if (APPLE) +    add_xray_lib("RTXRay.test.osx" +      $<TARGET_OBJECTS:RTXray.osx> +      $<TARGET_OBJECTS:RTXrayFDR.osx> +      $<TARGET_OBJECTS:RTXrayPROFILING.osx> +      $<TARGET_OBJECTS:RTSanitizerCommon.osx> +      $<TARGET_OBJECTS:RTSanitizerCommonLibc.osx>) +  else() +  foreach(arch ${XRAY_SUPPORTED_ARCH}) +    add_xray_lib("RTXRay.test.${arch}" +      $<TARGET_OBJECTS:RTXray.${arch}> +      $<TARGET_OBJECTS:RTXrayFDR.${arch}> +      $<TARGET_OBJECTS:RTXrayPROFILING.${arch}> +      $<TARGET_OBJECTS:RTSanitizerCommon.${arch}> +      $<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>) +  endforeach() +  endif()    add_subdirectory(unit)  endif() diff --git a/lib/xray/tests/unit/CMakeLists.txt b/lib/xray/tests/unit/CMakeLists.txt index 62d01f2395813..b42eb50d07907 100644 --- a/lib/xray/tests/unit/CMakeLists.txt +++ b/lib/xray/tests/unit/CMakeLists.txt @@ -2,3 +2,11 @@ add_xray_unittest(XRayBufferQueueTest SOURCES    buffer_queue_test.cc xray_unit_test_main.cc)  add_xray_unittest(XRayFDRLoggingTest SOURCES    fdr_logging_test.cc xray_unit_test_main.cc) +add_xray_unittest(XRayAllocatorTest SOURCES +  allocator_test.cc xray_unit_test_main.cc) +add_xray_unittest(XRaySegmentedArrayTest SOURCES +  segmented_array_test.cc xray_unit_test_main.cc) +add_xray_unittest(XRayFunctionCallTrieTest SOURCES +  function_call_trie_test.cc xray_unit_test_main.cc) +add_xray_unittest(XRayProfileCollectorTest SOURCES +  profile_collector_test.cc xray_unit_test_main.cc) diff --git a/lib/xray/tests/unit/allocator_test.cc b/lib/xray/tests/unit/allocator_test.cc new file mode 100644 index 0000000000000..be404160e4177 --- /dev/null +++ b/lib/xray/tests/unit/allocator_test.cc @@ -0,0 +1,42 @@ +//===-- allocator_test.cc -------------------------------------------------===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of XRay, a function call tracing system. +// +//===----------------------------------------------------------------------===// + +#include "xray_allocator.h" +#include "gtest/gtest.h" + +namespace __xray { +namespace { + +struct TestData { +  s64 First; +  s64 Second; +}; + +TEST(AllocatorTest, Construction) { Allocator<sizeof(TestData)> A(2 << 11); } + +TEST(AllocatorTest, Allocate) { +  Allocator<sizeof(TestData)> A(2 << 11); +  auto B = A.Allocate(); +  ASSERT_NE(B.Data, nullptr); +} + +TEST(AllocatorTest, OverAllocate) { +  Allocator<sizeof(TestData)> A(sizeof(TestData)); +  auto B1 = A.Allocate(); +  (void)B1; +  auto B2 = A.Allocate(); +  ASSERT_EQ(B2.Data, nullptr); +} + +} // namespace +} // namespace __xray diff --git a/lib/xray/tests/unit/buffer_queue_test.cc b/lib/xray/tests/unit/buffer_queue_test.cc index 1ec7469ce1874..c0d4ccb268d6c 100644 --- a/lib/xray/tests/unit/buffer_queue_test.cc +++ b/lib/xray/tests/unit/buffer_queue_test.cc @@ -32,9 +32,9 @@ TEST(BufferQueueTest, GetAndRelease) {    ASSERT_TRUE(Success);    BufferQueue::Buffer Buf;    ASSERT_EQ(Buffers.getBuffer(Buf), BufferQueue::ErrorCode::Ok); -  ASSERT_NE(nullptr, Buf.Buffer); +  ASSERT_NE(nullptr, Buf.Data);    ASSERT_EQ(Buffers.releaseBuffer(Buf), BufferQueue::ErrorCode::Ok); -  ASSERT_EQ(nullptr, Buf.Buffer); +  ASSERT_EQ(nullptr, Buf.Data);  }  TEST(BufferQueueTest, GetUntilFailed) { @@ -53,7 +53,7 @@ TEST(BufferQueueTest, ReleaseUnknown) {    BufferQueue Buffers(kSize, 1, Success);    ASSERT_TRUE(Success);    BufferQueue::Buffer Buf; -  Buf.Buffer = reinterpret_cast<void *>(0xdeadbeef); +  Buf.Data = reinterpret_cast<void *>(0xdeadbeef);    Buf.Size = kSize;    EXPECT_EQ(BufferQueue::ErrorCode::UnrecognizedBuffer,              Buffers.releaseBuffer(Buf)); @@ -65,7 +65,7 @@ TEST(BufferQueueTest, ErrorsWhenFinalising) {    ASSERT_TRUE(Success);    BufferQueue::Buffer Buf;    ASSERT_EQ(Buffers.getBuffer(Buf), BufferQueue::ErrorCode::Ok); -  ASSERT_NE(nullptr, Buf.Buffer); +  ASSERT_NE(nullptr, Buf.Data);    ASSERT_EQ(Buffers.finalize(), BufferQueue::ErrorCode::Ok);    BufferQueue::Buffer OtherBuf;    ASSERT_EQ(BufferQueue::ErrorCode::QueueFinalizing, diff --git a/lib/xray/tests/unit/fdr_logging_test.cc b/lib/xray/tests/unit/fdr_logging_test.cc index 76738ea4dff3d..b6961efbc3517 100644 --- a/lib/xray/tests/unit/fdr_logging_test.cc +++ b/lib/xray/tests/unit/fdr_logging_test.cc @@ -10,6 +10,7 @@  // This file is a part of XRay, a function call tracing system.  //  //===----------------------------------------------------------------------===// +#include "sanitizer_common/sanitizer_common.h"  #include "xray_fdr_logging.h"  #include "gtest/gtest.h" @@ -86,7 +87,7 @@ TEST(FDRLoggingTest, Simple) {    XRayFileHeader H;    memcpy(&H, Contents, sizeof(XRayFileHeader)); -  ASSERT_EQ(H.Version, 2); +  ASSERT_EQ(H.Version, 3);    ASSERT_EQ(H.Type, FileTypes::FDR_LOG);    // We require one buffer at least to have the "extents" metadata record, @@ -131,7 +132,7 @@ TEST(FDRLoggingTest, Multiple) {    XRayFileHeader H;    memcpy(&H, Contents, sizeof(XRayFileHeader)); -  ASSERT_EQ(H.Version, 2); +  ASSERT_EQ(H.Version, 3);    ASSERT_EQ(H.Type, FileTypes::FDR_LOG);    MetadataRecord MDR0, MDR1; @@ -154,12 +155,12 @@ TEST(FDRLoggingTest, MultiThreadedCycling) {    // Now we want to create one thread, do some logging, then create another one,    // in succession and making sure that we're able to get thread records from    // the latest thread (effectively being able to recycle buffers). -  std::array<pid_t, 2> Threads; +  std::array<tid_t, 2> Threads;    for (uint64_t I = 0; I < 2; ++I) {      std::thread t{[I, &Threads] {        fdrLoggingHandleArg0(I + 1, XRayEntryType::ENTRY);        fdrLoggingHandleArg0(I + 1, XRayEntryType::EXIT); -      Threads[I] = syscall(SYS_gettid); +      Threads[I] = GetTid();      }};      t.join();    } @@ -182,7 +183,7 @@ TEST(FDRLoggingTest, MultiThreadedCycling) {    XRayFileHeader H;    memcpy(&H, Contents, sizeof(XRayFileHeader)); -  ASSERT_EQ(H.Version, 2); +  ASSERT_EQ(H.Version, 3);    ASSERT_EQ(H.Type, FileTypes::FDR_LOG);    MetadataRecord MDR0, MDR1; @@ -192,9 +193,9 @@ TEST(FDRLoggingTest, MultiThreadedCycling) {    ASSERT_EQ(MDR0.RecordKind,              uint8_t(MetadataRecord::RecordKinds::BufferExtents));    ASSERT_EQ(MDR1.RecordKind, uint8_t(MetadataRecord::RecordKinds::NewBuffer)); -  pid_t Latest = 0; -  memcpy(&Latest, MDR1.Data, sizeof(pid_t)); -  ASSERT_EQ(Latest, Threads[1]); +  int32_t Latest = 0; +  memcpy(&Latest, MDR1.Data, sizeof(int32_t)); +  ASSERT_EQ(Latest, static_cast<int32_t>(Threads[1]));  }  } // namespace diff --git a/lib/xray/tests/unit/function_call_trie_test.cc b/lib/xray/tests/unit/function_call_trie_test.cc new file mode 100644 index 0000000000000..049ecfb07e017 --- /dev/null +++ b/lib/xray/tests/unit/function_call_trie_test.cc @@ -0,0 +1,286 @@ +//===-- function_call_trie_test.cc ----------------------------------------===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of XRay, a function call tracing system. +// +//===----------------------------------------------------------------------===// +#include "gtest/gtest.h" + +#include "xray_function_call_trie.h" + +namespace __xray { + +namespace { + +TEST(FunctionCallTrieTest, ConstructWithTLSAllocators) { +  profilingFlags()->setDefaults(); +  FunctionCallTrie::Allocators Allocators = FunctionCallTrie::InitAllocators(); +  FunctionCallTrie Trie(Allocators); +} + +TEST(FunctionCallTrieTest, EnterAndExitFunction) { +  profilingFlags()->setDefaults(); +  auto A = FunctionCallTrie::InitAllocators(); +  FunctionCallTrie Trie(A); + +  Trie.enterFunction(1, 1); +  Trie.exitFunction(1, 2); + +  // We need a way to pull the data out. At this point, until we get a data +  // collection service implemented, we're going to export the data as a list of +  // roots, and manually walk through the structure ourselves. + +  const auto &R = Trie.getRoots(); + +  ASSERT_EQ(R.size(), 1u); +  ASSERT_EQ(R.front()->FId, 1); +  ASSERT_EQ(R.front()->CallCount, 1); +  ASSERT_EQ(R.front()->CumulativeLocalTime, 1u); +} + +TEST(FunctionCallTrieTest, MissingFunctionEntry) { +  profilingFlags()->setDefaults(); +  auto A = FunctionCallTrie::InitAllocators(); +  FunctionCallTrie Trie(A); +  Trie.exitFunction(1, 1); +  const auto &R = Trie.getRoots(); + +  ASSERT_TRUE(R.empty()); +} + +TEST(FunctionCallTrieTest, NoMatchingEntersForExit) { +  profilingFlags()->setDefaults(); +  auto A = FunctionCallTrie::InitAllocators(); +  FunctionCallTrie Trie(A); +  Trie.enterFunction(2, 1); +  Trie.enterFunction(3, 3); +  Trie.exitFunction(1, 5); +  const auto &R = Trie.getRoots(); + +  ASSERT_FALSE(R.empty()); +  EXPECT_EQ(R.size(), size_t{1}); +} + +TEST(FunctionCallTrieTest, MissingFunctionExit) { +  profilingFlags()->setDefaults(); +  auto A = FunctionCallTrie::InitAllocators(); +  FunctionCallTrie Trie(A); +  Trie.enterFunction(1, 1); +  const auto &R = Trie.getRoots(); + +  ASSERT_FALSE(R.empty()); +  EXPECT_EQ(R.size(), size_t{1}); +} + +TEST(FunctionCallTrieTest, MultipleRoots) { +  profilingFlags()->setDefaults(); +  auto A = FunctionCallTrie::InitAllocators(); +  FunctionCallTrie Trie(A); + +  // Enter and exit FId = 1. +  Trie.enterFunction(1, 1); +  Trie.exitFunction(1, 2); + +  // Enter and exit FId = 2. +  Trie.enterFunction(2, 3); +  Trie.exitFunction(2, 4); + +  const auto &R = Trie.getRoots(); +  ASSERT_FALSE(R.empty()); +  ASSERT_EQ(R.size(), 2u); + +  // Make sure the roots have different IDs. +  const auto R0 = R[0]; +  const auto R1 = R[1]; +  ASSERT_NE(R0->FId, R1->FId); + +  // Inspect the roots that they have the right data. +  ASSERT_NE(R0, nullptr); +  EXPECT_EQ(R0->CallCount, 1u); +  EXPECT_EQ(R0->CumulativeLocalTime, 1u); + +  ASSERT_NE(R1, nullptr); +  EXPECT_EQ(R1->CallCount, 1u); +  EXPECT_EQ(R1->CumulativeLocalTime, 1u); +} + +// While missing an intermediary entry may be rare in practice, we still enforce +// that we can handle the case where we've missed the entry event somehow, in +// between call entry/exits. To illustrate, imagine the following shadow call +// stack: +// +//   f0@t0 -> f1@t1 -> f2@t2 +// +// If for whatever reason we see an exit for `f2` @ t3, followed by an exit for +// `f0` @ t4 (i.e. no `f1` exit in between) then we need to handle the case of +// accounting local time to `f2` from d = (t3 - t2), then local time to `f1` +// as d' = (t3 - t1) - d, and then local time to `f0` as d'' = (t3 - t0) - d'. +TEST(FunctionCallTrieTest, MissingIntermediaryExit) { +  profilingFlags()->setDefaults(); +  auto A = FunctionCallTrie::InitAllocators(); +  FunctionCallTrie Trie(A); + +  Trie.enterFunction(1, 0); +  Trie.enterFunction(2, 100); +  Trie.enterFunction(3, 200); +  Trie.exitFunction(3, 300); +  Trie.exitFunction(1, 400); + +  // What we should see at this point is all the functions in the trie in a +  // specific order (1 -> 2 -> 3) with the appropriate count(s) and local +  // latencies. +  const auto &R = Trie.getRoots(); +  ASSERT_FALSE(R.empty()); +  ASSERT_EQ(R.size(), 1u); + +  const auto &F1 = *R[0]; +  ASSERT_EQ(F1.FId, 1); +  ASSERT_FALSE(F1.Callees.empty()); + +  const auto &F2 = *F1.Callees[0].NodePtr; +  ASSERT_EQ(F2.FId, 2); +  ASSERT_FALSE(F2.Callees.empty()); + +  const auto &F3 = *F2.Callees[0].NodePtr; +  ASSERT_EQ(F3.FId, 3); +  ASSERT_TRUE(F3.Callees.empty()); + +  // Now that we've established the preconditions, we check for specific aspects +  // of the nodes. +  EXPECT_EQ(F3.CallCount, 1); +  EXPECT_EQ(F2.CallCount, 1); +  EXPECT_EQ(F1.CallCount, 1); +  EXPECT_EQ(F3.CumulativeLocalTime, 100); +  EXPECT_EQ(F2.CumulativeLocalTime, 300); +  EXPECT_EQ(F1.CumulativeLocalTime, 100); +} + +TEST(FunctionCallTrieTest, DeepCallStack) { +  // Simulate a relatively deep call stack (32 levels) and ensure that we can +  // properly pop all the way up the stack. +  profilingFlags()->setDefaults(); +  auto A = FunctionCallTrie::InitAllocators(); +  FunctionCallTrie Trie(A); +  for (int i = 0; i < 32; ++i) +    Trie.enterFunction(i + 1, i); +  Trie.exitFunction(1, 33); + +  // Here, validate that we have a 32-level deep function call path from the +  // root (1) down to the leaf (33). +  const auto &R = Trie.getRoots(); +  ASSERT_EQ(R.size(), 1u); +  auto F = R[0]; +  for (int i = 0; i < 32; ++i) { +    EXPECT_EQ(F->FId, i + 1); +    EXPECT_EQ(F->CallCount, 1); +    if (F->Callees.empty() && i != 31) +      FAIL() << "Empty callees for FId " << F->FId; +    if (i != 31) +      F = F->Callees[0].NodePtr; +  } +} + +// TODO: Test that we can handle cross-CPU migrations, where TSCs are not +// guaranteed to be synchronised. +TEST(FunctionCallTrieTest, DeepCopy) { +  profilingFlags()->setDefaults(); +  auto A = FunctionCallTrie::InitAllocators(); +  FunctionCallTrie Trie(A); + +  Trie.enterFunction(1, 0); +  Trie.enterFunction(2, 1); +  Trie.exitFunction(2, 2); +  Trie.enterFunction(3, 3); +  Trie.exitFunction(3, 4); +  Trie.exitFunction(1, 5); + +  // We want to make a deep copy and compare notes. +  auto B = FunctionCallTrie::InitAllocators(); +  FunctionCallTrie Copy(B); +  Trie.deepCopyInto(Copy); + +  ASSERT_NE(Trie.getRoots().size(), 0u); +  ASSERT_EQ(Trie.getRoots().size(), Copy.getRoots().size()); +  const auto &R0Orig = *Trie.getRoots()[0]; +  const auto &R0Copy = *Copy.getRoots()[0]; +  EXPECT_EQ(R0Orig.FId, 1); +  EXPECT_EQ(R0Orig.FId, R0Copy.FId); + +  ASSERT_EQ(R0Orig.Callees.size(), 2u); +  ASSERT_EQ(R0Copy.Callees.size(), 2u); + +  const auto &F1Orig = +      *R0Orig.Callees +           .find_element( +               [](const FunctionCallTrie::NodeIdPair &R) { return R.FId == 2; }) +           ->NodePtr; +  const auto &F1Copy = +      *R0Copy.Callees +           .find_element( +               [](const FunctionCallTrie::NodeIdPair &R) { return R.FId == 2; }) +           ->NodePtr; +  EXPECT_EQ(&R0Orig, F1Orig.Parent); +  EXPECT_EQ(&R0Copy, F1Copy.Parent); +} + +TEST(FunctionCallTrieTest, MergeInto) { +  profilingFlags()->setDefaults(); +  auto A = FunctionCallTrie::InitAllocators(); +  FunctionCallTrie T0(A); +  FunctionCallTrie T1(A); + +  // 1 -> 2 -> 3 +  T0.enterFunction(1, 0); +  T0.enterFunction(2, 1); +  T0.enterFunction(3, 2); +  T0.exitFunction(3, 3); +  T0.exitFunction(2, 4); +  T0.exitFunction(1, 5); + +  // 1 -> 2 -> 3 +  T1.enterFunction(1, 0); +  T1.enterFunction(2, 1); +  T1.enterFunction(3, 2); +  T1.exitFunction(3, 3); +  T1.exitFunction(2, 4); +  T1.exitFunction(1, 5); + +  // We use a different allocator here to make sure that we're able to transfer +  // data into a FunctionCallTrie which uses a different allocator. This +  // reflects the inteded usage scenario for when we're collecting profiles that +  // aggregate across threads. +  auto B = FunctionCallTrie::InitAllocators(); +  FunctionCallTrie Merged(B); + +  T0.mergeInto(Merged); +  T1.mergeInto(Merged); + +  ASSERT_EQ(Merged.getRoots().size(), 1u); +  const auto &R0 = *Merged.getRoots()[0]; +  EXPECT_EQ(R0.FId, 1); +  EXPECT_EQ(R0.CallCount, 2); +  EXPECT_EQ(R0.CumulativeLocalTime, 10); +  EXPECT_EQ(R0.Callees.size(), 1u); + +  const auto &F1 = *R0.Callees[0].NodePtr; +  EXPECT_EQ(F1.FId, 2); +  EXPECT_EQ(F1.CallCount, 2); +  EXPECT_EQ(F1.CumulativeLocalTime, 6); +  EXPECT_EQ(F1.Callees.size(), 1u); + +  const auto &F2 = *F1.Callees[0].NodePtr; +  EXPECT_EQ(F2.FId, 3); +  EXPECT_EQ(F2.CallCount, 2); +  EXPECT_EQ(F2.CumulativeLocalTime, 2); +  EXPECT_EQ(F2.Callees.size(), 0u); +} + +} // namespace + +} // namespace __xray diff --git a/lib/xray/tests/unit/profile_collector_test.cc b/lib/xray/tests/unit/profile_collector_test.cc new file mode 100644 index 0000000000000..b7dbe567312a0 --- /dev/null +++ b/lib/xray/tests/unit/profile_collector_test.cc @@ -0,0 +1,179 @@ +//===-- profile_collector_test.cc -----------------------------------------===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of XRay, a function call tracing system. +// +//===----------------------------------------------------------------------===// +#include "gtest/gtest.h" + +#include "xray_profile_collector.h" +#include "xray_profiling_flags.h" +#include <cstdint> +#include <thread> +#include <utility> +#include <vector> + +namespace __xray { +namespace { + +static constexpr auto kHeaderSize = 16u; + +void ValidateBlock(XRayBuffer B) { +  profilingFlags()->setDefaults(); +  ASSERT_NE(static_cast<const void *>(B.Data), nullptr); +  ASSERT_NE(B.Size, 0u); +  ASSERT_GE(B.Size, kHeaderSize); +  // We look at the block size, the block number, and the thread ID to ensure +  // that none of them are zero (or that the header data is laid out as we +  // expect). +  char LocalBuffer[kHeaderSize] = {}; +  internal_memcpy(LocalBuffer, B.Data, kHeaderSize); +  u32 BlockSize = 0; +  u32 BlockNumber = 0; +  u64 ThreadId = 0; +  internal_memcpy(&BlockSize, LocalBuffer, sizeof(u32)); +  internal_memcpy(&BlockNumber, LocalBuffer + sizeof(u32), sizeof(u32)); +  internal_memcpy(&ThreadId, LocalBuffer + (2 * sizeof(u32)), sizeof(u64)); +  ASSERT_NE(BlockSize, 0u); +  ASSERT_GE(BlockNumber, 0u); +  ASSERT_NE(ThreadId, 0u); +} + +std::tuple<u32, u32, u64> ParseBlockHeader(XRayBuffer B) { +  char LocalBuffer[kHeaderSize] = {}; +  internal_memcpy(LocalBuffer, B.Data, kHeaderSize); +  u32 BlockSize = 0; +  u32 BlockNumber = 0; +  u64 ThreadId = 0; +  internal_memcpy(&BlockSize, LocalBuffer, sizeof(u32)); +  internal_memcpy(&BlockNumber, LocalBuffer + sizeof(u32), sizeof(u32)); +  internal_memcpy(&ThreadId, LocalBuffer + (2 * sizeof(u32)), sizeof(u64)); +  return std::make_tuple(BlockSize, BlockNumber, ThreadId); +} + +struct Profile { +  int64_t CallCount; +  int64_t CumulativeLocalTime; +  std::vector<int32_t> Path; +}; + +std::tuple<Profile, const char *> ParseProfile(const char *P) { +  Profile Result; +  // Read the path first, until we find a sentinel 0. +  int32_t F; +  do { +    internal_memcpy(&F, P, sizeof(int32_t)); +    P += sizeof(int32_t); +    Result.Path.push_back(F); +  } while (F != 0); + +  // Then read the CallCount. +  internal_memcpy(&Result.CallCount, P, sizeof(int64_t)); +  P += sizeof(int64_t); + +  // Then read the CumulativeLocalTime. +  internal_memcpy(&Result.CumulativeLocalTime, P, sizeof(int64_t)); +  P += sizeof(int64_t); +  return std::make_tuple(std::move(Result), P); +} + +TEST(profileCollectorServiceTest, PostSerializeCollect) { +  profilingFlags()->setDefaults(); +  // The most basic use-case (the one we actually only care about) is the one +  // where we ensure that we can post FunctionCallTrie instances, which are then +  // destroyed but serialized properly. +  // +  // First, we initialise a set of allocators in the local scope. This ensures +  // that we're able to copy the contents of the FunctionCallTrie that uses +  // the local allocators. +  auto Allocators = FunctionCallTrie::InitAllocators(); +  FunctionCallTrie T(Allocators); + +  // Then, we populate the trie with some data. +  T.enterFunction(1, 1); +  T.enterFunction(2, 2); +  T.exitFunction(2, 3); +  T.exitFunction(1, 4); + +  // Then we post the data to the global profile collector service. +  profileCollectorService::post(T, 1); + +  // Then we serialize the data. +  profileCollectorService::serialize(); + +  // Then we go through a single buffer to see whether we're getting the data we +  // expect. +  auto B = profileCollectorService::nextBuffer({nullptr, 0}); +  ValidateBlock(B); +  u32 BlockSize; +  u32 BlockNum; +  u64 ThreadId; +  std::tie(BlockSize, BlockNum, ThreadId) = ParseBlockHeader(B); + +  // We look at the serialized buffer to see whether the Trie we're expecting +  // to see is there. +  auto DStart = static_cast<const char *>(B.Data) + kHeaderSize; +  std::vector<char> D(DStart, DStart + BlockSize); +  B = profileCollectorService::nextBuffer(B); +  ASSERT_EQ(B.Data, nullptr); +  ASSERT_EQ(B.Size, 0u); + +  Profile Profile1, Profile2; +  auto P = static_cast<const char *>(D.data()); +  std::tie(Profile1, P) = ParseProfile(P); +  std::tie(Profile2, P) = ParseProfile(P); + +  ASSERT_NE(Profile1.Path.size(), Profile2.Path.size()); +  auto &P1 = Profile1.Path.size() < Profile2.Path.size() ? Profile2 : Profile1; +  auto &P2 = Profile1.Path.size() < Profile2.Path.size() ? Profile1 : Profile2; +  std::vector<int32_t> P1Expected = {2, 1, 0}; +  std::vector<int32_t> P2Expected = {1, 0}; +  ASSERT_EQ(P1.Path.size(), P1Expected.size()); +  ASSERT_EQ(P2.Path.size(), P2Expected.size()); +  ASSERT_EQ(P1.Path, P1Expected); +  ASSERT_EQ(P2.Path, P2Expected); +} + +// We break out a function that will be run in multiple threads, one that will +// use a thread local allocator, and will post the FunctionCallTrie to the +// profileCollectorService. This simulates what the threads being profiled would +// be doing anyway, but through the XRay logging implementation. +void threadProcessing() { +  thread_local auto Allocators = FunctionCallTrie::InitAllocators(); +  FunctionCallTrie T(Allocators); + +  T.enterFunction(1, 1); +  T.enterFunction(2, 2); +  T.exitFunction(2, 3); +  T.exitFunction(1, 4); + +  profileCollectorService::post(T, GetTid()); +} + +TEST(profileCollectorServiceTest, PostSerializeCollectMultipleThread) { +  profilingFlags()->setDefaults(); +  std::thread t1(threadProcessing); +  std::thread t2(threadProcessing); + +  t1.join(); +  t2.join(); + +  // At this point, t1 and t2 are already done with what they were doing. +  profileCollectorService::serialize(); + +  // Ensure that we see two buffers. +  auto B = profileCollectorService::nextBuffer({nullptr, 0}); +  ValidateBlock(B); + +  B = profileCollectorService::nextBuffer(B); +  ValidateBlock(B); +} + +} // namespace +} // namespace __xray diff --git a/lib/xray/tests/unit/segmented_array_test.cc b/lib/xray/tests/unit/segmented_array_test.cc new file mode 100644 index 0000000000000..035674ccfaf5e --- /dev/null +++ b/lib/xray/tests/unit/segmented_array_test.cc @@ -0,0 +1,200 @@ +#include "xray_segmented_array.h" +#include "gtest/gtest.h" + +namespace __xray { +namespace { + +struct TestData { +  s64 First; +  s64 Second; + +  // Need a constructor for emplace operations. +  TestData(s64 F, s64 S) : First(F), Second(S) {} +}; + +TEST(SegmentedArrayTest, ConstructWithAllocators) { +  using AllocatorType = typename Array<TestData>::AllocatorType; +  AllocatorType A(1 << 4); +  Array<TestData> Data(A); +  (void)Data; +} + +TEST(SegmentedArrayTest, ConstructAndPopulate) { +  using AllocatorType = typename Array<TestData>::AllocatorType; +  AllocatorType A(1 << 4); +  Array<TestData> data(A); +  ASSERT_NE(data.Append(TestData{0, 0}), nullptr); +  ASSERT_NE(data.Append(TestData{1, 1}), nullptr); +  ASSERT_EQ(data.size(), 2u); +} + +TEST(SegmentedArrayTest, ConstructPopulateAndLookup) { +  using AllocatorType = typename Array<TestData>::AllocatorType; +  AllocatorType A(1 << 4); +  Array<TestData> data(A); +  ASSERT_NE(data.Append(TestData{0, 1}), nullptr); +  ASSERT_EQ(data.size(), 1u); +  ASSERT_EQ(data[0].First, 0); +  ASSERT_EQ(data[0].Second, 1); +} + +TEST(SegmentedArrayTest, PopulateWithMoreElements) { +  using AllocatorType = typename Array<TestData>::AllocatorType; +  AllocatorType A(1 << 24); +  Array<TestData> data(A); +  static const auto kMaxElements = 100u; +  for (auto I = 0u; I < kMaxElements; ++I) { +    ASSERT_NE(data.Append(TestData{I, I + 1}), nullptr); +  } +  ASSERT_EQ(data.size(), kMaxElements); +  for (auto I = 0u; I < kMaxElements; ++I) { +    ASSERT_EQ(data[I].First, I); +    ASSERT_EQ(data[I].Second, I + 1); +  } +} + +TEST(SegmentedArrayTest, AppendEmplace) { +  using AllocatorType = typename Array<TestData>::AllocatorType; +  AllocatorType A(1 << 4); +  Array<TestData> data(A); +  ASSERT_NE(data.AppendEmplace(1, 1), nullptr); +  ASSERT_EQ(data[0].First, 1); +  ASSERT_EQ(data[0].Second, 1); +} + +TEST(SegmentedArrayTest, AppendAndTrim) { +  using AllocatorType = typename Array<TestData>::AllocatorType; +  AllocatorType A(1 << 4); +  Array<TestData> data(A); +  ASSERT_NE(data.AppendEmplace(1, 1), nullptr); +  ASSERT_EQ(data.size(), 1u); +  data.trim(1); +  ASSERT_EQ(data.size(), 0u); +  ASSERT_TRUE(data.empty()); +} + +TEST(SegmentedArrayTest, IteratorAdvance) { +  using AllocatorType = typename Array<TestData>::AllocatorType; +  AllocatorType A(1 << 4); +  Array<TestData> data(A); +  ASSERT_TRUE(data.empty()); +  ASSERT_EQ(data.begin(), data.end()); +  auto I0 = data.begin(); +  ASSERT_EQ(I0++, data.begin()); +  ASSERT_NE(I0, data.begin()); +  for (const auto &D : data) { +    (void)D; +    FAIL(); +  } +  ASSERT_NE(data.AppendEmplace(1, 1), nullptr); +  ASSERT_EQ(data.size(), 1u); +  ASSERT_NE(data.begin(), data.end()); +  auto &D0 = *data.begin(); +  ASSERT_EQ(D0.First, 1); +  ASSERT_EQ(D0.Second, 1); +} + +TEST(SegmentedArrayTest, IteratorRetreat) { +  using AllocatorType = typename Array<TestData>::AllocatorType; +  AllocatorType A(1 << 4); +  Array<TestData> data(A); +  ASSERT_TRUE(data.empty()); +  ASSERT_EQ(data.begin(), data.end()); +  ASSERT_NE(data.AppendEmplace(1, 1), nullptr); +  ASSERT_EQ(data.size(), 1u); +  ASSERT_NE(data.begin(), data.end()); +  auto &D0 = *data.begin(); +  ASSERT_EQ(D0.First, 1); +  ASSERT_EQ(D0.Second, 1); + +  auto I0 = data.end(); +  ASSERT_EQ(I0--, data.end()); +  ASSERT_NE(I0, data.end()); +  ASSERT_EQ(I0, data.begin()); +  ASSERT_EQ(I0->First, 1); +  ASSERT_EQ(I0->Second, 1); +} + +TEST(SegmentedArrayTest, IteratorTrimBehaviour) { +  using AllocatorType = typename Array<TestData>::AllocatorType; +  AllocatorType A(1 << 20); +  Array<TestData> Data(A); +  ASSERT_TRUE(Data.empty()); +  auto I0Begin = Data.begin(), I0End = Data.end(); +  // Add enough elements in Data to have more than one chunk. +  constexpr auto Segment = Array<TestData>::SegmentSize; +  constexpr auto SegmentX2 = Segment * 2; +  for (auto i = SegmentX2; i > 0u; --i) { +    Data.AppendEmplace(static_cast<s64>(i), static_cast<s64>(i)); +  } +  ASSERT_EQ(Data.size(), SegmentX2); +  { +    auto &Back = Data.back(); +    ASSERT_EQ(Back.First, 1); +    ASSERT_EQ(Back.Second, 1); +  } + +  // Trim one chunk's elements worth. +  Data.trim(Segment); +  ASSERT_EQ(Data.size(), Segment); + +  // Check that we are still able to access 'back' properly. +  { +    auto &Back = Data.back(); +    ASSERT_EQ(Back.First, static_cast<s64>(Segment + 1)); +    ASSERT_EQ(Back.Second, static_cast<s64>(Segment + 1)); +  } + +  // Then trim until it's empty. +  Data.trim(Segment); +  ASSERT_TRUE(Data.empty()); + +  // Here our iterators should be the same. +  auto I1Begin = Data.begin(), I1End = Data.end(); +  EXPECT_EQ(I0Begin, I1Begin); +  EXPECT_EQ(I0End, I1End); + +  // Then we ensure that adding elements back works just fine. +  for (auto i = SegmentX2; i > 0u; --i) { +    Data.AppendEmplace(static_cast<s64>(i), static_cast<s64>(i)); +  } +  EXPECT_EQ(Data.size(), SegmentX2); +} + +struct ShadowStackEntry { +  uint64_t EntryTSC = 0; +  uint64_t *NodePtr = nullptr; +  ShadowStackEntry(uint64_t T, uint64_t *N) : EntryTSC(T), NodePtr(N) {} +}; + +TEST(SegmentedArrayTest, SimulateStackBehaviour) { +  using AllocatorType = typename Array<ShadowStackEntry>::AllocatorType; +  AllocatorType A(1 << 10); +  Array<ShadowStackEntry> Data(A); +  static uint64_t Dummy = 0; +  constexpr uint64_t Max = 9; + +  for (uint64_t i = 0; i < Max; ++i) { +    auto P = Data.Append({i, &Dummy}); +    ASSERT_NE(P, nullptr); +    ASSERT_EQ(P->NodePtr, &Dummy); +    auto &Back = Data.back(); +    ASSERT_EQ(Back.NodePtr, &Dummy); +    ASSERT_EQ(Back.EntryTSC, i); +  } + +  // Simulate a stack by checking the data from the end as we're trimming. +  auto Counter = Max; +  ASSERT_EQ(Data.size(), size_t(Max)); +  while (!Data.empty()) { +    const auto &Top = Data.back(); +    uint64_t *TopNode = Top.NodePtr; +    EXPECT_EQ(TopNode, &Dummy) << "Counter = " << Counter; +    Data.trim(1); +    --Counter; +    ASSERT_EQ(Data.size(), size_t(Counter)); +  } +} + +} // namespace +} // namespace __xray diff --git a/lib/xray/xray_AArch64.cc b/lib/xray/xray_AArch64.cc index f26e77dd7fc1f..096de009e83c5 100644 --- a/lib/xray/xray_AArch64.cc +++ b/lib/xray/xray_AArch64.cc @@ -112,6 +112,12 @@ bool patchCustomEvent(const bool Enable, const uint32_t FuncId,    return false;  } +bool patchTypedEvent(const bool Enable, const uint32_t FuncId, +                     const XRaySledEntry &Sled) XRAY_NEVER_INSTRUMENT { +  // FIXME: Implement in aarch64? +  return false; +} +  // FIXME: Maybe implement this better?  bool probeRequiredCPUFeatures() XRAY_NEVER_INSTRUMENT { return true; } diff --git a/lib/xray/xray_allocator.h b/lib/xray/xray_allocator.h new file mode 100644 index 0000000000000..8244815284a84 --- /dev/null +++ b/lib/xray/xray_allocator.h @@ -0,0 +1,129 @@ +//===-- xray_allocator.h ---------------------------------------*- C++ -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of XRay, a dynamic runtime instrumentation system. +// +// Defines the allocator interface for an arena allocator, used primarily for +// the profiling runtime. +// +//===----------------------------------------------------------------------===// +#ifndef XRAY_ALLOCATOR_H +#define XRAY_ALLOCATOR_H + +#include "sanitizer_common/sanitizer_common.h" +#include "sanitizer_common/sanitizer_internal_defs.h" +#include "sanitizer_common/sanitizer_mutex.h" +#include "sanitizer_common/sanitizer_posix.h" +#include "xray_utils.h" +#include <sys/mman.h> +#include <cstddef> +#include <cstdint> + +#ifndef MAP_NORESERVE +// no-op on NetBSD (at least), unsupported flag on FreeBSD basically because unneeded +#define MAP_NORESERVE 0 +#endif + +namespace __xray { + +/// The Allocator type hands out fixed-sized chunks of memory that are +/// cache-line aligned and sized. This is useful for placement of +/// performance-sensitive data in memory that's frequently accessed. The +/// allocator also self-limits the peak memory usage to a dynamically defined +/// maximum. +/// +/// N is the lower-bound size of the block of memory to return from the +/// allocation function. N is used to compute the size of a block, which is +/// cache-line-size multiples worth of memory. We compute the size of a block by +/// determining how many cache lines worth of memory is required to subsume N. +/// +/// The Allocator instance will manage its own memory acquired through mmap. +/// This severely constrains the platforms on which this can be used to POSIX +/// systems where mmap semantics are well-defined. +/// +/// FIXME: Isolate the lower-level memory management to a different abstraction +/// that can be platform-specific. +template <size_t N> struct Allocator { +  // The Allocator returns memory as Block instances. +  struct Block { +    /// Compute the minimum cache-line size multiple that is >= N. +    static constexpr auto Size = nearest_boundary(N, kCacheLineSize); +    void *Data; +  }; + +private: +  const size_t MaxMemory{0}; +  void *BackingStore = nullptr; +  void *AlignedNextBlock = nullptr; +  size_t AllocatedBlocks = 0; +  SpinMutex Mutex{}; + +  void *Alloc() { +    SpinMutexLock Lock(&Mutex); +    if (UNLIKELY(BackingStore == nullptr)) { +      BackingStore = reinterpret_cast<void *>( +          internal_mmap(NULL, MaxMemory, PROT_READ | PROT_WRITE, +                        MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, 0, 0)); +      if (BackingStore == MAP_FAILED) { +        BackingStore = nullptr; +        if (Verbosity()) +          Report("XRay Profiling: Failed to allocate memory for allocator.\n"); +        return nullptr; +      } + +      AlignedNextBlock = BackingStore; + +      // Ensure that NextBlock is aligned appropriately. +      auto BackingStoreNum = reinterpret_cast<uintptr_t>(BackingStore); +      auto AlignedNextBlockNum = nearest_boundary( +          reinterpret_cast<uintptr_t>(AlignedNextBlock), kCacheLineSize); +      if (diff(AlignedNextBlockNum, BackingStoreNum) > ptrdiff_t(MaxMemory)) { +        munmap(BackingStore, MaxMemory); +        AlignedNextBlock = BackingStore = nullptr; +        if (Verbosity()) +          Report("XRay Profiling: Cannot obtain enough memory from " +                 "preallocated region.\n"); +        return nullptr; +      } + +      AlignedNextBlock = reinterpret_cast<void *>(AlignedNextBlockNum); + +      // Assert that AlignedNextBlock is cache-line aligned. +      DCHECK_EQ(reinterpret_cast<uintptr_t>(AlignedNextBlock) % kCacheLineSize, +                0); +    } + +    if ((AllocatedBlocks * Block::Size) >= MaxMemory) +      return nullptr; + +    // Align the pointer we'd like to return to an appropriate alignment, then +    // advance the pointer from where to start allocations. +    void *Result = AlignedNextBlock; +    AlignedNextBlock = reinterpret_cast<void *>( +        reinterpret_cast<char *>(AlignedNextBlock) + N); +    ++AllocatedBlocks; +    return Result; +  } + +public: +  explicit Allocator(size_t M) +      : MaxMemory(nearest_boundary(M, kCacheLineSize)) {} + +  Block Allocate() { return {Alloc()}; } + +  ~Allocator() NOEXCEPT { +    if (BackingStore != nullptr) { +      internal_munmap(BackingStore, MaxMemory); +    } +  } +}; + +} // namespace __xray + +#endif // XRAY_ALLOCATOR_H diff --git a/lib/xray/xray_arm.cc b/lib/xray/xray_arm.cc index da4efcdd2b170..5b828287e3f69 100644 --- a/lib/xray/xray_arm.cc +++ b/lib/xray/xray_arm.cc @@ -149,6 +149,12 @@ bool patchCustomEvent(const bool Enable, const uint32_t FuncId,    return false;  } +bool patchTypedEvent(const bool Enable, const uint32_t FuncId, +                     const XRaySledEntry &Sled) XRAY_NEVER_INSTRUMENT { +  // FIXME: Implement in arm? +  return false; +} +  // FIXME: Maybe implement this better?  bool probeRequiredCPUFeatures() XRAY_NEVER_INSTRUMENT { return true; } diff --git a/lib/xray/xray_basic_flags.cc b/lib/xray/xray_basic_flags.cc new file mode 100644 index 0000000000000..14d805c71a886 --- /dev/null +++ b/lib/xray/xray_basic_flags.cc @@ -0,0 +1,50 @@ +//===-- xray_basic_flags.cc -------------------------------------*- C++ -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of XRay, a dynamic runtime instrumentation system. +// +// XRay Basic flag parsing logic. +//===----------------------------------------------------------------------===// + +#include "xray_basic_flags.h" +#include "sanitizer_common/sanitizer_common.h" +#include "sanitizer_common/sanitizer_flag_parser.h" +#include "sanitizer_common/sanitizer_libc.h" +#include "xray_defs.h" + +using namespace __sanitizer; + +namespace __xray { + +/// Use via basicFlags(). +BasicFlags xray_basic_flags_dont_use_directly; + +void BasicFlags::setDefaults() XRAY_NEVER_INSTRUMENT { +#define XRAY_FLAG(Type, Name, DefaultValue, Description) Name = DefaultValue; +#include "xray_basic_flags.inc" +#undef XRAY_FLAG +} + +void registerXRayBasicFlags(FlagParser *P, +                            BasicFlags *F) XRAY_NEVER_INSTRUMENT { +#define XRAY_FLAG(Type, Name, DefaultValue, Description)                       \ +  RegisterFlag(P, #Name, Description, &F->Name); +#include "xray_basic_flags.inc" +#undef XRAY_FLAG +} + +const char *useCompilerDefinedBasicFlags() XRAY_NEVER_INSTRUMENT { +#ifdef XRAY_BASIC_OPTIONS +  return SANITIZER_STRINGIFY(XRAY_BASIC_OPTIONS); +#else +  return ""; +#endif +} + +} // namespace __xray diff --git a/lib/xray/xray_basic_flags.h b/lib/xray/xray_basic_flags.h new file mode 100644 index 0000000000000..041578f0663ca --- /dev/null +++ b/lib/xray/xray_basic_flags.h @@ -0,0 +1,38 @@ +//===-- xray_basic_flags.h -------------------------------------*- C++ -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of XRay, a dynamic runtime instruementation system. +// +// XRay Basic Mode runtime flags. +//===----------------------------------------------------------------------===// + +#ifndef XRAY_BASIC_FLAGS_H +#define XRAY_BASIC_FLAGS_H + +#include "sanitizer_common/sanitizer_flag_parser.h" +#include "sanitizer_common/sanitizer_internal_defs.h" + +namespace __xray { + +struct BasicFlags { +#define XRAY_FLAG(Type, Name, DefaultValue, Description) Type Name; +#include "xray_basic_flags.inc" +#undef XRAY_FLAG + +  void setDefaults(); +}; + +extern BasicFlags xray_basic_flags_dont_use_directly; +extern void registerXRayBasicFlags(FlagParser *P, BasicFlags *F); +const char *useCompilerDefinedBasicFlags(); +inline BasicFlags *basicFlags() { return &xray_basic_flags_dont_use_directly; } + +} // namespace __xray + +#endif // XRAY_BASIC_FLAGS_H diff --git a/lib/xray/xray_basic_flags.inc b/lib/xray/xray_basic_flags.inc new file mode 100644 index 0000000000000..327735b510557 --- /dev/null +++ b/lib/xray/xray_basic_flags.inc @@ -0,0 +1,24 @@ +//===-- xray_basic_flags.inc ------------------------------------*- C++ -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// XRay runtime flags. +// +//===----------------------------------------------------------------------===// +#ifndef XRAY_FLAG +#error "Define XRAY_FLAG prior to including this file!" +#endif + +XRAY_FLAG(int, func_duration_threshold_us, 5, +          "Basic logging will try to skip functions that execute for fewer " +          "microseconds than this threshold.") +XRAY_FLAG(int, max_stack_depth, 64, +          "Basic logging will keep track of at most this deep a call stack, " +          "any more and the recordings will be dropped.") +XRAY_FLAG(int, thread_buffer_size, 1024, +          "The number of entries to keep on a per-thread buffer.") diff --git a/lib/xray/xray_inmemory_log.cc b/lib/xray/xray_basic_logging.cc index a27ffbcbd12ee..585ca641cd0cd 100644 --- a/lib/xray/xray_inmemory_log.cc +++ b/lib/xray/xray_basic_logging.cc @@ -1,4 +1,4 @@ -//===-- xray_inmemory_log.cc ------------------------------------*- C++ -*-===// +//===-- xray_basic_logging.cc -----------------------------------*- C++ -*-===//  //  //                     The LLVM Compiler Infrastructure  // @@ -15,8 +15,6 @@  //  //===----------------------------------------------------------------------===// -#include <cassert> -#include <cstring>  #include <errno.h>  #include <fcntl.h>  #include <pthread.h> @@ -29,16 +27,18 @@  #include "sanitizer_common/sanitizer_allocator_internal.h"  #include "sanitizer_common/sanitizer_libc.h"  #include "xray/xray_records.h" +#include "xray_recursion_guard.h" +#include "xray_basic_flags.h" +#include "xray_basic_logging.h"  #include "xray_defs.h"  #include "xray_flags.h" -#include "xray_inmemory_log.h"  #include "xray_interface_internal.h"  #include "xray_tsc.h"  #include "xray_utils.h"  namespace __xray { -__sanitizer::SpinMutex LogMutex; +SpinMutex LogMutex;  // We use elements of this type to record the entry TSC of every function ID we  // see as we're tracing a particular thread's execution. @@ -60,43 +60,41 @@ struct alignas(64) ThreadLocalData {    size_t StackSize = 0;    size_t StackEntries = 0;    int Fd = -1; -  pid_t TID = 0;  };  static pthread_key_t PThreadKey; -static __sanitizer::atomic_uint8_t BasicInitialized{0}; +static atomic_uint8_t BasicInitialized{0};  BasicLoggingOptions GlobalOptions; -thread_local volatile bool RecursionGuard = false; +thread_local atomic_uint8_t Guard{0}; -static uint64_t thresholdTicks() XRAY_NEVER_INSTRUMENT { -  static uint64_t TicksPerSec = probeRequiredCPUFeatures() -                                    ? getTSCFrequency() -                                    : __xray::NanosecondsPerSecond; -  static const uint64_t ThresholdTicks = -      TicksPerSec * GlobalOptions.DurationFilterMicros / 1000000; -  return ThresholdTicks; -} +static atomic_uint8_t UseRealTSC{0}; +static atomic_uint64_t ThresholdTicks{0}; +static atomic_uint64_t TicksPerSec{0}; +static atomic_uint64_t CycleFrequency{NanosecondsPerSecond};  static int openLogFile() XRAY_NEVER_INSTRUMENT {    int F = getLogFD();    if (F == -1)      return -1; -  // Test for required CPU features and cache the cycle frequency -  static bool TSCSupported = probeRequiredCPUFeatures(); -  static uint64_t CycleFrequency = -      TSCSupported ? getTSCFrequency() : __xray::NanosecondsPerSecond; +  static pthread_once_t DetectOnce = PTHREAD_ONCE_INIT; +  pthread_once(&DetectOnce, +[] { +    if (atomic_load(&UseRealTSC, memory_order_acquire)) +      atomic_store(&CycleFrequency, getTSCFrequency(), memory_order_release); +  });    // Since we're here, we get to write the header. We set it up so that the    // header will only be written once, at the start, and let the threads    // logging do writes which just append.    XRayFileHeader Header; -  Header.Version = 2; // Version 2 includes tail exit records. +  // Version 2 includes tail exit records. +  // Version 3 includes pid inside records. +  Header.Version = 3;    Header.Type = FileTypes::NAIVE_LOG; -  Header.CycleFrequency = CycleFrequency; +  Header.CycleFrequency = atomic_load(&CycleFrequency, memory_order_acquire);    // FIXME: Actually check whether we have 'constant_tsc' and 'nonstop_tsc'    // before setting the values in the header. @@ -107,20 +105,21 @@ static int openLogFile() XRAY_NEVER_INSTRUMENT {    return F;  } -int getGlobalFd() XRAY_NEVER_INSTRUMENT { -  static int Fd = openLogFile(); +static int getGlobalFd() XRAY_NEVER_INSTRUMENT { +  static pthread_once_t OnceInit = PTHREAD_ONCE_INIT; +  static int Fd = 0; +  pthread_once(&OnceInit, +[] { Fd = openLogFile(); });    return Fd;  } -ThreadLocalData &getThreadLocalData() XRAY_NEVER_INSTRUMENT { +static ThreadLocalData &getThreadLocalData() XRAY_NEVER_INSTRUMENT {    thread_local ThreadLocalData TLD;    thread_local bool UNUSED TOnce = [] {      if (GlobalOptions.ThreadBufferSize == 0) { -      if (__sanitizer::Verbosity()) +      if (Verbosity())          Report("Not initializing TLD since ThreadBufferSize == 0.\n");        return false;      } -    TLD.TID = __sanitizer::GetTid();      pthread_setspecific(PThreadKey, &TLD);      TLD.Fd = getGlobalFd();      TLD.InMemoryBuffer = reinterpret_cast<XRayRecord *>( @@ -129,7 +128,7 @@ ThreadLocalData &getThreadLocalData() XRAY_NEVER_INSTRUMENT {      TLD.BufferSize = GlobalOptions.ThreadBufferSize;      TLD.BufferOffset = 0;      if (GlobalOptions.MaxStackDepth == 0) { -      if (__sanitizer::Verbosity()) +      if (Verbosity())          Report("Not initializing the ShadowStack since MaxStackDepth == 0.\n");        TLD.StackSize = 0;        TLD.StackEntries = 0; @@ -141,13 +140,6 @@ ThreadLocalData &getThreadLocalData() XRAY_NEVER_INSTRUMENT {                        alignof(StackEntry)));      TLD.StackSize = GlobalOptions.MaxStackDepth;      TLD.StackEntries = 0; -    if (__sanitizer::Verbosity() >= 2) { -      static auto UNUSED Once = [] { -        auto ticks = thresholdTicks(); -        Report("Ticks threshold: %d\n", ticks); -        return false; -      }(); -    }      return false;    }();    return TLD; @@ -157,7 +149,6 @@ template <class RDTSC>  void InMemoryRawLog(int32_t FuncId, XRayEntryType Type,                      RDTSC ReadTSC) XRAY_NEVER_INSTRUMENT {    auto &TLD = getThreadLocalData(); -  auto &InMemoryBuffer = TLD.InMemoryBuffer;    int Fd = getGlobalFd();    if (Fd == -1)      return; @@ -165,10 +156,9 @@ void InMemoryRawLog(int32_t FuncId, XRayEntryType Type,    // Use a simple recursion guard, to handle cases where we're already logging    // and for one reason or another, this function gets called again in the same    // thread. -  if (RecursionGuard) +  RecursionGuard G(Guard); +  if (!G)      return; -  RecursionGuard = true; -  auto ExitGuard = __sanitizer::at_scope_exit([] { RecursionGuard = false; });    uint8_t CPU = 0;    uint64_t TSC = ReadTSC(CPU); @@ -189,7 +179,7 @@ void InMemoryRawLog(int32_t FuncId, XRayEntryType Type,      E.TSC = TSC;      auto StackEntryPtr = static_cast<char *>(TLD.ShadowStack) +                           (sizeof(StackEntry) * (TLD.StackEntries - 1)); -    __sanitizer::internal_memcpy(StackEntryPtr, &E, sizeof(StackEntry)); +    internal_memcpy(StackEntryPtr, &E, sizeof(StackEntry));      break;    }    case XRayEntryType::EXIT: @@ -213,12 +203,12 @@ void InMemoryRawLog(int32_t FuncId, XRayEntryType Type,      StackEntry StackTop;      auto StackEntryPtr = static_cast<char *>(TLD.ShadowStack) +                           (sizeof(StackEntry) * TLD.StackEntries); -    __sanitizer::internal_memcpy(&StackTop, StackEntryPtr, sizeof(StackEntry)); +    internal_memcpy(&StackTop, StackEntryPtr, sizeof(StackEntry));      if (StackTop.FuncId == FuncId && StackTop.CPU == CPU &&          StackTop.TSC < TSC) {        auto Delta = TSC - StackTop.TSC; -      if (Delta < thresholdTicks()) { -        assert(TLD.BufferOffset > 0); +      if (Delta < atomic_load(&ThresholdTicks, memory_order_relaxed)) { +        DCHECK(TLD.BufferOffset > 0);          TLD.BufferOffset -= StackTop.Type == XRayEntryType::ENTRY ? 1 : 2;          return;        } @@ -227,27 +217,26 @@ void InMemoryRawLog(int32_t FuncId, XRayEntryType Type,    }    default:      // Should be unreachable. -    assert(false && "Unsupported XRayEntryType encountered."); +    DCHECK(false && "Unsupported XRayEntryType encountered.");      break;    }    // First determine whether the delta between the function's enter record and    // the exit record is higher than the threshold. -  __xray::XRayRecord R; +  XRayRecord R;    R.RecordType = RecordTypes::NORMAL;    R.CPU = CPU;    R.TSC = TSC; -  R.TId = TLD.TID; +  R.TId = GetTid();  +  R.PId = internal_getpid();     R.Type = Type;    R.FuncId = FuncId; -  auto EntryPtr = static_cast<char *>(InMemoryBuffer) + -                  (sizeof(__xray::XRayRecord) * TLD.BufferOffset); -  __sanitizer::internal_memcpy(EntryPtr, &R, sizeof(R)); +  auto FirstEntry = reinterpret_cast<XRayRecord *>(TLD.InMemoryBuffer); +  internal_memcpy(FirstEntry + TLD.BufferOffset, &R, sizeof(R));    if (++TLD.BufferOffset == TLD.BufferSize) { -    __sanitizer::SpinMutexLock L(&LogMutex); -    auto RecordBuffer = reinterpret_cast<__xray::XRayRecord *>(InMemoryBuffer); -    retryingWriteAll(Fd, reinterpret_cast<char *>(RecordBuffer), -                     reinterpret_cast<char *>(RecordBuffer + TLD.BufferOffset)); +    SpinMutexLock L(&LogMutex); +    retryingWriteAll(Fd, reinterpret_cast<char *>(FirstEntry), +                     reinterpret_cast<char *>(FirstEntry + TLD.BufferOffset));      TLD.BufferOffset = 0;      TLD.StackEntries = 0;    } @@ -257,8 +246,8 @@ template <class RDTSC>  void InMemoryRawLogWithArg(int32_t FuncId, XRayEntryType Type, uint64_t Arg1,                             RDTSC ReadTSC) XRAY_NEVER_INSTRUMENT {    auto &TLD = getThreadLocalData(); -  auto &InMemoryBuffer = TLD.InMemoryBuffer; -  auto &Offset = TLD.BufferOffset; +  auto FirstEntry = +      reinterpret_cast<XRayArgPayload *>(TLD.InMemoryBuffer);    const auto &BuffLen = TLD.BufferSize;    int Fd = getGlobalFd();    if (Fd == -1) @@ -267,45 +256,41 @@ void InMemoryRawLogWithArg(int32_t FuncId, XRayEntryType Type, uint64_t Arg1,    // First we check whether there's enough space to write the data consecutively    // in the thread-local buffer. If not, we first flush the buffer before    // attempting to write the two records that must be consecutive. -  if (Offset + 2 > BuffLen) { -    __sanitizer::SpinMutexLock L(&LogMutex); -    auto RecordBuffer = reinterpret_cast<__xray::XRayRecord *>(InMemoryBuffer); -    retryingWriteAll(Fd, reinterpret_cast<char *>(RecordBuffer), -                     reinterpret_cast<char *>(RecordBuffer + Offset)); -    Offset = 0; +  if (TLD.BufferOffset + 2 > BuffLen) { +    SpinMutexLock L(&LogMutex); +    retryingWriteAll(Fd, reinterpret_cast<char *>(FirstEntry), +                     reinterpret_cast<char *>(FirstEntry + TLD.BufferOffset)); +    TLD.BufferOffset = 0;      TLD.StackEntries = 0;    }    // Then we write the "we have an argument" record.    InMemoryRawLog(FuncId, Type, ReadTSC); -  if (RecursionGuard) +  RecursionGuard G(Guard); +  if (!G)      return; -  RecursionGuard = true; -  auto ExitGuard = __sanitizer::at_scope_exit([] { RecursionGuard = false; }); -  // And from here on write the arg payload. -  __xray::XRayArgPayload R; +  // And, from here on write the arg payload. +  XRayArgPayload R;    R.RecordType = RecordTypes::ARG_PAYLOAD;    R.FuncId = FuncId; -  R.TId = TLD.TID; +  R.TId = GetTid();  +  R.PId = internal_getpid();     R.Arg = Arg1; -  auto EntryPtr = -      &reinterpret_cast<__xray::XRayArgPayload *>(&InMemoryBuffer)[Offset]; -  std::memcpy(EntryPtr, &R, sizeof(R)); -  if (++Offset == BuffLen) { -    __sanitizer::SpinMutexLock L(&LogMutex); -    auto RecordBuffer = reinterpret_cast<__xray::XRayRecord *>(InMemoryBuffer); -    retryingWriteAll(Fd, reinterpret_cast<char *>(RecordBuffer), -                     reinterpret_cast<char *>(RecordBuffer + Offset)); -    Offset = 0; +  internal_memcpy(FirstEntry + TLD.BufferOffset, &R, sizeof(R)); +  if (++TLD.BufferOffset == BuffLen) { +    SpinMutexLock L(&LogMutex); +    retryingWriteAll(Fd, reinterpret_cast<char *>(FirstEntry), +                     reinterpret_cast<char *>(FirstEntry + TLD.BufferOffset)); +    TLD.BufferOffset = 0;      TLD.StackEntries = 0;    }  }  void basicLoggingHandleArg0RealTSC(int32_t FuncId,                                     XRayEntryType Type) XRAY_NEVER_INSTRUMENT { -  InMemoryRawLog(FuncId, Type, __xray::readTSC); +  InMemoryRawLog(FuncId, Type, readTSC);  }  void basicLoggingHandleArg0EmulateTSC(int32_t FuncId, XRayEntryType Type) @@ -318,13 +303,13 @@ void basicLoggingHandleArg0EmulateTSC(int32_t FuncId, XRayEntryType Type)        TS = {0, 0};      }      CPU = 0; -    return TS.tv_sec * __xray::NanosecondsPerSecond + TS.tv_nsec; +    return TS.tv_sec * NanosecondsPerSecond + TS.tv_nsec;    });  }  void basicLoggingHandleArg1RealTSC(int32_t FuncId, XRayEntryType Type,                                     uint64_t Arg1) XRAY_NEVER_INSTRUMENT { -  InMemoryRawLogWithArg(FuncId, Type, Arg1, __xray::readTSC); +  InMemoryRawLogWithArg(FuncId, Type, Arg1, readTSC);  }  void basicLoggingHandleArg1EmulateTSC(int32_t FuncId, XRayEntryType Type, @@ -338,34 +323,34 @@ void basicLoggingHandleArg1EmulateTSC(int32_t FuncId, XRayEntryType Type,            TS = {0, 0};          }          CPU = 0; -        return TS.tv_sec * __xray::NanosecondsPerSecond + TS.tv_nsec; +        return TS.tv_sec * NanosecondsPerSecond + TS.tv_nsec;        });  }  static void TLDDestructor(void *P) XRAY_NEVER_INSTRUMENT {    ThreadLocalData &TLD = *reinterpret_cast<ThreadLocalData *>(P); -  auto ExitGuard = __sanitizer::at_scope_exit([&TLD] { +  auto ExitGuard = at_scope_exit([&TLD] {      // Clean up dynamic resources.      if (TLD.InMemoryBuffer)        InternalFree(TLD.InMemoryBuffer);      if (TLD.ShadowStack)        InternalFree(TLD.ShadowStack); -    if (__sanitizer::Verbosity()) -      Report("Cleaned up log for TID: %d\n", TLD.TID); +    if (Verbosity()) +      Report("Cleaned up log for TID: %d\n", GetTid());    });    if (TLD.Fd == -1 || TLD.BufferOffset == 0) { -    if (__sanitizer::Verbosity()) -      Report("Skipping buffer for TID: %d; Fd = %d; Offset = %llu\n", TLD.TID, +    if (Verbosity()) +      Report("Skipping buffer for TID: %d; Fd = %d; Offset = %llu\n", GetTid(),               TLD.Fd, TLD.BufferOffset);      return;    }    { -    __sanitizer::SpinMutexLock L(&LogMutex); +    SpinMutexLock L(&LogMutex);      retryingWriteAll(TLD.Fd, reinterpret_cast<char *>(TLD.InMemoryBuffer),                       reinterpret_cast<char *>(TLD.InMemoryBuffer) + -                         (sizeof(__xray::XRayRecord) * TLD.BufferOffset)); +                         (sizeof(XRayRecord) * TLD.BufferOffset));    }    // Because this thread's exit could be the last one trying to write to @@ -378,45 +363,89 @@ static void TLDDestructor(void *P) XRAY_NEVER_INSTRUMENT {  XRayLogInitStatus basicLoggingInit(size_t BufferSize, size_t BufferMax,                                     void *Options,                                     size_t OptionsSize) XRAY_NEVER_INSTRUMENT { -  static bool UNUSED Once = [] { -    pthread_key_create(&PThreadKey, TLDDestructor); -    return false; -  }(); -    uint8_t Expected = 0; -  if (!__sanitizer::atomic_compare_exchange_strong( -          &BasicInitialized, &Expected, 1, __sanitizer::memory_order_acq_rel)) { -    if (__sanitizer::Verbosity()) +  if (!atomic_compare_exchange_strong(&BasicInitialized, &Expected, 1, +                                      memory_order_acq_rel)) { +    if (Verbosity())        Report("Basic logging already initialized.\n");      return XRayLogInitStatus::XRAY_LOG_INITIALIZED;    } -  if (OptionsSize != sizeof(BasicLoggingOptions)) { +  static pthread_once_t OnceInit = PTHREAD_ONCE_INIT; +  pthread_once(&OnceInit, +[] { +    pthread_key_create(&PThreadKey, TLDDestructor); +    atomic_store(&UseRealTSC, probeRequiredCPUFeatures(), memory_order_release); +    // Initialize the global TicksPerSec value. +    atomic_store(&TicksPerSec, +                 probeRequiredCPUFeatures() ? getTSCFrequency() +                                            : NanosecondsPerSecond, +                 memory_order_release); +    if (!atomic_load(&UseRealTSC, memory_order_relaxed) && Verbosity()) +      Report("WARNING: Required CPU features missing for XRay instrumentation, " +             "using emulation instead.\n"); +  }); + +  if (BufferSize == 0 && BufferMax == 0 && Options != nullptr) { +    FlagParser P; +    BasicFlags F; +    F.setDefaults(); +    registerXRayBasicFlags(&P, &F); +    P.ParseString(useCompilerDefinedBasicFlags()); +    auto *EnvOpts = GetEnv("XRAY_BASIC_OPTIONS"); +    if (EnvOpts == nullptr) +      EnvOpts = ""; + +    P.ParseString(EnvOpts); + +    // If XRAY_BASIC_OPTIONS was not defined, then we use the deprecated options +    // set through XRAY_OPTIONS instead. +    if (internal_strlen(EnvOpts) == 0) { +      F.func_duration_threshold_us = +          flags()->xray_naive_log_func_duration_threshold_us; +      F.max_stack_depth = flags()->xray_naive_log_max_stack_depth; +      F.thread_buffer_size = flags()->xray_naive_log_thread_buffer_size; +    } + +    P.ParseString(static_cast<const char *>(Options)); +    GlobalOptions.ThreadBufferSize = F.thread_buffer_size; +    GlobalOptions.DurationFilterMicros = F.func_duration_threshold_us; +    GlobalOptions.MaxStackDepth = F.max_stack_depth; +    *basicFlags() = F; +  } else if (OptionsSize != sizeof(BasicLoggingOptions)) {      Report("Invalid options size, potential ABI mismatch; expected %d got %d",             sizeof(BasicLoggingOptions), OptionsSize);      return XRayLogInitStatus::XRAY_LOG_UNINITIALIZED; +  } else { +    if (Verbosity()) +      Report("XRay Basic: struct-based init is deprecated, please use " +             "string-based configuration instead.\n"); +    GlobalOptions = *reinterpret_cast<BasicLoggingOptions *>(Options);    } -  static auto UseRealTSC = probeRequiredCPUFeatures(); -  if (!UseRealTSC && __sanitizer::Verbosity()) -    Report("WARNING: Required CPU features missing for XRay instrumentation, " -           "using emulation instead.\n"); - -  GlobalOptions = *reinterpret_cast<BasicLoggingOptions *>(Options); -  __xray_set_handler_arg1(UseRealTSC ? basicLoggingHandleArg1RealTSC -                                     : basicLoggingHandleArg1EmulateTSC); -  __xray_set_handler(UseRealTSC ? basicLoggingHandleArg0RealTSC -                                : basicLoggingHandleArg0EmulateTSC); +  atomic_store(&ThresholdTicks, +               atomic_load(&TicksPerSec, memory_order_acquire) * +                   GlobalOptions.DurationFilterMicros / 1000000, +               memory_order_release); +  __xray_set_handler_arg1(atomic_load(&UseRealTSC, memory_order_acquire) +                              ? basicLoggingHandleArg1RealTSC +                              : basicLoggingHandleArg1EmulateTSC); +  __xray_set_handler(atomic_load(&UseRealTSC, memory_order_acquire) +                         ? basicLoggingHandleArg0RealTSC +                         : basicLoggingHandleArg0EmulateTSC); + +  // TODO: Implement custom event and typed event handling support in Basic +  // Mode.    __xray_remove_customevent_handler(); +  __xray_remove_typedevent_handler();    return XRayLogInitStatus::XRAY_LOG_INITIALIZED;  }  XRayLogInitStatus basicLoggingFinalize() XRAY_NEVER_INSTRUMENT {    uint8_t Expected = 0; -  if (!__sanitizer::atomic_compare_exchange_strong( -          &BasicInitialized, &Expected, 0, __sanitizer::memory_order_acq_rel) && -      __sanitizer::Verbosity()) +  if (!atomic_compare_exchange_strong(&BasicInitialized, &Expected, 0, +                                      memory_order_acq_rel) && +      Verbosity())      Report("Basic logging already finalized.\n");    // Nothing really to do aside from marking state of the global to be @@ -444,24 +473,41 @@ bool basicLogDynamicInitializer() XRAY_NEVER_INSTRUMENT {    };    auto RegistrationResult = __xray_log_register_mode("xray-basic", Impl);    if (RegistrationResult != XRayLogRegisterStatus::XRAY_REGISTRATION_OK && -      __sanitizer::Verbosity()) +      Verbosity())      Report("Cannot register XRay Basic Mode to 'xray-basic'; error = %d\n",             RegistrationResult);    if (flags()->xray_naive_log || -      !__sanitizer::internal_strcmp(flags()->xray_mode, "xray-basic")) { -    __xray_set_log_impl(Impl); -    BasicLoggingOptions Options; -    Options.DurationFilterMicros = -        flags()->xray_naive_log_func_duration_threshold_us; -    Options.MaxStackDepth = flags()->xray_naive_log_max_stack_depth; -    Options.ThreadBufferSize = flags()->xray_naive_log_thread_buffer_size; -    __xray_log_init(flags()->xray_naive_log_thread_buffer_size, 0, &Options, -                    sizeof(BasicLoggingOptions)); -    static auto UNUSED Once = [] { -      static auto UNUSED &TLD = getThreadLocalData(); -      __sanitizer::Atexit(+[] { TLDDestructor(&TLD); }); +      !internal_strcmp(flags()->xray_mode, "xray-basic")) { +    auto SelectResult = __xray_log_select_mode("xray-basic"); +    if (SelectResult != XRayLogRegisterStatus::XRAY_REGISTRATION_OK) { +      if (Verbosity()) +        Report("Failed selecting XRay Basic Mode; error = %d\n", SelectResult);        return false; -    }(); +    } + +    // We initialize the implementation using the data we get from the +    // XRAY_BASIC_OPTIONS environment variable, at this point of the +    // implementation. +    auto *Env = GetEnv("XRAY_BASIC_OPTIONS"); +    auto InitResult = +        __xray_log_init_mode("xray-basic", Env == nullptr ? "" : Env); +    if (InitResult != XRayLogInitStatus::XRAY_LOG_INITIALIZED) { +      if (Verbosity()) +        Report("Failed initializing XRay Basic Mode; error = %d\n", InitResult); +      return false; +    } + +    // At this point we know that we've successfully initialized Basic mode +    // tracing, and the only chance we're going to get for the current thread to +    // clean-up may be at thread/program exit. To ensure that we're going to get +    // the cleanup even without calling the finalization routines, we're +    // registering a program exit function that will do the cleanup. +    static pthread_once_t DynamicOnce = PTHREAD_ONCE_INIT; +    pthread_once(&DynamicOnce, +[] { +      static void *FakeTLD = nullptr; +      FakeTLD = &getThreadLocalData(); +      Atexit(+[] { TLDDestructor(FakeTLD); }); +    });    }    return true;  } diff --git a/lib/xray/xray_inmemory_log.h b/lib/xray/xray_basic_logging.h index e4fcb8ca5ffdc..1639b96d91a1a 100644 --- a/lib/xray/xray_inmemory_log.h +++ b/lib/xray/xray_basic_logging.h @@ -1,5 +1,4 @@ -//===-- xray_inmemory_log.h -//------------------------------------------------===// +//===-- xray_basic_logging.h ----------------------------------------------===//  //  //                     The LLVM Compiler Infrastructure  // diff --git a/lib/xray/xray_buffer_queue.cc b/lib/xray/xray_buffer_queue.cc index a0018f6b0cba4..8dfcc23540b12 100644 --- a/lib/xray/xray_buffer_queue.cc +++ b/lib/xray/xray_buffer_queue.cc @@ -16,14 +16,37 @@  #include "sanitizer_common/sanitizer_allocator_internal.h"  #include "sanitizer_common/sanitizer_common.h"  #include "sanitizer_common/sanitizer_libc.h" +#include <memory>  using namespace __xray;  using namespace __sanitizer; +template <class T> static T *initArray(size_t N) { +  auto A = reinterpret_cast<T *>( +      InternalAlloc(N * sizeof(T), nullptr, kCacheLineSize)); +  if (A != nullptr) +    while (N > 0) +      new (A + (--N)) T(); +  return A; +} +  BufferQueue::BufferQueue(size_t B, size_t N, bool &Success) -    : BufferSize(B), Buffers(new BufferRep[N]()), BufferCount(N), Finalizing{0}, -      OwnedBuffers(new void *[N]()), Next(Buffers), First(Buffers), -      LiveBuffers(0) { +    : BufferSize(B), Buffers(initArray<BufferQueue::BufferRep>(N)), +      BufferCount(N), Finalizing{0}, OwnedBuffers(initArray<void *>(N)), +      Next(Buffers), First(Buffers), LiveBuffers(0) { +  if (Buffers == nullptr) { +    Success = false; +    return; +  } +  if (OwnedBuffers == nullptr) { +    // Clean up the buffers we've already allocated. +    for (auto B = Buffers, E = Buffers + BufferCount; B != E; ++B) +      B->~BufferRep(); +    InternalFree(Buffers); +    Success = false; +    return; +  }; +    for (size_t i = 0; i < N; ++i) {      auto &T = Buffers[i];      void *Tmp = InternalAlloc(BufferSize, nullptr, 64); @@ -37,7 +60,7 @@ BufferQueue::BufferQueue(size_t B, size_t N, bool &Success)        return;      }      auto &Buf = T.Buff; -    Buf.Buffer = Tmp; +    Buf.Data = Tmp;      Buf.Size = B;      Buf.Extents = reinterpret_cast<BufferExtents *>(Extents);      OwnedBuffers[i] = Tmp; @@ -46,9 +69,9 @@ BufferQueue::BufferQueue(size_t B, size_t N, bool &Success)  }  BufferQueue::ErrorCode BufferQueue::getBuffer(Buffer &Buf) { -  if (__sanitizer::atomic_load(&Finalizing, __sanitizer::memory_order_acquire)) +  if (atomic_load(&Finalizing, memory_order_acquire))      return ErrorCode::QueueFinalizing; -  __sanitizer::SpinMutexLock Guard(&Mutex); +  SpinMutexLock Guard(&Mutex);    if (LiveBuffers == BufferCount)      return ErrorCode::NotEnoughMemory; @@ -68,7 +91,7 @@ BufferQueue::ErrorCode BufferQueue::releaseBuffer(Buffer &Buf) {    // Blitz through the buffers array to find the buffer.    bool Found = false;    for (auto I = OwnedBuffers, E = OwnedBuffers + BufferCount; I != E; ++I) { -    if (*I == Buf.Buffer) { +    if (*I == Buf.Data) {        Found = true;        break;      } @@ -76,7 +99,7 @@ BufferQueue::ErrorCode BufferQueue::releaseBuffer(Buffer &Buf) {    if (!Found)      return ErrorCode::UnrecognizedBuffer; -  __sanitizer::SpinMutexLock Guard(&Mutex); +  SpinMutexLock Guard(&Mutex);    // This points to a semantic bug, we really ought to not be releasing more    // buffers than we actually get. @@ -86,7 +109,7 @@ BufferQueue::ErrorCode BufferQueue::releaseBuffer(Buffer &Buf) {    // Now that the buffer has been released, we mark it as "used".    First->Buff = Buf;    First->Used = true; -  Buf.Buffer = nullptr; +  Buf.Data = nullptr;    Buf.Size = 0;    --LiveBuffers;    if (++First == (Buffers + BufferCount)) @@ -96,8 +119,7 @@ BufferQueue::ErrorCode BufferQueue::releaseBuffer(Buffer &Buf) {  }  BufferQueue::ErrorCode BufferQueue::finalize() { -  if (__sanitizer::atomic_exchange(&Finalizing, 1, -                                   __sanitizer::memory_order_acq_rel)) +  if (atomic_exchange(&Finalizing, 1, memory_order_acq_rel))      return ErrorCode::QueueFinalizing;    return ErrorCode::Ok;  } @@ -106,9 +128,11 @@ BufferQueue::~BufferQueue() {    for (auto I = Buffers, E = Buffers + BufferCount; I != E; ++I) {      auto &T = *I;      auto &Buf = T.Buff; -    InternalFree(Buf.Buffer); +    InternalFree(Buf.Data);      InternalFree(Buf.Extents);    } -  delete[] Buffers; -  delete[] OwnedBuffers; +  for (auto B = Buffers, E = Buffers + BufferCount; B != E; ++B) +    B->~BufferRep(); +  InternalFree(Buffers); +  InternalFree(OwnedBuffers);  } diff --git a/lib/xray/xray_buffer_queue.h b/lib/xray/xray_buffer_queue.h index 1ceb582746165..e76fa7983c90e 100644 --- a/lib/xray/xray_buffer_queue.h +++ b/lib/xray/xray_buffer_queue.h @@ -15,9 +15,10 @@  #ifndef XRAY_BUFFER_QUEUE_H  #define XRAY_BUFFER_QUEUE_H -#include <cstddef>  #include "sanitizer_common/sanitizer_atomic.h" +#include "sanitizer_common/sanitizer_common.h"  #include "sanitizer_common/sanitizer_mutex.h" +#include <cstddef>  namespace __xray { @@ -27,18 +28,17 @@ namespace __xray {  /// the "flight data recorder" (FDR) mode to support ongoing XRay function call  /// trace collection.  class BufferQueue { - public: +public:    struct alignas(64) BufferExtents { -    __sanitizer::atomic_uint64_t Size; +    atomic_uint64_t Size;    };    struct Buffer { -    void *Buffer = nullptr; +    void *Data = nullptr;      size_t Size = 0; -    BufferExtents* Extents; +    BufferExtents *Extents;    }; - private:    struct BufferRep {      // The managed buffer.      Buffer Buff; @@ -48,14 +48,72 @@ class BufferQueue {      bool Used = false;    }; +private: +  // This models a ForwardIterator. |T| Must be either a `Buffer` or `const +  // Buffer`. Note that we only advance to the "used" buffers, when +  // incrementing, so that at dereference we're always at a valid point. +  template <class T> class Iterator { +  public: +    BufferRep *Buffers = nullptr; +    size_t Offset = 0; +    size_t Max = 0; + +    Iterator &operator++() { +      DCHECK_NE(Offset, Max); +      do { +        ++Offset; +      } while (!Buffers[Offset].Used && Offset != Max); +      return *this; +    } + +    Iterator operator++(int) { +      Iterator C = *this; +      ++(*this); +      return C; +    } + +    T &operator*() const { return Buffers[Offset].Buff; } + +    T *operator->() const { return &(Buffers[Offset].Buff); } + +    Iterator(BufferRep *Root, size_t O, size_t M) +        : Buffers(Root), Offset(O), Max(M) { +      // We want to advance to the first Offset where the 'Used' property is +      // true, or to the end of the list/queue. +      while (!Buffers[Offset].Used && Offset != Max) { +        ++Offset; +      } +    } + +    Iterator() = default; +    Iterator(const Iterator &) = default; +    Iterator(Iterator &&) = default; +    Iterator &operator=(const Iterator &) = default; +    Iterator &operator=(Iterator &&) = default; +    ~Iterator() = default; + +    template <class V> +    friend bool operator==(const Iterator &L, const Iterator<V> &R) { +      DCHECK_EQ(L.Max, R.Max); +      return L.Buffers == R.Buffers && L.Offset == R.Offset; +    } + +    template <class V> +    friend bool operator!=(const Iterator &L, const Iterator<V> &R) { +      return !(L == R); +    } +  }; +    // Size of each individual Buffer.    size_t BufferSize;    BufferRep *Buffers; + +  // Amount of pre-allocated buffers.    size_t BufferCount; -  __sanitizer::SpinMutex Mutex; -  __sanitizer::atomic_uint8_t Finalizing; +  SpinMutex Mutex; +  atomic_uint8_t Finalizing;    // Pointers to buffers managed/owned by the BufferQueue.    void **OwnedBuffers; @@ -70,7 +128,7 @@ class BufferQueue {    // Count of buffers that have been handed out through 'getBuffer'.    size_t LiveBuffers; - public: +public:    enum class ErrorCode : unsigned {      Ok,      NotEnoughMemory, @@ -81,16 +139,16 @@ class BufferQueue {    static const char *getErrorString(ErrorCode E) {      switch (E) { -      case ErrorCode::Ok: -        return "(none)"; -      case ErrorCode::NotEnoughMemory: -        return "no available buffers in the queue"; -      case ErrorCode::QueueFinalizing: -        return "queue already finalizing"; -      case ErrorCode::UnrecognizedBuffer: -        return "buffer being returned not owned by buffer queue"; -      case ErrorCode::AlreadyFinalized: -        return "queue already finalized"; +    case ErrorCode::Ok: +      return "(none)"; +    case ErrorCode::NotEnoughMemory: +      return "no available buffers in the queue"; +    case ErrorCode::QueueFinalizing: +      return "queue already finalizing"; +    case ErrorCode::UnrecognizedBuffer: +      return "buffer being returned not owned by buffer queue"; +    case ErrorCode::AlreadyFinalized: +      return "queue already finalized";      }      return "unknown error";    } @@ -122,8 +180,7 @@ class BufferQueue {    ErrorCode releaseBuffer(Buffer &Buf);    bool finalizing() const { -    return __sanitizer::atomic_load(&Finalizing, -                                    __sanitizer::memory_order_acquire); +    return atomic_load(&Finalizing, memory_order_acquire);    }    /// Returns the configured size of the buffers in the buffer queue. @@ -141,19 +198,29 @@ class BufferQueue {    /// Applies the provided function F to each Buffer in the queue, only if the    /// Buffer is marked 'used' (i.e. has been the result of getBuffer(...) and a    /// releaseBuffer(...) operation). -  template <class F> -  void apply(F Fn) { -    __sanitizer::SpinMutexLock G(&Mutex); -    for (auto I = Buffers, E = Buffers + BufferCount; I != E; ++I) { -      const auto &T = *I; -      if (T.Used) Fn(T.Buff); -    } +  template <class F> void apply(F Fn) { +    SpinMutexLock G(&Mutex); +    for (auto I = begin(), E = end(); I != E; ++I) +      Fn(*I); +  } + +  using const_iterator = Iterator<const Buffer>; +  using iterator = Iterator<Buffer>; + +  /// Provides iterator access to the raw Buffer instances. +  iterator begin() const { return iterator(Buffers, 0, BufferCount); } +  const_iterator cbegin() const { +    return const_iterator(Buffers, 0, BufferCount); +  } +  iterator end() const { return iterator(Buffers, BufferCount, BufferCount); } +  const_iterator cend() const { +    return const_iterator(Buffers, BufferCount, BufferCount);    }    // Cleans up allocated buffers.    ~BufferQueue();  }; -}  // namespace __xray +} // namespace __xray -#endif  // XRAY_BUFFER_QUEUE_H +#endif // XRAY_BUFFER_QUEUE_H diff --git a/lib/xray/xray_fdr_flags.cc b/lib/xray/xray_fdr_flags.cc new file mode 100644 index 0000000000000..a14851b1b616e --- /dev/null +++ b/lib/xray/xray_fdr_flags.cc @@ -0,0 +1,48 @@ +//===-- xray_fdr_flags.cc ---------------------------------------*- C++ -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of XRay, a dynamic runtime instrumentation system. +// +// XRay FDR flag parsing logic. +//===----------------------------------------------------------------------===// + +#include "xray_fdr_flags.h" +#include "sanitizer_common/sanitizer_common.h" +#include "sanitizer_common/sanitizer_flag_parser.h" +#include "sanitizer_common/sanitizer_libc.h" +#include "xray_defs.h" + +using namespace __sanitizer; + +namespace __xray { + +FDRFlags xray_fdr_flags_dont_use_directly; // use via fdrFlags(). + +void FDRFlags::setDefaults() XRAY_NEVER_INSTRUMENT { +#define XRAY_FLAG(Type, Name, DefaultValue, Description) Name = DefaultValue; +#include "xray_fdr_flags.inc" +#undef XRAY_FLAG +} + +void registerXRayFDRFlags(FlagParser *P, FDRFlags *F) XRAY_NEVER_INSTRUMENT { +#define XRAY_FLAG(Type, Name, DefaultValue, Description)                       \ +  RegisterFlag(P, #Name, Description, &F->Name); +#include "xray_fdr_flags.inc" +#undef XRAY_FLAG +} + +const char *useCompilerDefinedFDRFlags() XRAY_NEVER_INSTRUMENT { +#ifdef XRAY_FDR_OPTIONS +  return SANITIZER_STRINGIFY(XRAY_FDR_OPTIONS); +#else +  return ""; +#endif +} + +} // namespace __xray diff --git a/lib/xray/xray_fdr_flags.h b/lib/xray/xray_fdr_flags.h new file mode 100644 index 0000000000000..9c953f1cabcf5 --- /dev/null +++ b/lib/xray/xray_fdr_flags.h @@ -0,0 +1,38 @@ +//===-- xray_fdr_flags.h ---------------------------------------*- C++ -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of XRay, a dynamic runtime instrumentation system. +// +// This file defines the flags for the flight-data-recorder mode implementation. +// +//===----------------------------------------------------------------------===// +#ifndef XRAY_FDR_FLAGS_H +#define XRAY_FDR_FLAGS_H + +#include "sanitizer_common/sanitizer_flag_parser.h" +#include "sanitizer_common/sanitizer_internal_defs.h" + +namespace __xray { + +struct FDRFlags { +#define XRAY_FLAG(Type, Name, DefaultValue, Description) Type Name; +#include "xray_fdr_flags.inc" +#undef XRAY_FLAG + +  void setDefaults(); +}; + +extern FDRFlags xray_fdr_flags_dont_use_directly; +extern void registerXRayFDRFlags(FlagParser *P, FDRFlags *F); +const char *useCompilerDefinedFDRFlags(); +inline FDRFlags *fdrFlags() { return &xray_fdr_flags_dont_use_directly; } + +} // namespace __xray + +#endif // XRAY_FDR_FLAGS_H diff --git a/lib/xray/xray_fdr_flags.inc b/lib/xray/xray_fdr_flags.inc new file mode 100644 index 0000000000000..d8721ad12cbe0 --- /dev/null +++ b/lib/xray/xray_fdr_flags.inc @@ -0,0 +1,29 @@ +//===-- xray_fdr_flags.inc --------------------------------------*- C++ -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// XRay FDR Mode runtime flags. +// +//===----------------------------------------------------------------------===// +#ifndef XRAY_FLAG +#error "Define XRAY_FLAG prior to including this file!" +#endif + +// FDR (Flight Data Recorder) Mode logging options. +XRAY_FLAG(int, func_duration_threshold_us, 5, +          "FDR logging will try to skip functions that execute for fewer " +          "microseconds than this threshold.") +XRAY_FLAG(int, grace_period_ms, 100, +          "FDR logging will wait this much time in milliseconds before " +          "actually flushing the log; this gives a chance for threads to " +          "notice that the log has been finalized and clean up.") +XRAY_FLAG(int, buffer_size, 16384, +          "Size of buffers in the circular buffer queue.") +XRAY_FLAG(int, buffer_max, 100, "Maximum number of buffers in the queue.") +XRAY_FLAG(bool, no_file_flush, false, +          "Set to true to not write log files by default.") diff --git a/lib/xray/xray_fdr_log_records.h b/lib/xray/xray_fdr_log_records.h index 324208db82ca0..87096d4fc29eb 100644 --- a/lib/xray/xray_fdr_log_records.h +++ b/lib/xray/xray_fdr_log_records.h @@ -32,6 +32,8 @@ struct alignas(16) MetadataRecord {      CustomEventMarker,      CallArgument,      BufferExtents, +    TypedEventMarker, +    Pid,    };    // Use 7 bits to identify this record type. diff --git a/lib/xray/xray_fdr_logging.cc b/lib/xray/xray_fdr_logging.cc index 1bfa10c21f5cd..6cb2dfa0c658f 100644 --- a/lib/xray/xray_fdr_logging.cc +++ b/lib/xray/xray_fdr_logging.cc @@ -15,64 +15,836 @@  //  //===----------------------------------------------------------------------===//  #include "xray_fdr_logging.h" +#include <cassert>  #include <errno.h> +#include <limits> +#include <memory> +#include <pthread.h>  #include <sys/syscall.h>  #include <sys/time.h>  #include <time.h>  #include <unistd.h> +#include "sanitizer_common/sanitizer_allocator_internal.h"  #include "sanitizer_common/sanitizer_atomic.h"  #include "sanitizer_common/sanitizer_common.h"  #include "xray/xray_interface.h"  #include "xray/xray_records.h"  #include "xray_buffer_queue.h"  #include "xray_defs.h" -#include "xray_fdr_logging_impl.h" +#include "xray_fdr_flags.h"  #include "xray_flags.h" +#include "xray_recursion_guard.h"  #include "xray_tsc.h"  #include "xray_utils.h"  namespace __xray { +atomic_sint32_t LoggingStatus = {XRayLogInitStatus::XRAY_LOG_UNINITIALIZED}; + +// Group together thread-local-data in a struct, then hide it behind a function +// call so that it can be initialized on first use instead of as a global. We +// force the alignment to 64-bytes for x86 cache line alignment, as this +// structure is used in the hot path of implementation. +struct alignas(64) ThreadLocalData { +  BufferQueue::Buffer Buffer; +  char *RecordPtr = nullptr; +  // The number of FunctionEntry records immediately preceding RecordPtr. +  uint8_t NumConsecutiveFnEnters = 0; + +  // The number of adjacent, consecutive pairs of FunctionEntry, Tail Exit +  // records preceding RecordPtr. +  uint8_t NumTailCalls = 0; + +  // We use a thread_local variable to keep track of which CPUs we've already +  // run, and the TSC times for these CPUs. This allows us to stop repeating the +  // CPU field in the function records. +  // +  // We assume that we'll support only 65536 CPUs for x86_64. +  uint16_t CurrentCPU = std::numeric_limits<uint16_t>::max(); +  uint64_t LastTSC = 0; +  uint64_t LastFunctionEntryTSC = 0; + +  // Make sure a thread that's ever called handleArg0 has a thread-local +  // live reference to the buffer queue for this particular instance of +  // FDRLogging, and that we're going to clean it up when the thread exits. +  BufferQueue *BQ = nullptr; +}; + +static_assert(std::is_trivially_destructible<ThreadLocalData>::value, +              "ThreadLocalData must be trivially destructible"); + +static constexpr auto MetadataRecSize = sizeof(MetadataRecord); +static constexpr auto FunctionRecSize = sizeof(FunctionRecord); + +// Use a global pthread key to identify thread-local data for logging. +static pthread_key_t Key; +  // Global BufferQueue. -BufferQueue *BQ = nullptr; +static BufferQueue *BQ = nullptr; -__sanitizer::atomic_sint32_t LogFlushStatus = { +static atomic_sint32_t LogFlushStatus = {      XRayLogFlushStatus::XRAY_LOG_NOT_FLUSHING}; -FDRLoggingOptions FDROptions; +static FDRLoggingOptions FDROptions; + +static SpinMutex FDROptionsMutex; + +// This function will initialize the thread-local data structure used by the FDR +// logging implementation and return a reference to it. The implementation +// details require a bit of care to maintain. +// +// First, some requirements on the implementation in general: +// +//   - XRay handlers should not call any memory allocation routines that may +//     delegate to an instrumented implementation. This means functions like +//     malloc() and free() should not be called while instrumenting. +// +//   - We would like to use some thread-local data initialized on first-use of +//     the XRay instrumentation. These allow us to implement unsynchronized +//     routines that access resources associated with the thread. +// +// The implementation here uses a few mechanisms that allow us to provide both +// the requirements listed above. We do this by: +// +//   1. Using a thread-local aligned storage buffer for representing the +//      ThreadLocalData struct. This data will be uninitialized memory by +//      design. +// +//   2. Not requiring a thread exit handler/implementation, keeping the +//      thread-local as purely a collection of references/data that do not +//      require cleanup. +// +// We're doing this to avoid using a `thread_local` object that has a +// non-trivial destructor, because the C++ runtime might call std::malloc(...) +// to register calls to destructors. Deadlocks may arise when, for example, an +// externally provided malloc implementation is XRay instrumented, and +// initializing the thread-locals involves calling into malloc. A malloc +// implementation that does global synchronization might be holding a lock for a +// critical section, calling a function that might be XRay instrumented (and +// thus in turn calling into malloc by virtue of registration of the +// thread_local's destructor). +static_assert(alignof(ThreadLocalData) >= 64, +              "ThreadLocalData must be cache line aligned."); +static ThreadLocalData &getThreadLocalData() { +  thread_local typename std::aligned_storage< +      sizeof(ThreadLocalData), alignof(ThreadLocalData)>::type TLDStorage{}; + +  if (pthread_getspecific(Key) == NULL) { +    new (reinterpret_cast<ThreadLocalData *>(&TLDStorage)) ThreadLocalData{}; +    pthread_setspecific(Key, &TLDStorage); +  } + +  return *reinterpret_cast<ThreadLocalData *>(&TLDStorage); +} + +static void writeNewBufferPreamble(tid_t Tid, timespec TS, +                                   pid_t Pid) XRAY_NEVER_INSTRUMENT { +  static constexpr int InitRecordsCount = 3; +  auto &TLD = getThreadLocalData(); +  MetadataRecord Metadata[InitRecordsCount]; +  { +    // Write out a MetadataRecord to signify that this is the start of a new +    // buffer, associated with a particular thread, with a new CPU.  For the +    // data, we have 15 bytes to squeeze as much information as we can.  At this +    // point we only write down the following bytes: +    //   - Thread ID (tid_t, cast to 4 bytes type due to Darwin being 8 bytes) +    auto &NewBuffer = Metadata[0]; +    NewBuffer.Type = uint8_t(RecordType::Metadata); +    NewBuffer.RecordKind = uint8_t(MetadataRecord::RecordKinds::NewBuffer); +    int32_t tid = static_cast<int32_t>(Tid); +    internal_memcpy(&NewBuffer.Data, &tid, sizeof(tid)); +  } + +  // Also write the WalltimeMarker record. +  { +    static_assert(sizeof(time_t) <= 8, "time_t needs to be at most 8 bytes"); +    auto &WalltimeMarker = Metadata[1]; +    WalltimeMarker.Type = uint8_t(RecordType::Metadata); +    WalltimeMarker.RecordKind = +        uint8_t(MetadataRecord::RecordKinds::WalltimeMarker); + +    // We only really need microsecond precision here, and enforce across +    // platforms that we need 64-bit seconds and 32-bit microseconds encoded in +    // the Metadata record. +    int32_t Micros = TS.tv_nsec / 1000; +    int64_t Seconds = TS.tv_sec; +    internal_memcpy(WalltimeMarker.Data, &Seconds, sizeof(Seconds)); +    internal_memcpy(WalltimeMarker.Data + sizeof(Seconds), &Micros, +                    sizeof(Micros)); +  } + +  // Also write the Pid record. +  { +    // Write out a MetadataRecord that contains the current pid +    auto &PidMetadata = Metadata[2]; +    PidMetadata.Type = uint8_t(RecordType::Metadata); +    PidMetadata.RecordKind = uint8_t(MetadataRecord::RecordKinds::Pid); +    int32_t pid = static_cast<int32_t>(Pid); +    internal_memcpy(&PidMetadata.Data, &pid, sizeof(pid)); +  } + +  TLD.NumConsecutiveFnEnters = 0; +  TLD.NumTailCalls = 0; +  if (TLD.BQ == nullptr || TLD.BQ->finalizing()) +    return; +  internal_memcpy(TLD.RecordPtr, Metadata, sizeof(Metadata)); +  TLD.RecordPtr += sizeof(Metadata); +  // Since we write out the extents as the first metadata record of the +  // buffer, we need to write out the extents including the extents record. +  atomic_store(&TLD.Buffer.Extents->Size, sizeof(Metadata), +               memory_order_release); +} + +static void setupNewBuffer(int (*wall_clock_reader)( +    clockid_t, struct timespec *)) XRAY_NEVER_INSTRUMENT { +  auto &TLD = getThreadLocalData(); +  auto &B = TLD.Buffer; +  TLD.RecordPtr = static_cast<char *>(B.Data); +  tid_t Tid = GetTid(); +  timespec TS{0, 0}; +  pid_t Pid = internal_getpid(); +  // This is typically clock_gettime, but callers have injection ability. +  wall_clock_reader(CLOCK_MONOTONIC, &TS); +  writeNewBufferPreamble(Tid, TS, Pid); +  TLD.NumConsecutiveFnEnters = 0; +  TLD.NumTailCalls = 0; +} + +static void incrementExtents(size_t Add) { +  auto &TLD = getThreadLocalData(); +  atomic_fetch_add(&TLD.Buffer.Extents->Size, Add, memory_order_acq_rel); +} + +static void decrementExtents(size_t Subtract) { +  auto &TLD = getThreadLocalData(); +  atomic_fetch_sub(&TLD.Buffer.Extents->Size, Subtract, memory_order_acq_rel); +} + +static void writeNewCPUIdMetadata(uint16_t CPU, +                                  uint64_t TSC) XRAY_NEVER_INSTRUMENT { +  auto &TLD = getThreadLocalData(); +  MetadataRecord NewCPUId; +  NewCPUId.Type = uint8_t(RecordType::Metadata); +  NewCPUId.RecordKind = uint8_t(MetadataRecord::RecordKinds::NewCPUId); + +  // The data for the New CPU will contain the following bytes: +  //   - CPU ID (uint16_t, 2 bytes) +  //   - Full TSC (uint64_t, 8 bytes) +  // Total = 10 bytes. +  internal_memcpy(&NewCPUId.Data, &CPU, sizeof(CPU)); +  internal_memcpy(&NewCPUId.Data[sizeof(CPU)], &TSC, sizeof(TSC)); +  internal_memcpy(TLD.RecordPtr, &NewCPUId, sizeof(MetadataRecord)); +  TLD.RecordPtr += sizeof(MetadataRecord); +  TLD.NumConsecutiveFnEnters = 0; +  TLD.NumTailCalls = 0; +  incrementExtents(sizeof(MetadataRecord)); +} + +static void writeTSCWrapMetadata(uint64_t TSC) XRAY_NEVER_INSTRUMENT { +  auto &TLD = getThreadLocalData(); +  MetadataRecord TSCWrap; +  TSCWrap.Type = uint8_t(RecordType::Metadata); +  TSCWrap.RecordKind = uint8_t(MetadataRecord::RecordKinds::TSCWrap); + +  // The data for the TSCWrap record contains the following bytes: +  //   - Full TSC (uint64_t, 8 bytes) +  // Total = 8 bytes. +  internal_memcpy(&TSCWrap.Data, &TSC, sizeof(TSC)); +  internal_memcpy(TLD.RecordPtr, &TSCWrap, sizeof(MetadataRecord)); +  TLD.RecordPtr += sizeof(MetadataRecord); +  TLD.NumConsecutiveFnEnters = 0; +  TLD.NumTailCalls = 0; +  incrementExtents(sizeof(MetadataRecord)); +} + +// Call Argument metadata records store the arguments to a function in the +// order of their appearance; holes are not supported by the buffer format. +static void writeCallArgumentMetadata(uint64_t A) XRAY_NEVER_INSTRUMENT { +  auto &TLD = getThreadLocalData(); +  MetadataRecord CallArg; +  CallArg.Type = uint8_t(RecordType::Metadata); +  CallArg.RecordKind = uint8_t(MetadataRecord::RecordKinds::CallArgument); + +  internal_memcpy(CallArg.Data, &A, sizeof(A)); +  internal_memcpy(TLD.RecordPtr, &CallArg, sizeof(MetadataRecord)); +  TLD.RecordPtr += sizeof(MetadataRecord); +  incrementExtents(sizeof(MetadataRecord)); +} + +static void writeFunctionRecord(int FuncId, uint32_t TSCDelta, +                                XRayEntryType EntryType) XRAY_NEVER_INSTRUMENT { +  FunctionRecord FuncRecord; +  FuncRecord.Type = uint8_t(RecordType::Function); +  // Only take 28 bits of the function id. +  FuncRecord.FuncId = FuncId & ~(0x0F << 28); +  FuncRecord.TSCDelta = TSCDelta; + +  auto &TLD = getThreadLocalData(); +  switch (EntryType) { +  case XRayEntryType::ENTRY: +    ++TLD.NumConsecutiveFnEnters; +    FuncRecord.RecordKind = uint8_t(FunctionRecord::RecordKinds::FunctionEnter); +    break; +  case XRayEntryType::LOG_ARGS_ENTRY: +    // We should not rewind functions with logged args. +    TLD.NumConsecutiveFnEnters = 0; +    TLD.NumTailCalls = 0; +    FuncRecord.RecordKind = uint8_t(FunctionRecord::RecordKinds::FunctionEnter); +    break; +  case XRayEntryType::EXIT: +    // If we've decided to log the function exit, we will never erase the log +    // before it. +    TLD.NumConsecutiveFnEnters = 0; +    TLD.NumTailCalls = 0; +    FuncRecord.RecordKind = uint8_t(FunctionRecord::RecordKinds::FunctionExit); +    break; +  case XRayEntryType::TAIL: +    // If we just entered the function we're tail exiting from or erased every +    // invocation since then, this function entry tail pair is a candidate to +    // be erased when the child function exits. +    if (TLD.NumConsecutiveFnEnters > 0) { +      ++TLD.NumTailCalls; +      TLD.NumConsecutiveFnEnters = 0; +    } else { +      // We will never be able to erase this tail call since we have logged +      // something in between the function entry and tail exit. +      TLD.NumTailCalls = 0; +      TLD.NumConsecutiveFnEnters = 0; +    } +    FuncRecord.RecordKind = +        uint8_t(FunctionRecord::RecordKinds::FunctionTailExit); +    break; +  case XRayEntryType::CUSTOM_EVENT: { +    // This is a bug in patching, so we'll report it once and move on. +    static atomic_uint8_t ErrorLatch{0}; +    if (!atomic_exchange(&ErrorLatch, 1, memory_order_acq_rel)) +      Report("Internal error: patched an XRay custom event call as a function; " +             "func id = %d\n", +             FuncId); +    return; +  } +  case XRayEntryType::TYPED_EVENT: { +    static atomic_uint8_t ErrorLatch{0}; +    if (!atomic_exchange(&ErrorLatch, 1, memory_order_acq_rel)) +      Report("Internal error: patched an XRay typed event call as a function; " +             "func id = %d\n", +             FuncId); +    return; +  } +  } + +  internal_memcpy(TLD.RecordPtr, &FuncRecord, sizeof(FunctionRecord)); +  TLD.RecordPtr += sizeof(FunctionRecord); +  incrementExtents(sizeof(FunctionRecord)); +} + +static atomic_uint64_t TicksPerSec{0}; +static atomic_uint64_t ThresholdTicks{0}; + +// Re-point the thread local pointer into this thread's Buffer before the recent +// "Function Entry" record and any "Tail Call Exit" records after that. +static void rewindRecentCall(uint64_t TSC, uint64_t &LastTSC, +                             uint64_t &LastFunctionEntryTSC, int32_t FuncId) { +  auto &TLD = getThreadLocalData(); +  TLD.RecordPtr -= FunctionRecSize; +  decrementExtents(FunctionRecSize); +  FunctionRecord FuncRecord; +  internal_memcpy(&FuncRecord, TLD.RecordPtr, FunctionRecSize); +  DCHECK(FuncRecord.RecordKind == +             uint8_t(FunctionRecord::RecordKinds::FunctionEnter) && +         "Expected to find function entry recording when rewinding."); +  DCHECK(FuncRecord.FuncId == (FuncId & ~(0x0F << 28)) && +         "Expected matching function id when rewinding Exit"); +  --TLD.NumConsecutiveFnEnters; +  LastTSC -= FuncRecord.TSCDelta; + +  // We unwound one call. Update the state and return without writing a log. +  if (TLD.NumConsecutiveFnEnters != 0) { +    LastFunctionEntryTSC -= FuncRecord.TSCDelta; +    return; +  } + +  // Otherwise we've rewound the stack of all function entries, we might be +  // able to rewind further by erasing tail call functions that are being +  // exited from via this exit. +  LastFunctionEntryTSC = 0; +  auto RewindingTSC = LastTSC; +  auto RewindingRecordPtr = TLD.RecordPtr - FunctionRecSize; +  while (TLD.NumTailCalls > 0) { +    // Rewind the TSC back over the TAIL EXIT record. +    FunctionRecord ExpectedTailExit; +    internal_memcpy(&ExpectedTailExit, RewindingRecordPtr, FunctionRecSize); + +    DCHECK(ExpectedTailExit.RecordKind == +               uint8_t(FunctionRecord::RecordKinds::FunctionTailExit) && +           "Expected to find tail exit when rewinding."); +    RewindingRecordPtr -= FunctionRecSize; +    RewindingTSC -= ExpectedTailExit.TSCDelta; +    FunctionRecord ExpectedFunctionEntry; +    internal_memcpy(&ExpectedFunctionEntry, RewindingRecordPtr, +                    FunctionRecSize); +    DCHECK(ExpectedFunctionEntry.RecordKind == +               uint8_t(FunctionRecord::RecordKinds::FunctionEnter) && +           "Expected to find function entry when rewinding tail call."); +    DCHECK(ExpectedFunctionEntry.FuncId == ExpectedTailExit.FuncId && +           "Expected funcids to match when rewinding tail call."); + +    // This tail call exceeded the threshold duration. It will not be erased. +    if ((TSC - RewindingTSC) >= atomic_load_relaxed(&ThresholdTicks)) { +      TLD.NumTailCalls = 0; +      return; +    } + +    // We can erase a tail exit pair that we're exiting through since +    // its duration is under threshold. +    --TLD.NumTailCalls; +    RewindingRecordPtr -= FunctionRecSize; +    RewindingTSC -= ExpectedFunctionEntry.TSCDelta; +    TLD.RecordPtr -= 2 * FunctionRecSize; +    LastTSC = RewindingTSC; +    decrementExtents(2 * FunctionRecSize); +  } +} + +static bool releaseThreadLocalBuffer(BufferQueue &BQArg) { +  auto &TLD = getThreadLocalData(); +  auto EC = BQArg.releaseBuffer(TLD.Buffer); +  if (EC != BufferQueue::ErrorCode::Ok) { +    Report("Failed to release buffer at %p; error=%s\n", TLD.Buffer.Data, +           BufferQueue::getErrorString(EC)); +    return false; +  } +  return true; +} + +static bool prepareBuffer(uint64_t TSC, unsigned char CPU, +                          int (*wall_clock_reader)(clockid_t, +                                                   struct timespec *), +                          size_t MaxSize) XRAY_NEVER_INSTRUMENT { +  auto &TLD = getThreadLocalData(); +  char *BufferStart = static_cast<char *>(TLD.Buffer.Data); +  if ((TLD.RecordPtr + MaxSize) > (BufferStart + TLD.Buffer.Size)) { +    if (!releaseThreadLocalBuffer(*TLD.BQ)) +      return false; +    auto EC = TLD.BQ->getBuffer(TLD.Buffer); +    if (EC != BufferQueue::ErrorCode::Ok) { +      Report("Failed to prepare a buffer; error = '%s'\n", +             BufferQueue::getErrorString(EC)); +      return false; +    } +    setupNewBuffer(wall_clock_reader); -__sanitizer::SpinMutex FDROptionsMutex; +    // Always write the CPU metadata as the first record in the buffer. +    writeNewCPUIdMetadata(CPU, TSC); +  } +  return true; +} + +static bool +isLogInitializedAndReady(BufferQueue *LBQ, uint64_t TSC, unsigned char CPU, +                         int (*wall_clock_reader)(clockid_t, struct timespec *)) +    XRAY_NEVER_INSTRUMENT { +  // Bail out right away if logging is not initialized yet. +  // We should take the opportunity to release the buffer though. +  auto Status = atomic_load(&LoggingStatus, memory_order_acquire); +  auto &TLD = getThreadLocalData(); +  if (Status != XRayLogInitStatus::XRAY_LOG_INITIALIZED) { +    if (TLD.RecordPtr != nullptr && +        (Status == XRayLogInitStatus::XRAY_LOG_FINALIZING || +         Status == XRayLogInitStatus::XRAY_LOG_FINALIZED)) { +      if (!releaseThreadLocalBuffer(*LBQ)) +        return false; +      TLD.RecordPtr = nullptr; +      return false; +    } +    return false; +  } + +  if (atomic_load(&LoggingStatus, memory_order_acquire) != +          XRayLogInitStatus::XRAY_LOG_INITIALIZED || +      LBQ->finalizing()) { +    if (!releaseThreadLocalBuffer(*LBQ)) +      return false; +    TLD.RecordPtr = nullptr; +  } + +  if (TLD.Buffer.Data == nullptr) { +    auto EC = LBQ->getBuffer(TLD.Buffer); +    if (EC != BufferQueue::ErrorCode::Ok) { +      auto LS = atomic_load(&LoggingStatus, memory_order_acquire); +      if (LS != XRayLogInitStatus::XRAY_LOG_FINALIZING && +          LS != XRayLogInitStatus::XRAY_LOG_FINALIZED) +        Report("Failed to acquire a buffer; error = '%s'\n", +               BufferQueue::getErrorString(EC)); +      return false; +    } + +    setupNewBuffer(wall_clock_reader); + +    // Always write the CPU metadata as the first record in the buffer. +    writeNewCPUIdMetadata(CPU, TSC); +  } + +  if (TLD.CurrentCPU == std::numeric_limits<uint16_t>::max()) { +    // This means this is the first CPU this thread has ever run on. We set +    // the current CPU and record this as the first TSC we've seen. +    TLD.CurrentCPU = CPU; +    writeNewCPUIdMetadata(CPU, TSC); +  } + +  return true; +} + +// Compute the TSC difference between the time of measurement and the previous +// event. There are a few interesting situations we need to account for: +// +//   - The thread has migrated to a different CPU. If this is the case, then +//     we write down the following records: +// +//       1. A 'NewCPUId' Metadata record. +//       2. A FunctionRecord with a 0 for the TSCDelta field. +// +//   - The TSC delta is greater than the 32 bits we can store in a +//     FunctionRecord. In this case we write down the following records: +// +//       1. A 'TSCWrap' Metadata record. +//       2. A FunctionRecord with a 0 for the TSCDelta field. +// +//   - The TSC delta is representable within the 32 bits we can store in a +//     FunctionRecord. In this case we write down just a FunctionRecord with +//     the correct TSC delta. +static uint32_t writeCurrentCPUTSC(ThreadLocalData &TLD, uint64_t TSC, +                                   uint8_t CPU) { +  if (CPU != TLD.CurrentCPU) { +    // We've moved to a new CPU. +    writeNewCPUIdMetadata(CPU, TSC); +    return 0; +  } +  // If the delta is greater than the range for a uint32_t, then we write out +  // the TSC wrap metadata entry with the full TSC, and the TSC for the +  // function record be 0. +  uint64_t Delta = TSC - TLD.LastTSC; +  if (Delta <= std::numeric_limits<uint32_t>::max()) +    return Delta; + +  writeTSCWrapMetadata(TSC); +  return 0; +} + +static void endBufferIfFull() XRAY_NEVER_INSTRUMENT { +  auto &TLD = getThreadLocalData(); +  auto BufferStart = static_cast<char *>(TLD.Buffer.Data); +  if ((TLD.RecordPtr + MetadataRecSize) - BufferStart <= +      ptrdiff_t{MetadataRecSize}) { +    if (!releaseThreadLocalBuffer(*TLD.BQ)) +      return; +    TLD.RecordPtr = nullptr; +  } +} + +thread_local atomic_uint8_t Running{0}; + +/// Here's where the meat of the processing happens. The writer captures +/// function entry, exit and tail exit points with a time and will create +/// TSCWrap, NewCPUId and Function records as necessary. The writer might +/// walk backward through its buffer and erase trivial functions to avoid +/// polluting the log and may use the buffer queue to obtain or release a +/// buffer. +static void processFunctionHook(int32_t FuncId, XRayEntryType Entry, +                                uint64_t TSC, unsigned char CPU, uint64_t Arg1, +                                int (*wall_clock_reader)(clockid_t, +                                                         struct timespec *)) +    XRAY_NEVER_INSTRUMENT { +  __asm volatile("# LLVM-MCA-BEGIN processFunctionHook"); +  // Prevent signal handler recursion, so in case we're already in a log writing +  // mode and the signal handler comes in (and is also instrumented) then we +  // don't want to be clobbering potentially partial writes already happening in +  // the thread. We use a simple thread_local latch to only allow one on-going +  // handleArg0 to happen at any given time. +  RecursionGuard Guard{Running}; +  if (!Guard) { +    DCHECK(atomic_load_relaxed(&Running) && "RecursionGuard is buggy!"); +    return; +  } + +  auto &TLD = getThreadLocalData(); + +  if (TLD.BQ == nullptr) +    TLD.BQ = BQ; + +  if (!isLogInitializedAndReady(TLD.BQ, TSC, CPU, wall_clock_reader)) +    return; + +  // Before we go setting up writing new function entries, we need to be really +  // careful about the pointer math we're doing. This means we need to ensure +  // that the record we are about to write is going to fit into the buffer, +  // without overflowing the buffer. +  // +  // To do this properly, we use the following assumptions: +  // +  //   - The least number of bytes we will ever write is 8 +  //     (sizeof(FunctionRecord)) only if the delta between the previous entry +  //     and this entry is within 32 bits. +  //   - The most number of bytes we will ever write is 8 + 16 + 16 = 40. +  //     This is computed by: +  // +  //       MaxSize = sizeof(FunctionRecord) + 2 * sizeof(MetadataRecord) +  // +  //     These arise in the following cases: +  // +  //       1. When the delta between the TSC we get and the previous TSC for the +  //          same CPU is outside of the uint32_t range, we end up having to +  //          write a MetadataRecord to indicate a "tsc wrap" before the actual +  //          FunctionRecord. +  //       2. When we learn that we've moved CPUs, we need to write a +  //          MetadataRecord to indicate a "cpu change", and thus write out the +  //          current TSC for that CPU before writing out the actual +  //          FunctionRecord. +  //       3. When we learn about a new CPU ID, we need to write down a "new cpu +  //          id" MetadataRecord before writing out the actual FunctionRecord. +  //       4. The second MetadataRecord is the optional function call argument. +  // +  // So the math we need to do is to determine whether writing 40 bytes past the +  // current pointer exceeds the buffer's maximum size. If we don't have enough +  // space to write 40 bytes in the buffer, we need get a new Buffer, set it up +  // properly before doing any further writing. +  size_t MaxSize = FunctionRecSize + 2 * MetadataRecSize; +  if (!prepareBuffer(TSC, CPU, wall_clock_reader, MaxSize)) { +    TLD.BQ = nullptr; +    return; +  } + +  // By this point, we are now ready to write up to 40 bytes (explained above). +  DCHECK((TLD.RecordPtr + MaxSize) - static_cast<char *>(TLD.Buffer.Data) >= +             static_cast<ptrdiff_t>(MetadataRecSize) && +         "Misconfigured BufferQueue provided; Buffer size not large enough."); + +  auto RecordTSCDelta = writeCurrentCPUTSC(TLD, TSC, CPU); +  TLD.LastTSC = TSC; +  TLD.CurrentCPU = CPU; +  switch (Entry) { +  case XRayEntryType::ENTRY: +  case XRayEntryType::LOG_ARGS_ENTRY: +    // Update the thread local state for the next invocation. +    TLD.LastFunctionEntryTSC = TSC; +    break; +  case XRayEntryType::TAIL: +  case XRayEntryType::EXIT: +    // Break out and write the exit record if we can't erase any functions. +    if (TLD.NumConsecutiveFnEnters == 0 || +        (TSC - TLD.LastFunctionEntryTSC) >= +            atomic_load_relaxed(&ThresholdTicks)) +      break; +    rewindRecentCall(TSC, TLD.LastTSC, TLD.LastFunctionEntryTSC, FuncId); +    return; // without writing log. +  case XRayEntryType::CUSTOM_EVENT: { +    // This is a bug in patching, so we'll report it once and move on. +    static atomic_uint8_t ErrorLatch{0}; +    if (!atomic_exchange(&ErrorLatch, 1, memory_order_acq_rel)) +      Report("Internal error: patched an XRay custom event call as a function; " +             "func id = %d\n", +             FuncId); +    return; +  } +  case XRayEntryType::TYPED_EVENT: { +    static atomic_uint8_t ErrorLatch{0}; +    if (!atomic_exchange(&ErrorLatch, 1, memory_order_acq_rel)) +      Report("Internal error: patched an XRay typed event call as a function; " +             "func id = %d\n", +             FuncId); +    return; +  } +  } + +  writeFunctionRecord(FuncId, RecordTSCDelta, Entry); +  if (Entry == XRayEntryType::LOG_ARGS_ENTRY) +    writeCallArgumentMetadata(Arg1); + +  // If we've exhausted the buffer by this time, we then release the buffer to +  // make sure that other threads may start using this buffer. +  endBufferIfFull(); +  __asm volatile("# LLVM-MCA-END"); +} + +static XRayFileHeader &fdrCommonHeaderInfo() { +  static std::aligned_storage<sizeof(XRayFileHeader)>::type HStorage; +  static pthread_once_t OnceInit = PTHREAD_ONCE_INIT; +  static bool TSCSupported = true; +  static uint64_t CycleFrequency = NanosecondsPerSecond; +  pthread_once(&OnceInit, +[] { +    XRayFileHeader &H = reinterpret_cast<XRayFileHeader &>(HStorage); +    // Version 2 of the log writes the extents of the buffer, instead of +    // relying on an end-of-buffer record. +    // Version 3 includes PID metadata record +    H.Version = 3; +    H.Type = FileTypes::FDR_LOG; + +    // Test for required CPU features and cache the cycle frequency +    TSCSupported = probeRequiredCPUFeatures(); +    if (TSCSupported) +      CycleFrequency = getTSCFrequency(); +    H.CycleFrequency = CycleFrequency; + +    // FIXME: Actually check whether we have 'constant_tsc' and +    // 'nonstop_tsc' before setting the values in the header. +    H.ConstantTSC = 1; +    H.NonstopTSC = 1; +  }); +  return reinterpret_cast<XRayFileHeader &>(HStorage); +} + +// This is the iterator implementation, which knows how to handle FDR-mode +// specific buffers. This is used as an implementation of the iterator function +// needed by __xray_set_buffer_iterator(...). It maintains a global state of the +// buffer iteration for the currently installed FDR mode buffers. In particular: +// +//   - If the argument represents the initial state of XRayBuffer ({nullptr, 0}) +//     then the iterator returns the header information. +//   - If the argument represents the header information ({address of header +//     info, size of the header info}) then it returns the first FDR buffer's +//     address and extents. +//   - It will keep returning the next buffer and extents as there are more +//     buffers to process. When the input represents the last buffer, it will +//     return the initial state to signal completion ({nullptr, 0}). +// +// See xray/xray_log_interface.h for more details on the requirements for the +// implementations of __xray_set_buffer_iterator(...) and +// __xray_log_process_buffers(...). +XRayBuffer fdrIterator(const XRayBuffer B) { +  DCHECK(internal_strcmp(__xray_log_get_current_mode(), "xray-fdr") == 0); +  DCHECK(BQ->finalizing()); + +  if (BQ == nullptr || !BQ->finalizing()) { +    if (Verbosity()) +      Report( +          "XRay FDR: Failed global buffer queue is null or not finalizing!\n"); +    return {nullptr, 0}; +  } + +  // We use a global scratch-pad for the header information, which only gets +  // initialized the first time this function is called. We'll update one part +  // of this information with some relevant data (in particular the number of +  // buffers to expect). +  static std::aligned_storage<sizeof(XRayFileHeader)>::type HeaderStorage; +  static pthread_once_t HeaderOnce = PTHREAD_ONCE_INIT; +  pthread_once(&HeaderOnce, +[] { +    reinterpret_cast<XRayFileHeader &>(HeaderStorage) = fdrCommonHeaderInfo(); +  }); + +  // We use a convenience alias for code referring to Header from here on out. +  auto &Header = reinterpret_cast<XRayFileHeader &>(HeaderStorage); +  if (B.Data == nullptr && B.Size == 0) { +    Header.FdrData = FdrAdditionalHeaderData{BQ->ConfiguredBufferSize()}; +    return XRayBuffer{static_cast<void *>(&Header), sizeof(Header)}; +  } + +  static BufferQueue::const_iterator It{}; +  static BufferQueue::const_iterator End{}; +  static void *CurrentBuffer{nullptr}; +  if (B.Data == static_cast<void *>(&Header) && B.Size == sizeof(Header)) { +    // From this point on, we provide raw access to the raw buffer we're getting +    // from the BufferQueue. We're relying on the iterators from the current +    // Buffer queue. +    It = BQ->cbegin(); +    End = BQ->cend(); +  } + +  if (CurrentBuffer != nullptr) { +    InternalFree(CurrentBuffer); +    CurrentBuffer = nullptr; +  } + +  if (It == End) +    return {nullptr, 0}; + +  // Set up the current buffer to contain the extents like we would when writing +  // out to disk. The difference here would be that we still write "empty" +  // buffers, or at least go through the iterators faithfully to let the +  // handlers see the empty buffers in the queue. +  auto BufferSize = atomic_load(&It->Extents->Size, memory_order_acquire); +  auto SerializedBufferSize = BufferSize + sizeof(MetadataRecord); +  CurrentBuffer = InternalAlloc(SerializedBufferSize); +  if (CurrentBuffer == nullptr) +    return {nullptr, 0}; + +  // Write out the extents as a Metadata Record into the CurrentBuffer. +  MetadataRecord ExtentsRecord; +  ExtentsRecord.Type = uint8_t(RecordType::Metadata); +  ExtentsRecord.RecordKind = +      uint8_t(MetadataRecord::RecordKinds::BufferExtents); +  internal_memcpy(ExtentsRecord.Data, &BufferSize, sizeof(BufferSize)); +  auto AfterExtents = +      static_cast<char *>(internal_memcpy(CurrentBuffer, &ExtentsRecord, +                                          sizeof(MetadataRecord))) + +      sizeof(MetadataRecord); +  internal_memcpy(AfterExtents, It->Data, BufferSize); + +  XRayBuffer Result; +  Result.Data = CurrentBuffer; +  Result.Size = SerializedBufferSize; +  ++It; +  return Result; +}  // Must finalize before flushing.  XRayLogFlushStatus fdrLoggingFlush() XRAY_NEVER_INSTRUMENT { -  if (__sanitizer::atomic_load(&LoggingStatus, -                               __sanitizer::memory_order_acquire) != +  if (atomic_load(&LoggingStatus, memory_order_acquire) !=        XRayLogInitStatus::XRAY_LOG_FINALIZED) { -    if (__sanitizer::Verbosity()) +    if (Verbosity())        Report("Not flushing log, implementation is not finalized.\n");      return XRayLogFlushStatus::XRAY_LOG_NOT_FLUSHING;    }    s32 Result = XRayLogFlushStatus::XRAY_LOG_NOT_FLUSHING; -  if (!__sanitizer::atomic_compare_exchange_strong( -          &LogFlushStatus, &Result, XRayLogFlushStatus::XRAY_LOG_FLUSHING, -          __sanitizer::memory_order_release)) { - -    if (__sanitizer::Verbosity()) +  if (!atomic_compare_exchange_strong(&LogFlushStatus, &Result, +                                      XRayLogFlushStatus::XRAY_LOG_FLUSHING, +                                      memory_order_release)) { +    if (Verbosity())        Report("Not flushing log, implementation is still finalizing.\n");      return static_cast<XRayLogFlushStatus>(Result);    }    if (BQ == nullptr) { -    if (__sanitizer::Verbosity()) +    if (Verbosity())        Report("Cannot flush when global buffer queue is null.\n");      return XRayLogFlushStatus::XRAY_LOG_NOT_FLUSHING;    }    // We wait a number of milliseconds to allow threads to see that we've    // finalised before attempting to flush the log. -  __sanitizer::SleepForMillis(flags()->xray_fdr_log_grace_period_ms); +  SleepForMillis(fdrFlags()->grace_period_ms); + +  // At this point, we're going to uninstall the iterator implementation, before +  // we decide to do anything further with the global buffer queue. +  __xray_log_remove_buffer_iterator(); + +  // Once flushed, we should set the global status of the logging implementation +  // to "uninitialized" to allow for FDR-logging multiple runs. +  auto ResetToUnitialized = at_scope_exit([] { +    atomic_store(&LoggingStatus, XRayLogInitStatus::XRAY_LOG_UNINITIALIZED, +                 memory_order_release); +  }); + +  auto CleanupBuffers = at_scope_exit([] { +    if (BQ != nullptr) { +      auto &TLD = getThreadLocalData(); +      if (TLD.RecordPtr != nullptr && TLD.BQ != nullptr) +        releaseThreadLocalBuffer(*TLD.BQ); +      BQ->~BufferQueue(); +      InternalFree(BQ); +      BQ = nullptr; +    } +  }); + +  if (fdrFlags()->no_file_flush) { +    if (Verbosity()) +      Report("XRay FDR: Not flushing to file, 'no_file_flush=true'.\n"); + +    atomic_store(&LogFlushStatus, XRayLogFlushStatus::XRAY_LOG_FLUSHED, +                 memory_order_release); +    return XRayLogFlushStatus::XRAY_LOG_FLUSHED; +  }    // We write out the file in the following format:    // @@ -85,35 +857,20 @@ XRayLogFlushStatus fdrLoggingFlush() XRAY_NEVER_INSTRUMENT {    //    int Fd = -1;    { -    __sanitizer::SpinMutexLock Guard(&FDROptionsMutex); +    // FIXME: Remove this section of the code, when we remove the struct-based +    // configuration API. +    SpinMutexLock Guard(&FDROptionsMutex);      Fd = FDROptions.Fd;    }    if (Fd == -1)      Fd = getLogFD();    if (Fd == -1) {      auto Result = XRayLogFlushStatus::XRAY_LOG_NOT_FLUSHING; -    __sanitizer::atomic_store(&LogFlushStatus, Result, -                              __sanitizer::memory_order_release); +    atomic_store(&LogFlushStatus, Result, memory_order_release);      return Result;    } -  // Test for required CPU features and cache the cycle frequency -  static bool TSCSupported = probeRequiredCPUFeatures(); -  static uint64_t CycleFrequency = -      TSCSupported ? getTSCFrequency() : __xray::NanosecondsPerSecond; - -  XRayFileHeader Header; - -  // Version 2 of the log writes the extents of the buffer, instead of relying -  // on an end-of-buffer record. -  Header.Version = 2; -  Header.Type = FileTypes::FDR_LOG; -  Header.CycleFrequency = CycleFrequency; - -  // FIXME: Actually check whether we have 'constant_tsc' and 'nonstop_tsc' -  // before setting the values in the header. -  Header.ConstantTSC = 1; -  Header.NonstopTSC = 1; +  XRayFileHeader Header = fdrCommonHeaderInfo();    Header.FdrData = FdrAdditionalHeaderData{BQ->ConfiguredBufferSize()};    retryingWriteAll(Fd, reinterpret_cast<char *>(&Header),                     reinterpret_cast<char *>(&Header) + sizeof(Header)); @@ -121,39 +878,36 @@ XRayLogFlushStatus fdrLoggingFlush() XRAY_NEVER_INSTRUMENT {    BQ->apply([&](const BufferQueue::Buffer &B) {      // Starting at version 2 of the FDR logging implementation, we only write      // the records identified by the extents of the buffer. We use the Extents -    // from the Buffer and write that out as the first record in the buffer. -    // We still use a Metadata record, but fill in the extents instead for the +    // from the Buffer and write that out as the first record in the buffer.  We +    // still use a Metadata record, but fill in the extents instead for the      // data.      MetadataRecord ExtentsRecord; -    auto BufferExtents = __sanitizer::atomic_load( -        &B.Extents->Size, __sanitizer::memory_order_acquire); -    assert(BufferExtents <= B.Size); +    auto BufferExtents = atomic_load(&B.Extents->Size, memory_order_acquire); +    DCHECK(BufferExtents <= B.Size);      ExtentsRecord.Type = uint8_t(RecordType::Metadata);      ExtentsRecord.RecordKind =          uint8_t(MetadataRecord::RecordKinds::BufferExtents); -    std::memcpy(ExtentsRecord.Data, &BufferExtents, sizeof(BufferExtents)); +    internal_memcpy(ExtentsRecord.Data, &BufferExtents, sizeof(BufferExtents));      if (BufferExtents > 0) {        retryingWriteAll(Fd, reinterpret_cast<char *>(&ExtentsRecord),                         reinterpret_cast<char *>(&ExtentsRecord) +                             sizeof(MetadataRecord)); -      retryingWriteAll(Fd, reinterpret_cast<char *>(B.Buffer), -                       reinterpret_cast<char *>(B.Buffer) + BufferExtents); +      retryingWriteAll(Fd, reinterpret_cast<char *>(B.Data), +                       reinterpret_cast<char *>(B.Data) + BufferExtents);      }    }); -  __sanitizer::atomic_store(&LogFlushStatus, -                            XRayLogFlushStatus::XRAY_LOG_FLUSHED, -                            __sanitizer::memory_order_release); +  atomic_store(&LogFlushStatus, XRayLogFlushStatus::XRAY_LOG_FLUSHED, +               memory_order_release);    return XRayLogFlushStatus::XRAY_LOG_FLUSHED;  }  XRayLogInitStatus fdrLoggingFinalize() XRAY_NEVER_INSTRUMENT {    s32 CurrentStatus = XRayLogInitStatus::XRAY_LOG_INITIALIZED; -  if (!__sanitizer::atomic_compare_exchange_strong( -          &LoggingStatus, &CurrentStatus, -          XRayLogInitStatus::XRAY_LOG_FINALIZING, -          __sanitizer::memory_order_release)) { -    if (__sanitizer::Verbosity()) +  if (!atomic_compare_exchange_strong(&LoggingStatus, &CurrentStatus, +                                      XRayLogInitStatus::XRAY_LOG_FINALIZING, +                                      memory_order_release)) { +    if (Verbosity())        Report("Cannot finalize log, implementation not initialized.\n");      return static_cast<XRayLogInitStatus>(CurrentStatus);    } @@ -162,39 +916,11 @@ XRayLogInitStatus fdrLoggingFinalize() XRAY_NEVER_INSTRUMENT {    // operations to be performed until re-initialized.    BQ->finalize(); -  __sanitizer::atomic_store(&LoggingStatus, -                            XRayLogInitStatus::XRAY_LOG_FINALIZED, -                            __sanitizer::memory_order_release); +  atomic_store(&LoggingStatus, XRayLogInitStatus::XRAY_LOG_FINALIZED, +               memory_order_release);    return XRayLogInitStatus::XRAY_LOG_FINALIZED;  } -XRayLogInitStatus fdrLoggingReset() XRAY_NEVER_INSTRUMENT { -  s32 CurrentStatus = XRayLogInitStatus::XRAY_LOG_FINALIZED; -  if (__sanitizer::atomic_compare_exchange_strong( -          &LoggingStatus, &CurrentStatus, -          XRayLogInitStatus::XRAY_LOG_INITIALIZED, -          __sanitizer::memory_order_release)) -    return static_cast<XRayLogInitStatus>(CurrentStatus); - -  // Release the in-memory buffer queue. -  delete BQ; -  BQ = nullptr; - -  // Spin until the flushing status is flushed. -  s32 CurrentFlushingStatus = XRayLogFlushStatus::XRAY_LOG_FLUSHED; -  while (__sanitizer::atomic_compare_exchange_weak( -      &LogFlushStatus, &CurrentFlushingStatus, -      XRayLogFlushStatus::XRAY_LOG_NOT_FLUSHING, -      __sanitizer::memory_order_release)) { -    if (CurrentFlushingStatus == XRayLogFlushStatus::XRAY_LOG_NOT_FLUSHING) -      break; -    CurrentFlushingStatus = XRayLogFlushStatus::XRAY_LOG_FLUSHED; -  } - -  // At this point, we know that the status is flushed, and that we can assume -  return XRayLogInitStatus::XRAY_LOG_UNINITIALIZED; -} -  struct TSCAndCPU {    uint64_t TSC = 0;    unsigned char CPU = 0; @@ -202,12 +928,14 @@ struct TSCAndCPU {  static TSCAndCPU getTimestamp() XRAY_NEVER_INSTRUMENT {    // We want to get the TSC as early as possible, so that we can check whether -  // we've seen this CPU before. We also do it before we load anything else, to -  // allow for forward progress with the scheduling. +  // we've seen this CPU before. We also do it before we load anything else, +  // to allow for forward progress with the scheduling.    TSCAndCPU Result;    // Test once for required CPU features -  static bool TSCSupported = probeRequiredCPUFeatures(); +  static pthread_once_t OnceProbe = PTHREAD_ONCE_INIT; +  static bool TSCSupported = true; +  pthread_once(&OnceProbe, +[] { TSCSupported = probeRequiredCPUFeatures(); });    if (TSCSupported) {      Result.TSC = __xray::readTSC(Result.CPU); @@ -228,20 +956,17 @@ static TSCAndCPU getTimestamp() XRAY_NEVER_INSTRUMENT {  void fdrLoggingHandleArg0(int32_t FuncId,                            XRayEntryType Entry) XRAY_NEVER_INSTRUMENT {    auto TC = getTimestamp(); -  __xray_fdr_internal::processFunctionHook(FuncId, Entry, TC.TSC, TC.CPU, 0, -                                           clock_gettime, BQ); +  processFunctionHook(FuncId, Entry, TC.TSC, TC.CPU, 0, clock_gettime);  }  void fdrLoggingHandleArg1(int32_t FuncId, XRayEntryType Entry,                            uint64_t Arg) XRAY_NEVER_INSTRUMENT {    auto TC = getTimestamp(); -  __xray_fdr_internal::processFunctionHook(FuncId, Entry, TC.TSC, TC.CPU, Arg, -                                           clock_gettime, BQ); +  processFunctionHook(FuncId, Entry, TC.TSC, TC.CPU, Arg, clock_gettime);  }  void fdrLoggingHandleCustomEvent(void *Event,                                   std::size_t EventSize) XRAY_NEVER_INSTRUMENT { -  using namespace __xray_fdr_internal;    auto TC = getTimestamp();    auto &TSC = TC.TSC;    auto &CPU = TC.CPU; @@ -249,13 +974,8 @@ void fdrLoggingHandleCustomEvent(void *Event,    if (!Guard)      return;    if (EventSize > std::numeric_limits<int32_t>::max()) { -    using Empty = struct {}; -    static Empty Once = [&] { -      Report("Event size too large = %zu ; > max = %d\n", EventSize, -             std::numeric_limits<int32_t>::max()); -      return Empty(); -    }(); -    (void)Once; +    static pthread_once_t Once = PTHREAD_ONCE_INIT; +    pthread_once(&Once, +[] { Report("Event size too large.\n"); });    }    int32_t ReducedEventSize = static_cast<int32_t>(EventSize);    auto &TLD = getThreadLocalData(); @@ -264,8 +984,8 @@ void fdrLoggingHandleCustomEvent(void *Event,    // Here we need to prepare the log to handle:    //   - The metadata record we're going to write. (16 bytes) -  //   - The additional data we're going to write. Currently, that's the size of -  //   the event we're going to dump into the log as free-form bytes. +  //   - The additional data we're going to write. Currently, that's the size +  //   of the event we're going to dump into the log as free-form bytes.    if (!prepareBuffer(TSC, CPU, clock_gettime, MetadataRecSize + EventSize)) {      TLD.BQ = nullptr;      return; @@ -280,90 +1000,207 @@ void fdrLoggingHandleCustomEvent(void *Event,    CustomEvent.RecordKind =        uint8_t(MetadataRecord::RecordKinds::CustomEventMarker);    constexpr auto TSCSize = sizeof(TC.TSC); -  std::memcpy(&CustomEvent.Data, &ReducedEventSize, sizeof(int32_t)); -  std::memcpy(&CustomEvent.Data[sizeof(int32_t)], &TSC, TSCSize); -  std::memcpy(TLD.RecordPtr, &CustomEvent, sizeof(CustomEvent)); +  internal_memcpy(&CustomEvent.Data, &ReducedEventSize, sizeof(int32_t)); +  internal_memcpy(&CustomEvent.Data[sizeof(int32_t)], &TSC, TSCSize); +  internal_memcpy(TLD.RecordPtr, &CustomEvent, sizeof(CustomEvent));    TLD.RecordPtr += sizeof(CustomEvent); -  std::memcpy(TLD.RecordPtr, Event, ReducedEventSize); +  internal_memcpy(TLD.RecordPtr, Event, ReducedEventSize); +  incrementExtents(MetadataRecSize + EventSize); +  endBufferIfFull(); +} + +void fdrLoggingHandleTypedEvent( +    uint16_t EventType, const void *Event, +    std::size_t EventSize) noexcept XRAY_NEVER_INSTRUMENT { +  auto TC = getTimestamp(); +  auto &TSC = TC.TSC; +  auto &CPU = TC.CPU; +  RecursionGuard Guard{Running}; +  if (!Guard) +    return; +  if (EventSize > std::numeric_limits<int32_t>::max()) { +    static pthread_once_t Once = PTHREAD_ONCE_INIT; +    pthread_once(&Once, +[] { Report("Event size too large.\n"); }); +  } +  int32_t ReducedEventSize = static_cast<int32_t>(EventSize); +  auto &TLD = getThreadLocalData(); +  if (!isLogInitializedAndReady(TLD.BQ, TSC, CPU, clock_gettime)) +    return; + +  // Here we need to prepare the log to handle: +  //   - The metadata record we're going to write. (16 bytes) +  //   - The additional data we're going to write. Currently, that's the size +  //   of the event we're going to dump into the log as free-form bytes. +  if (!prepareBuffer(TSC, CPU, clock_gettime, MetadataRecSize + EventSize)) { +    TLD.BQ = nullptr; +    return; +  } +  // Write the custom event metadata record, which consists of the following +  // information: +  //   - 8 bytes (64-bits) for the full TSC when the event started. +  //   - 4 bytes (32-bits) for the length of the data. +  //   - 2 bytes (16-bits) for the event type. 3 bytes remain since one of the +  //       bytes has the record type (Metadata Record) and kind (TypedEvent). +  //       We'll log the error if the event type is greater than 2 bytes. +  //       Event types are generated sequentially, so 2^16 is enough. +  MetadataRecord TypedEvent; +  TypedEvent.Type = uint8_t(RecordType::Metadata); +  TypedEvent.RecordKind = +      uint8_t(MetadataRecord::RecordKinds::TypedEventMarker); +  constexpr auto TSCSize = sizeof(TC.TSC); +  internal_memcpy(&TypedEvent.Data, &ReducedEventSize, sizeof(int32_t)); +  internal_memcpy(&TypedEvent.Data[sizeof(int32_t)], &TSC, TSCSize); +  internal_memcpy(&TypedEvent.Data[sizeof(int32_t) + TSCSize], &EventType, +                  sizeof(EventType)); +  internal_memcpy(TLD.RecordPtr, &TypedEvent, sizeof(TypedEvent)); + +  TLD.RecordPtr += sizeof(TypedEvent); +  internal_memcpy(TLD.RecordPtr, Event, ReducedEventSize);    incrementExtents(MetadataRecSize + EventSize);    endBufferIfFull();  } -XRayLogInitStatus fdrLoggingInit(std::size_t BufferSize, std::size_t BufferMax, +XRayLogInitStatus fdrLoggingInit(size_t BufferSize, size_t BufferMax,                                   void *Options,                                   size_t OptionsSize) XRAY_NEVER_INSTRUMENT { -  if (OptionsSize != sizeof(FDRLoggingOptions)) { -    if (__sanitizer::Verbosity()) -      Report("Cannot initialize FDR logging; wrong size for options: %d\n", -             OptionsSize); -    return static_cast<XRayLogInitStatus>(__sanitizer::atomic_load( -        &LoggingStatus, __sanitizer::memory_order_acquire)); -  } +  if (Options == nullptr) +    return XRayLogInitStatus::XRAY_LOG_UNINITIALIZED; +    s32 CurrentStatus = XRayLogInitStatus::XRAY_LOG_UNINITIALIZED; -  if (!__sanitizer::atomic_compare_exchange_strong( -          &LoggingStatus, &CurrentStatus, -          XRayLogInitStatus::XRAY_LOG_INITIALIZING, -          __sanitizer::memory_order_release)) { -    if (__sanitizer::Verbosity()) +  if (!atomic_compare_exchange_strong(&LoggingStatus, &CurrentStatus, +                                      XRayLogInitStatus::XRAY_LOG_INITIALIZING, +                                      memory_order_release)) { +    if (Verbosity())        Report("Cannot initialize already initialized implementation.\n");      return static_cast<XRayLogInitStatus>(CurrentStatus);    } -  { -    __sanitizer::SpinMutexLock Guard(&FDROptionsMutex); -    memcpy(&FDROptions, Options, OptionsSize); +  // Because of __xray_log_init_mode(...) which guarantees that this will be +  // called with BufferSize == 0 and BufferMax == 0 we parse the configuration +  // provided in the Options pointer as a string instead. +  if (BufferSize == 0 && BufferMax == 0) { +    if (Verbosity()) +      Report("Initializing FDR mode with options: %s\n", +             static_cast<const char *>(Options)); + +    // TODO: Factor out the flags specific to the FDR mode implementation. For +    // now, use the global/single definition of the flags, since the FDR mode +    // flags are already defined there. +    FlagParser FDRParser; +    FDRFlags FDRFlags; +    registerXRayFDRFlags(&FDRParser, &FDRFlags); +    FDRFlags.setDefaults(); + +    // Override first from the general XRAY_DEFAULT_OPTIONS compiler-provided +    // options until we migrate everyone to use the XRAY_FDR_OPTIONS +    // compiler-provided options. +    FDRParser.ParseString(useCompilerDefinedFlags()); +    FDRParser.ParseString(useCompilerDefinedFDRFlags()); +    auto *EnvOpts = GetEnv("XRAY_FDR_OPTIONS"); +    if (EnvOpts == nullptr) +      EnvOpts = ""; +    FDRParser.ParseString(EnvOpts); + +    // FIXME: Remove this when we fully remove the deprecated flags. +    if (internal_strlen(EnvOpts) == 0) { +      FDRFlags.func_duration_threshold_us = +          flags()->xray_fdr_log_func_duration_threshold_us; +      FDRFlags.grace_period_ms = flags()->xray_fdr_log_grace_period_ms; +    } + +    // The provided options should always override the compiler-provided and +    // environment-variable defined options. +    FDRParser.ParseString(static_cast<const char *>(Options)); +    *fdrFlags() = FDRFlags; +    BufferSize = FDRFlags.buffer_size; +    BufferMax = FDRFlags.buffer_max; +    SpinMutexLock Guard(&FDROptionsMutex); +    FDROptions.Fd = -1; +    FDROptions.ReportErrors = true; +  } else if (OptionsSize != sizeof(FDRLoggingOptions)) { +    // FIXME: This is deprecated, and should really be removed. +    // At this point we use the flag parser specific to the FDR mode +    // implementation. +    if (Verbosity()) +      Report("Cannot initialize FDR logging; wrong size for options: %d\n", +             OptionsSize); +    return static_cast<XRayLogInitStatus>( +        atomic_load(&LoggingStatus, memory_order_acquire)); +  } else { +    if (Verbosity()) +      Report("XRay FDR: struct-based init is deprecated, please use " +             "string-based configuration instead.\n"); +    SpinMutexLock Guard(&FDROptionsMutex); +    internal_memcpy(&FDROptions, Options, OptionsSize);    }    bool Success = false;    if (BQ != nullptr) { -    delete BQ; +    BQ->~BufferQueue(); +    InternalFree(BQ);      BQ = nullptr;    } -  if (BQ == nullptr) -    BQ = new BufferQueue(BufferSize, BufferMax, Success); +  if (BQ == nullptr) { +    BQ = reinterpret_cast<BufferQueue *>( +        InternalAlloc(sizeof(BufferQueue), nullptr, 64)); +    new (BQ) BufferQueue(BufferSize, BufferMax, Success); +  }    if (!Success) {      Report("BufferQueue init failed.\n");      if (BQ != nullptr) { -      delete BQ; +      BQ->~BufferQueue(); +      InternalFree(BQ);        BQ = nullptr;      }      return XRayLogInitStatus::XRAY_LOG_UNINITIALIZED;    } -  static bool UNUSED Once = [] { -    pthread_key_create(&__xray_fdr_internal::Key, +[](void *) { -      auto &TLD = __xray_fdr_internal::getThreadLocalData(); +  static pthread_once_t OnceInit = PTHREAD_ONCE_INIT; +  pthread_once(&OnceInit, +[] { +    atomic_store(&TicksPerSec, +                 probeRequiredCPUFeatures() ? getTSCFrequency() +                                            : __xray::NanosecondsPerSecond, +                 memory_order_release); +    pthread_key_create(&Key, +[](void *TLDPtr) { +      if (TLDPtr == nullptr) +        return; +      auto &TLD = *reinterpret_cast<ThreadLocalData *>(TLDPtr);        if (TLD.BQ == nullptr)          return;        auto EC = TLD.BQ->releaseBuffer(TLD.Buffer);        if (EC != BufferQueue::ErrorCode::Ok)          Report("At thread exit, failed to release buffer at %p; error=%s\n", -               TLD.Buffer.Buffer, BufferQueue::getErrorString(EC)); +               TLD.Buffer.Data, BufferQueue::getErrorString(EC));      }); -    return false; -  }(); +  }); +  atomic_store(&ThresholdTicks, +               atomic_load_relaxed(&TicksPerSec) * +                   fdrFlags()->func_duration_threshold_us / 1000000, +               memory_order_release);    // Arg1 handler should go in first to avoid concurrent code accidentally    // falling back to arg0 when it should have ran arg1.    __xray_set_handler_arg1(fdrLoggingHandleArg1);    // Install the actual handleArg0 handler after initialising the buffers.    __xray_set_handler(fdrLoggingHandleArg0);    __xray_set_customevent_handler(fdrLoggingHandleCustomEvent); +  __xray_set_typedevent_handler(fdrLoggingHandleTypedEvent); + +  // Install the buffer iterator implementation. +  __xray_log_set_buffer_iterator(fdrIterator); -  __sanitizer::atomic_store(&LoggingStatus, -                            XRayLogInitStatus::XRAY_LOG_INITIALIZED, -                            __sanitizer::memory_order_release); +  atomic_store(&LoggingStatus, XRayLogInitStatus::XRAY_LOG_INITIALIZED, +               memory_order_release); -  if (__sanitizer::Verbosity()) +  if (Verbosity())      Report("XRay FDR init successful.\n");    return XRayLogInitStatus::XRAY_LOG_INITIALIZED;  }  bool fdrLogDynamicInitializer() XRAY_NEVER_INSTRUMENT { -  using namespace __xray;    XRayLogImpl Impl{        fdrLoggingInit,        fdrLoggingFinalize, @@ -372,11 +1209,10 @@ bool fdrLogDynamicInitializer() XRAY_NEVER_INSTRUMENT {    };    auto RegistrationResult = __xray_log_register_mode("xray-fdr", Impl);    if (RegistrationResult != XRayLogRegisterStatus::XRAY_REGISTRATION_OK && -      __sanitizer::Verbosity()) +      Verbosity())      Report("Cannot register XRay FDR mode to 'xray-fdr'; error = %d\n",             RegistrationResult); -  if (flags()->xray_fdr_log || -      !__sanitizer::internal_strcmp(flags()->xray_mode, "xray-fdr")) +  if (flags()->xray_fdr_log || !internal_strcmp(flags()->xray_mode, "xray-fdr"))      __xray_set_log_impl(Impl);    return true;  } diff --git a/lib/xray/xray_fdr_logging_impl.h b/lib/xray/xray_fdr_logging_impl.h deleted file mode 100644 index 59eab55b2573c..0000000000000 --- a/lib/xray/xray_fdr_logging_impl.h +++ /dev/null @@ -1,705 +0,0 @@ -//===-- xray_fdr_logging_impl.h ---------------------------------*- C++ -*-===// -// -//                     The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file is a part of XRay, a dynamic runtime instrumentation system. -// -// Here we implement the thread local state management and record i/o for Flight -// Data Recorder mode for XRay, where we use compact structures to store records -// in memory as well as when writing out the data to files. -// -//===----------------------------------------------------------------------===// -#ifndef XRAY_XRAY_FDR_LOGGING_IMPL_H -#define XRAY_XRAY_FDR_LOGGING_IMPL_H - -#include <cassert> -#include <cstddef> -#include <cstring> -#include <limits> -#include <pthread.h> -#include <sys/syscall.h> -#include <time.h> -#include <type_traits> -#include <unistd.h> - -#include "sanitizer_common/sanitizer_common.h" -#include "xray/xray_log_interface.h" -#include "xray_buffer_queue.h" -#include "xray_defs.h" -#include "xray_fdr_log_records.h" -#include "xray_flags.h" -#include "xray_tsc.h" - -namespace __xray { - -__sanitizer::atomic_sint32_t LoggingStatus = { -    XRayLogInitStatus::XRAY_LOG_UNINITIALIZED}; - -/// We expose some of the state transitions when FDR logging mode is operating -/// such that we can simulate a series of log events that may occur without -/// and test with determinism without worrying about the real CPU time. -/// -/// Because the code uses thread_local allocation extensively as part of its -/// design, callers that wish to test events occuring on different threads -/// will actually have to run them on different threads. -/// -/// This also means that it is possible to break invariants maintained by -/// cooperation with xray_fdr_logging class, so be careful and think twice. -namespace __xray_fdr_internal { - -/// Writes the new buffer record and wallclock time that begin a buffer for the -/// current thread. -static void writeNewBufferPreamble(pid_t Tid, timespec TS); - -/// Writes a Function Record to the buffer associated with the current thread. -static void writeFunctionRecord(int FuncId, uint32_t TSCDelta, -                                XRayEntryType EntryType); - -/// Sets up a new buffer in thread_local storage and writes a preamble. The -/// wall_clock_reader function is used to populate the WallTimeRecord entry. -static void setupNewBuffer(int (*wall_clock_reader)(clockid_t, -                                                    struct timespec *)); - -/// TSC Wrap records are written when a TSC delta encoding scheme overflows. -static void writeTSCWrapMetadata(uint64_t TSC); - -// Group together thread-local-data in a struct, then hide it behind a function -// call so that it can be initialized on first use instead of as a global. We -// force the alignment to 64-bytes for x86 cache line alignment, as this -// structure is used in the hot path of implementation. -struct alignas(64) ThreadLocalData { -  BufferQueue::Buffer Buffer; -  char *RecordPtr = nullptr; -  // The number of FunctionEntry records immediately preceding RecordPtr. -  uint8_t NumConsecutiveFnEnters = 0; - -  // The number of adjacent, consecutive pairs of FunctionEntry, Tail Exit -  // records preceding RecordPtr. -  uint8_t NumTailCalls = 0; - -  // We use a thread_local variable to keep track of which CPUs we've already -  // run, and the TSC times for these CPUs. This allows us to stop repeating the -  // CPU field in the function records. -  // -  // We assume that we'll support only 65536 CPUs for x86_64. -  uint16_t CurrentCPU = std::numeric_limits<uint16_t>::max(); -  uint64_t LastTSC = 0; -  uint64_t LastFunctionEntryTSC = 0; - -  // Make sure a thread that's ever called handleArg0 has a thread-local -  // live reference to the buffer queue for this particular instance of -  // FDRLogging, and that we're going to clean it up when the thread exits. -  BufferQueue *BQ = nullptr; -}; - -static_assert(std::is_trivially_destructible<ThreadLocalData>::value, -              "ThreadLocalData must be trivially destructible"); - -static constexpr auto MetadataRecSize = sizeof(MetadataRecord); -static constexpr auto FunctionRecSize = sizeof(FunctionRecord); - -// Use a global pthread key to identify thread-local data for logging. -static pthread_key_t Key; - -// This function will initialize the thread-local data structure used by the FDR -// logging implementation and return a reference to it. The implementation -// details require a bit of care to maintain. -// -// First, some requirements on the implementation in general: -// -//   - XRay handlers should not call any memory allocation routines that may -//     delegate to an instrumented implementation. This means functions like -//     malloc() and free() should not be called while instrumenting. -// -//   - We would like to use some thread-local data initialized on first-use of -//     the XRay instrumentation. These allow us to implement unsynchronized -//     routines that access resources associated with the thread. -// -// The implementation here uses a few mechanisms that allow us to provide both -// the requirements listed above. We do this by: -// -//   1. Using a thread-local aligned storage buffer for representing the -//      ThreadLocalData struct. This data will be uninitialized memory by -//      design. -// -//   2. Not requiring a thread exit handler/implementation, keeping the -//      thread-local as purely a collection of references/data that do not -//      require cleanup. -// -// We're doing this to avoid using a `thread_local` object that has a -// non-trivial destructor, because the C++ runtime might call std::malloc(...) -// to register calls to destructors. Deadlocks may arise when, for example, an -// externally provided malloc implementation is XRay instrumented, and -// initializing the thread-locals involves calling into malloc. A malloc -// implementation that does global synchronization might be holding a lock for a -// critical section, calling a function that might be XRay instrumented (and -// thus in turn calling into malloc by virtue of registration of the -// thread_local's destructor). -static ThreadLocalData &getThreadLocalData() { -  static_assert(alignof(ThreadLocalData) >= 64, -                "ThreadLocalData must be cache line aligned."); -  thread_local ThreadLocalData TLD; -  thread_local bool UNUSED ThreadOnce = [] { -    pthread_setspecific(Key, &TLD); -    return false; -  }(); -  return TLD; -} - -//-----------------------------------------------------------------------------| -// The rest of the file is implementation.                                     | -//-----------------------------------------------------------------------------| -// Functions are implemented in the header for inlining since we don't want    | -// to grow the stack when we've hijacked the binary for logging.               | -//-----------------------------------------------------------------------------| - -namespace { - -class RecursionGuard { -  volatile bool &Running; -  const bool Valid; - -public: -  explicit RecursionGuard(volatile bool &R) : Running(R), Valid(!R) { -    if (Valid) -      Running = true; -  } - -  RecursionGuard(const RecursionGuard &) = delete; -  RecursionGuard(RecursionGuard &&) = delete; -  RecursionGuard &operator=(const RecursionGuard &) = delete; -  RecursionGuard &operator=(RecursionGuard &&) = delete; - -  explicit operator bool() const { return Valid; } - -  ~RecursionGuard() noexcept { -    if (Valid) -      Running = false; -  } -}; - -} // namespace - -static void writeNewBufferPreamble(pid_t Tid, -                                   timespec TS) XRAY_NEVER_INSTRUMENT { -  static constexpr int InitRecordsCount = 2; -  auto &TLD = getThreadLocalData(); -  MetadataRecord Metadata[InitRecordsCount]; -  { -    // Write out a MetadataRecord to signify that this is the start of a new -    // buffer, associated with a particular thread, with a new CPU.  For the -    // data, we have 15 bytes to squeeze as much information as we can.  At this -    // point we only write down the following bytes: -    //   - Thread ID (pid_t, 4 bytes) -    auto &NewBuffer = Metadata[0]; -    NewBuffer.Type = uint8_t(RecordType::Metadata); -    NewBuffer.RecordKind = uint8_t(MetadataRecord::RecordKinds::NewBuffer); -    std::memcpy(&NewBuffer.Data, &Tid, sizeof(pid_t)); -  } - -  // Also write the WalltimeMarker record. -  { -    static_assert(sizeof(time_t) <= 8, "time_t needs to be at most 8 bytes"); -    auto &WalltimeMarker = Metadata[1]; -    WalltimeMarker.Type = uint8_t(RecordType::Metadata); -    WalltimeMarker.RecordKind = -        uint8_t(MetadataRecord::RecordKinds::WalltimeMarker); - -    // We only really need microsecond precision here, and enforce across -    // platforms that we need 64-bit seconds and 32-bit microseconds encoded in -    // the Metadata record. -    int32_t Micros = TS.tv_nsec / 1000; -    int64_t Seconds = TS.tv_sec; -    std::memcpy(WalltimeMarker.Data, &Seconds, sizeof(Seconds)); -    std::memcpy(WalltimeMarker.Data + sizeof(Seconds), &Micros, sizeof(Micros)); -  } - -  TLD.NumConsecutiveFnEnters = 0; -  TLD.NumTailCalls = 0; -  if (TLD.BQ == nullptr || TLD.BQ->finalizing()) -    return; -  std::memcpy(TLD.RecordPtr, Metadata, sizeof(Metadata)); -  TLD.RecordPtr += sizeof(Metadata); -  // Since we write out the extents as the first metadata record of the -  // buffer, we need to write out the extents including the extents record. -  __sanitizer::atomic_store(&TLD.Buffer.Extents->Size, sizeof(Metadata), -                            __sanitizer::memory_order_release); -} - -inline void setupNewBuffer(int (*wall_clock_reader)( -    clockid_t, struct timespec *)) XRAY_NEVER_INSTRUMENT { -  auto &TLD = getThreadLocalData(); -  auto &B = TLD.Buffer; -  TLD.RecordPtr = static_cast<char *>(B.Buffer); -  pid_t Tid = syscall(SYS_gettid); -  timespec TS{0, 0}; -  // This is typically clock_gettime, but callers have injection ability. -  wall_clock_reader(CLOCK_MONOTONIC, &TS); -  writeNewBufferPreamble(Tid, TS); -  TLD.NumConsecutiveFnEnters = 0; -  TLD.NumTailCalls = 0; -} - -static void incrementExtents(size_t Add) { -  auto &TLD = getThreadLocalData(); -  __sanitizer::atomic_fetch_add(&TLD.Buffer.Extents->Size, Add, -                                __sanitizer::memory_order_acq_rel); -} - -static void decrementExtents(size_t Subtract) { -  auto &TLD = getThreadLocalData(); -  __sanitizer::atomic_fetch_sub(&TLD.Buffer.Extents->Size, Subtract, -                                __sanitizer::memory_order_acq_rel); -} - -inline void writeNewCPUIdMetadata(uint16_t CPU, -                                  uint64_t TSC) XRAY_NEVER_INSTRUMENT { -  auto &TLD = getThreadLocalData(); -  MetadataRecord NewCPUId; -  NewCPUId.Type = uint8_t(RecordType::Metadata); -  NewCPUId.RecordKind = uint8_t(MetadataRecord::RecordKinds::NewCPUId); - -  // The data for the New CPU will contain the following bytes: -  //   - CPU ID (uint16_t, 2 bytes) -  //   - Full TSC (uint64_t, 8 bytes) -  // Total = 10 bytes. -  std::memcpy(&NewCPUId.Data, &CPU, sizeof(CPU)); -  std::memcpy(&NewCPUId.Data[sizeof(CPU)], &TSC, sizeof(TSC)); -  std::memcpy(TLD.RecordPtr, &NewCPUId, sizeof(MetadataRecord)); -  TLD.RecordPtr += sizeof(MetadataRecord); -  TLD.NumConsecutiveFnEnters = 0; -  TLD.NumTailCalls = 0; -  incrementExtents(sizeof(MetadataRecord)); -} - -inline void writeTSCWrapMetadata(uint64_t TSC) XRAY_NEVER_INSTRUMENT { -  auto &TLD = getThreadLocalData(); -  MetadataRecord TSCWrap; -  TSCWrap.Type = uint8_t(RecordType::Metadata); -  TSCWrap.RecordKind = uint8_t(MetadataRecord::RecordKinds::TSCWrap); - -  // The data for the TSCWrap record contains the following bytes: -  //   - Full TSC (uint64_t, 8 bytes) -  // Total = 8 bytes. -  std::memcpy(&TSCWrap.Data, &TSC, sizeof(TSC)); -  std::memcpy(TLD.RecordPtr, &TSCWrap, sizeof(MetadataRecord)); -  TLD.RecordPtr += sizeof(MetadataRecord); -  TLD.NumConsecutiveFnEnters = 0; -  TLD.NumTailCalls = 0; -  incrementExtents(sizeof(MetadataRecord)); -} - -// Call Argument metadata records store the arguments to a function in the -// order of their appearance; holes are not supported by the buffer format. -static inline void writeCallArgumentMetadata(uint64_t A) XRAY_NEVER_INSTRUMENT { -  auto &TLD = getThreadLocalData(); -  MetadataRecord CallArg; -  CallArg.Type = uint8_t(RecordType::Metadata); -  CallArg.RecordKind = uint8_t(MetadataRecord::RecordKinds::CallArgument); - -  std::memcpy(CallArg.Data, &A, sizeof(A)); -  std::memcpy(TLD.RecordPtr, &CallArg, sizeof(MetadataRecord)); -  TLD.RecordPtr += sizeof(MetadataRecord); -  incrementExtents(sizeof(MetadataRecord)); -} - -static inline void -writeFunctionRecord(int FuncId, uint32_t TSCDelta, -                    XRayEntryType EntryType) XRAY_NEVER_INSTRUMENT { -  FunctionRecord FuncRecord; -  FuncRecord.Type = uint8_t(RecordType::Function); -  // Only take 28 bits of the function id. -  FuncRecord.FuncId = FuncId & ~(0x0F << 28); -  FuncRecord.TSCDelta = TSCDelta; - -  auto &TLD = getThreadLocalData(); -  switch (EntryType) { -  case XRayEntryType::ENTRY: -    ++TLD.NumConsecutiveFnEnters; -    FuncRecord.RecordKind = uint8_t(FunctionRecord::RecordKinds::FunctionEnter); -    break; -  case XRayEntryType::LOG_ARGS_ENTRY: -    // We should not rewind functions with logged args. -    TLD.NumConsecutiveFnEnters = 0; -    TLD.NumTailCalls = 0; -    FuncRecord.RecordKind = uint8_t(FunctionRecord::RecordKinds::FunctionEnter); -    break; -  case XRayEntryType::EXIT: -    // If we've decided to log the function exit, we will never erase the log -    // before it. -    TLD.NumConsecutiveFnEnters = 0; -    TLD.NumTailCalls = 0; -    FuncRecord.RecordKind = uint8_t(FunctionRecord::RecordKinds::FunctionExit); -    break; -  case XRayEntryType::TAIL: -    // If we just entered the function we're tail exiting from or erased every -    // invocation since then, this function entry tail pair is a candidate to -    // be erased when the child function exits. -    if (TLD.NumConsecutiveFnEnters > 0) { -      ++TLD.NumTailCalls; -      TLD.NumConsecutiveFnEnters = 0; -    } else { -      // We will never be able to erase this tail call since we have logged -      // something in between the function entry and tail exit. -      TLD.NumTailCalls = 0; -      TLD.NumConsecutiveFnEnters = 0; -    } -    FuncRecord.RecordKind = -        uint8_t(FunctionRecord::RecordKinds::FunctionTailExit); -    break; -  case XRayEntryType::CUSTOM_EVENT: { -    // This is a bug in patching, so we'll report it once and move on. -    static bool Once = [&] { -      Report("Internal error: patched an XRay custom event call as a function; " -             "func id = %d\n", -             FuncId); -      return true; -    }(); -    (void)Once; -    return; -  } -  } - -  std::memcpy(TLD.RecordPtr, &FuncRecord, sizeof(FunctionRecord)); -  TLD.RecordPtr += sizeof(FunctionRecord); -  incrementExtents(sizeof(FunctionRecord)); -} - -static uint64_t thresholdTicks() { -  static uint64_t TicksPerSec = probeRequiredCPUFeatures() -                                    ? getTSCFrequency() -                                    : __xray::NanosecondsPerSecond; -  static const uint64_t ThresholdTicks = -      TicksPerSec * flags()->xray_fdr_log_func_duration_threshold_us / 1000000; -  return ThresholdTicks; -} - -// Re-point the thread local pointer into this thread's Buffer before the recent -// "Function Entry" record and any "Tail Call Exit" records after that. -static void rewindRecentCall(uint64_t TSC, uint64_t &LastTSC, -                             uint64_t &LastFunctionEntryTSC, int32_t FuncId) { -  auto &TLD = getThreadLocalData(); -  TLD.RecordPtr -= FunctionRecSize; -  decrementExtents(FunctionRecSize); -  FunctionRecord FuncRecord; -  std::memcpy(&FuncRecord, TLD.RecordPtr, FunctionRecSize); -  assert(FuncRecord.RecordKind == -             uint8_t(FunctionRecord::RecordKinds::FunctionEnter) && -         "Expected to find function entry recording when rewinding."); -  assert(FuncRecord.FuncId == (FuncId & ~(0x0F << 28)) && -         "Expected matching function id when rewinding Exit"); -  --TLD.NumConsecutiveFnEnters; -  LastTSC -= FuncRecord.TSCDelta; - -  // We unwound one call. Update the state and return without writing a log. -  if (TLD.NumConsecutiveFnEnters != 0) { -    LastFunctionEntryTSC -= FuncRecord.TSCDelta; -    return; -  } - -  // Otherwise we've rewound the stack of all function entries, we might be -  // able to rewind further by erasing tail call functions that are being -  // exited from via this exit. -  LastFunctionEntryTSC = 0; -  auto RewindingTSC = LastTSC; -  auto RewindingRecordPtr = TLD.RecordPtr - FunctionRecSize; -  while (TLD.NumTailCalls > 0) { -    // Rewind the TSC back over the TAIL EXIT record. -    FunctionRecord ExpectedTailExit; -    std::memcpy(&ExpectedTailExit, RewindingRecordPtr, FunctionRecSize); - -    assert(ExpectedTailExit.RecordKind == -               uint8_t(FunctionRecord::RecordKinds::FunctionTailExit) && -           "Expected to find tail exit when rewinding."); -    RewindingRecordPtr -= FunctionRecSize; -    RewindingTSC -= ExpectedTailExit.TSCDelta; -    FunctionRecord ExpectedFunctionEntry; -    std::memcpy(&ExpectedFunctionEntry, RewindingRecordPtr, FunctionRecSize); -    assert(ExpectedFunctionEntry.RecordKind == -               uint8_t(FunctionRecord::RecordKinds::FunctionEnter) && -           "Expected to find function entry when rewinding tail call."); -    assert(ExpectedFunctionEntry.FuncId == ExpectedTailExit.FuncId && -           "Expected funcids to match when rewinding tail call."); - -    // This tail call exceeded the threshold duration. It will not be erased. -    if ((TSC - RewindingTSC) >= thresholdTicks()) { -      TLD.NumTailCalls = 0; -      return; -    } - -    // We can erase a tail exit pair that we're exiting through since -    // its duration is under threshold. -    --TLD.NumTailCalls; -    RewindingRecordPtr -= FunctionRecSize; -    RewindingTSC -= ExpectedFunctionEntry.TSCDelta; -    TLD.RecordPtr -= 2 * FunctionRecSize; -    LastTSC = RewindingTSC; -    decrementExtents(2 * FunctionRecSize); -  } -} - -inline bool releaseThreadLocalBuffer(BufferQueue &BQArg) { -  auto &TLD = getThreadLocalData(); -  auto EC = BQArg.releaseBuffer(TLD.Buffer); -  if (EC != BufferQueue::ErrorCode::Ok) { -    Report("Failed to release buffer at %p; error=%s\n", TLD.Buffer.Buffer, -           BufferQueue::getErrorString(EC)); -    return false; -  } -  return true; -} - -inline bool prepareBuffer(uint64_t TSC, unsigned char CPU, -                          int (*wall_clock_reader)(clockid_t, -                                                   struct timespec *), -                          size_t MaxSize) XRAY_NEVER_INSTRUMENT { -  auto &TLD = getThreadLocalData(); -  char *BufferStart = static_cast<char *>(TLD.Buffer.Buffer); -  if ((TLD.RecordPtr + MaxSize) > (BufferStart + TLD.Buffer.Size)) { -    if (!releaseThreadLocalBuffer(*TLD.BQ)) -      return false; -    auto EC = TLD.BQ->getBuffer(TLD.Buffer); -    if (EC != BufferQueue::ErrorCode::Ok) { -      Report("Failed to acquire a buffer; error=%s\n", -             BufferQueue::getErrorString(EC)); -      return false; -    } -    setupNewBuffer(wall_clock_reader); - -    // Always write the CPU metadata as the first record in the buffer. -    writeNewCPUIdMetadata(CPU, TSC); -  } -  return true; -} - -inline bool -isLogInitializedAndReady(BufferQueue *LBQ, uint64_t TSC, unsigned char CPU, -                         int (*wall_clock_reader)(clockid_t, struct timespec *)) -    XRAY_NEVER_INSTRUMENT { -  // Bail out right away if logging is not initialized yet. -  // We should take the opportunity to release the buffer though. -  auto Status = __sanitizer::atomic_load(&LoggingStatus, -                                         __sanitizer::memory_order_acquire); -  auto &TLD = getThreadLocalData(); -  if (Status != XRayLogInitStatus::XRAY_LOG_INITIALIZED) { -    if (TLD.RecordPtr != nullptr && -        (Status == XRayLogInitStatus::XRAY_LOG_FINALIZING || -         Status == XRayLogInitStatus::XRAY_LOG_FINALIZED)) { -      if (!releaseThreadLocalBuffer(*LBQ)) -        return false; -      TLD.RecordPtr = nullptr; -      return false; -    } -    return false; -  } - -  if (__sanitizer::atomic_load(&LoggingStatus, -                               __sanitizer::memory_order_acquire) != -          XRayLogInitStatus::XRAY_LOG_INITIALIZED || -      LBQ->finalizing()) { -    if (!releaseThreadLocalBuffer(*LBQ)) -      return false; -    TLD.RecordPtr = nullptr; -  } - -  if (TLD.Buffer.Buffer == nullptr) { -    auto EC = LBQ->getBuffer(TLD.Buffer); -    if (EC != BufferQueue::ErrorCode::Ok) { -      auto LS = __sanitizer::atomic_load(&LoggingStatus, -                                         __sanitizer::memory_order_acquire); -      if (LS != XRayLogInitStatus::XRAY_LOG_FINALIZING && -          LS != XRayLogInitStatus::XRAY_LOG_FINALIZED) -        Report("Failed to acquire a buffer; error=%s\n", -               BufferQueue::getErrorString(EC)); -      return false; -    } - -    setupNewBuffer(wall_clock_reader); - -    // Always write the CPU metadata as the first record in the buffer. -    writeNewCPUIdMetadata(CPU, TSC); -  } - -  if (TLD.CurrentCPU == std::numeric_limits<uint16_t>::max()) { -    // This means this is the first CPU this thread has ever run on. We set -    // the current CPU and record this as the first TSC we've seen. -    TLD.CurrentCPU = CPU; -    writeNewCPUIdMetadata(CPU, TSC); -  } - -  return true; -} // namespace __xray_fdr_internal - -// Compute the TSC difference between the time of measurement and the previous -// event. There are a few interesting situations we need to account for: -// -//   - The thread has migrated to a different CPU. If this is the case, then -//     we write down the following records: -// -//       1. A 'NewCPUId' Metadata record. -//       2. A FunctionRecord with a 0 for the TSCDelta field. -// -//   - The TSC delta is greater than the 32 bits we can store in a -//     FunctionRecord. In this case we write down the following records: -// -//       1. A 'TSCWrap' Metadata record. -//       2. A FunctionRecord with a 0 for the TSCDelta field. -// -//   - The TSC delta is representable within the 32 bits we can store in a -//     FunctionRecord. In this case we write down just a FunctionRecord with -//     the correct TSC delta. -inline uint32_t writeCurrentCPUTSC(ThreadLocalData &TLD, uint64_t TSC, -                                   uint8_t CPU) { -  if (CPU != TLD.CurrentCPU) { -    // We've moved to a new CPU. -    writeNewCPUIdMetadata(CPU, TSC); -    return 0; -  } -  // If the delta is greater than the range for a uint32_t, then we write out -  // the TSC wrap metadata entry with the full TSC, and the TSC for the -  // function record be 0. -  uint64_t Delta = TSC - TLD.LastTSC; -  if (Delta <= std::numeric_limits<uint32_t>::max()) -    return Delta; - -  writeTSCWrapMetadata(TSC); -  return 0; -} - -inline void endBufferIfFull() XRAY_NEVER_INSTRUMENT { -  auto &TLD = getThreadLocalData(); -  auto BufferStart = static_cast<char *>(TLD.Buffer.Buffer); -  if ((TLD.RecordPtr + MetadataRecSize) - BufferStart <= -      ptrdiff_t{MetadataRecSize}) { -    if (!releaseThreadLocalBuffer(*TLD.BQ)) -      return; -    TLD.RecordPtr = nullptr; -  } -} - -thread_local volatile bool Running = false; - -/// Here's where the meat of the processing happens. The writer captures -/// function entry, exit and tail exit points with a time and will create -/// TSCWrap, NewCPUId and Function records as necessary. The writer might -/// walk backward through its buffer and erase trivial functions to avoid -/// polluting the log and may use the buffer queue to obtain or release a -/// buffer. -inline void processFunctionHook(int32_t FuncId, XRayEntryType Entry, -                                uint64_t TSC, unsigned char CPU, uint64_t Arg1, -                                int (*wall_clock_reader)(clockid_t, -                                                         struct timespec *), -                                BufferQueue *BQ) XRAY_NEVER_INSTRUMENT { -  // Prevent signal handler recursion, so in case we're already in a log writing -  // mode and the signal handler comes in (and is also instrumented) then we -  // don't want to be clobbering potentially partial writes already happening in -  // the thread. We use a simple thread_local latch to only allow one on-going -  // handleArg0 to happen at any given time. -  RecursionGuard Guard{Running}; -  if (!Guard) { -    assert(Running == true && "RecursionGuard is buggy!"); -    return; -  } - -  auto &TLD = getThreadLocalData(); - -  // In case the reference has been cleaned up before, we make sure we -  // initialize it to the provided BufferQueue. -  if (TLD.BQ == nullptr) -    TLD.BQ = BQ; - -  if (!isLogInitializedAndReady(TLD.BQ, TSC, CPU, wall_clock_reader)) -    return; - -  // Before we go setting up writing new function entries, we need to be really -  // careful about the pointer math we're doing. This means we need to ensure -  // that the record we are about to write is going to fit into the buffer, -  // without overflowing the buffer. -  // -  // To do this properly, we use the following assumptions: -  // -  //   - The least number of bytes we will ever write is 8 -  //     (sizeof(FunctionRecord)) only if the delta between the previous entry -  //     and this entry is within 32 bits. -  //   - The most number of bytes we will ever write is 8 + 16 + 16 = 40. -  //     This is computed by: -  // -  //       MaxSize = sizeof(FunctionRecord) + 2 * sizeof(MetadataRecord) -  // -  //     These arise in the following cases: -  // -  //       1. When the delta between the TSC we get and the previous TSC for the -  //          same CPU is outside of the uint32_t range, we end up having to -  //          write a MetadataRecord to indicate a "tsc wrap" before the actual -  //          FunctionRecord. -  //       2. When we learn that we've moved CPUs, we need to write a -  //          MetadataRecord to indicate a "cpu change", and thus write out the -  //          current TSC for that CPU before writing out the actual -  //          FunctionRecord. -  //       3. When we learn about a new CPU ID, we need to write down a "new cpu -  //          id" MetadataRecord before writing out the actual FunctionRecord. -  //       4. The second MetadataRecord is the optional function call argument. -  // -  // So the math we need to do is to determine whether writing 40 bytes past the -  // current pointer exceeds the buffer's maximum size. If we don't have enough -  // space to write 40 bytes in the buffer, we need get a new Buffer, set it up -  // properly before doing any further writing. -  size_t MaxSize = FunctionRecSize + 2 * MetadataRecSize; -  if (!prepareBuffer(TSC, CPU, wall_clock_reader, MaxSize)) { -    TLD.BQ = nullptr; -    return; -  } - -  // By this point, we are now ready to write up to 40 bytes (explained above). -  assert((TLD.RecordPtr + MaxSize) - static_cast<char *>(TLD.Buffer.Buffer) >= -             static_cast<ptrdiff_t>(MetadataRecSize) && -         "Misconfigured BufferQueue provided; Buffer size not large enough."); - -  auto RecordTSCDelta = writeCurrentCPUTSC(TLD, TSC, CPU); -  TLD.LastTSC = TSC; -  TLD.CurrentCPU = CPU; -  switch (Entry) { -  case XRayEntryType::ENTRY: -  case XRayEntryType::LOG_ARGS_ENTRY: -    // Update the thread local state for the next invocation. -    TLD.LastFunctionEntryTSC = TSC; -    break; -  case XRayEntryType::TAIL: -  case XRayEntryType::EXIT: -    // Break out and write the exit record if we can't erase any functions. -    if (TLD.NumConsecutiveFnEnters == 0 || -        (TSC - TLD.LastFunctionEntryTSC) >= thresholdTicks()) -      break; -    rewindRecentCall(TSC, TLD.LastTSC, TLD.LastFunctionEntryTSC, FuncId); -    return; // without writing log. -  case XRayEntryType::CUSTOM_EVENT: { -    // This is a bug in patching, so we'll report it once and move on. -    static bool Once = [&] { -      Report("Internal error: patched an XRay custom event call as a function; " -             "func id = %d", -             FuncId); -      return true; -    }(); -    (void)Once; -    return; -  } -  } - -  writeFunctionRecord(FuncId, RecordTSCDelta, Entry); -  if (Entry == XRayEntryType::LOG_ARGS_ENTRY) -    writeCallArgumentMetadata(Arg1); - -  // If we've exhausted the buffer by this time, we then release the buffer to -  // make sure that other threads may start using this buffer. -  endBufferIfFull(); -} - -} // namespace __xray_fdr_internal -} // namespace __xray - -#endif // XRAY_XRAY_FDR_LOGGING_IMPL_H diff --git a/lib/xray/xray_flags.cc b/lib/xray/xray_flags.cc index 1ee4d10d753cd..b50b68666d808 100644 --- a/lib/xray/xray_flags.cc +++ b/lib/xray/xray_flags.cc @@ -30,7 +30,7 @@ void Flags::setDefaults() XRAY_NEVER_INSTRUMENT {  #undef XRAY_FLAG  } -static void registerXRayFlags(FlagParser *P, Flags *F) XRAY_NEVER_INSTRUMENT { +void registerXRayFlags(FlagParser *P, Flags *F) XRAY_NEVER_INSTRUMENT {  #define XRAY_FLAG(Type, Name, DefaultValue, Description)                       \    RegisterFlag(P, #Name, Description, &F->Name);  #include "xray_flags.inc" @@ -42,15 +42,14 @@ static void registerXRayFlags(FlagParser *P, Flags *F) XRAY_NEVER_INSTRUMENT {  // options that control XRay. This means users/deployments can tweak the  // defaults that override the hard-coded defaults in the xray_flags.inc at  // compile-time using the XRAY_DEFAULT_OPTIONS macro. -static const char *useCompilerDefinedFlags() XRAY_NEVER_INSTRUMENT { +const char *useCompilerDefinedFlags() XRAY_NEVER_INSTRUMENT {  #ifdef XRAY_DEFAULT_OPTIONS -// Do the double-layered string conversion to prevent badly crafted strings -// provided through the XRAY_DEFAULT_OPTIONS from causing compilation issues (or -// changing the semantics of the implementation through the macro). This ensures -// that we convert whatever XRAY_DEFAULT_OPTIONS is defined as a string literal. -#define XRAY_STRINGIZE(x) #x -#define XRAY_STRINGIZE_OPTIONS(options) XRAY_STRINGIZE(options) -  return XRAY_STRINGIZE_OPTIONS(XRAY_DEFAULT_OPTIONS); +  // Do the double-layered string conversion to prevent badly crafted strings +  // provided through the XRAY_DEFAULT_OPTIONS from causing compilation issues +  // (or changing the semantics of the implementation through the macro). This +  // ensures that we convert whatever XRAY_DEFAULT_OPTIONS is defined as a +  // string literal. +  return SANITIZER_STRINGIFY(XRAY_DEFAULT_OPTIONS);  #else    return "";  #endif diff --git a/lib/xray/xray_flags.h b/lib/xray/xray_flags.h index 3ed5b8844cb46..7c1ba94588562 100644 --- a/lib/xray/xray_flags.h +++ b/lib/xray/xray_flags.h @@ -29,6 +29,8 @@ struct Flags {  };  extern Flags xray_flags_dont_use_directly; +extern void registerXRayFlags(FlagParser *P, Flags *F); +const char *useCompilerDefinedFlags();  inline Flags *flags() { return &xray_flags_dont_use_directly; }  void initializeFlags(); diff --git a/lib/xray/xray_flags.inc b/lib/xray/xray_flags.inc index 29f1fce7d7f4d..c87903963a362 100644 --- a/lib/xray/xray_flags.inc +++ b/lib/xray/xray_flags.inc @@ -27,23 +27,24 @@ XRAY_FLAG(uptr, xray_page_size_override, 0,  XRAY_FLAG(bool, xray_naive_log, false,            "DEPRECATED: Use xray_mode=xray-basic instead.")  XRAY_FLAG(int, xray_naive_log_func_duration_threshold_us, 5, -          "Naive logging will try to skip functions that execute for fewer " -          "microseconds than this threshold.") +          "DEPRECATED: use the environment variable XRAY_BASIC_OPTIONS and set " +          "func_duration_threshold_us instead.")  XRAY_FLAG(int, xray_naive_log_max_stack_depth, 64, -          "Naive logging will keep track of at most this deep a call stack, " -          "any more and the recordings will be droppped.") +          "DEPRECATED: use the environment variable XRAY_BASIC_OPTIONS and set " +          "max_stack_depth instead.")  XRAY_FLAG(int, xray_naive_log_thread_buffer_size, 1024, -          "The number of entries to keep on a per-thread buffer.") +          "DEPRECATED: use the environment variable XRAY_BASIC_OPTIONS and set " +          "thread_buffer_size instead.")  // FDR (Flight Data Recorder) Mode logging options.  XRAY_FLAG(bool, xray_fdr_log, false,            "DEPRECATED: Use xray_mode=xray-fdr instead.")  XRAY_FLAG(int, xray_fdr_log_func_duration_threshold_us, 5, -          "FDR logging will try to skip functions that execute for fewer " -          "microseconds than this threshold.") +          "DEPRECATED: use the environment variable XRAY_FDR_OPTIONS and set " +          "func_duration_threshold_us instead.")  XRAY_FLAG(int, xray_fdr_log_grace_period_us, 0, -          "DEPRECATED: use xray_fdr_log_grace_period_ms instead.") +          "DEPRECATED: use the environment variable XRAY_FDR_OPTIONS and set " +          "grace_period_ms instead.")  XRAY_FLAG(int, xray_fdr_log_grace_period_ms, 100, -          "FDR logging will wait this much time in microseconds before " -          "actually flushing the log; this gives a chance for threads to " -          "notice that the log has been finalized and clean up.") +          "DEPRECATED: use the environment variable XRAY_FDR_OPTIONS and set " +          "grace_period_ms instead.") diff --git a/lib/xray/xray_function_call_trie.h b/lib/xray/xray_function_call_trie.h new file mode 100644 index 0000000000000..2acf14aa5625f --- /dev/null +++ b/lib/xray/xray_function_call_trie.h @@ -0,0 +1,455 @@ +//===-- xray_function_call_trie.h ------------------------------*- C++ -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of XRay, a dynamic runtime instrumentation system. +// +// This file defines the interface for a function call trie. +// +//===----------------------------------------------------------------------===// +#ifndef XRAY_FUNCTION_CALL_TRIE_H +#define XRAY_FUNCTION_CALL_TRIE_H + +#include "sanitizer_common/sanitizer_allocator_internal.h" +#include "xray_profiling_flags.h" +#include "xray_segmented_array.h" +#include <memory> // For placement new. +#include <utility> + +namespace __xray { + +/// A FunctionCallTrie represents the stack traces of XRay instrumented +/// functions that we've encountered, where a node corresponds to a function and +/// the path from the root to the node its stack trace. Each node in the trie +/// will contain some useful values, including: +/// +///   * The cumulative amount of time spent in this particular node/stack. +///   * The number of times this stack has appeared. +///   * A histogram of latencies for that particular node. +/// +/// Each node in the trie will also contain a list of callees, represented using +/// a Array<NodeIdPair> -- each NodeIdPair instance will contain the function +/// ID of the callee, and a pointer to the node. +/// +/// If we visualise this data structure, we'll find the following potential +/// representation: +/// +///   [function id node] -> [callees] [cumulative time] +///                         [call counter] [latency histogram] +/// +/// As an example, when we have a function in this pseudocode: +/// +///   func f(N) { +///     g() +///     h() +///     for i := 1..N { j() } +///   } +/// +/// We may end up with a trie of the following form: +/// +///   f -> [ g, h, j ] [...] [1] [...] +///   g -> [ ... ] [...] [1] [...] +///   h -> [ ... ] [...] [1] [...] +///   j -> [ ... ] [...] [N] [...] +/// +/// If for instance the function g() called j() like so: +/// +///   func g() { +///     for i := 1..10 { j() } +///   } +/// +/// We'll find the following updated trie: +/// +///   f -> [ g, h, j ] [...] [1] [...] +///   g -> [ j' ] [...] [1] [...] +///   h -> [ ... ] [...] [1] [...] +///   j -> [ ... ] [...] [N] [...] +///   j' -> [ ... ] [...] [10] [...] +/// +/// Note that we'll have a new node representing the path `f -> g -> j'` with +/// isolated data. This isolation gives us a means of representing the stack +/// traces as a path, as opposed to a key in a table. The alternative +/// implementation here would be to use a separate table for the path, and use +/// hashes of the path as an identifier to accumulate the information. We've +/// moved away from this approach as it takes a lot of time to compute the hash +/// every time we need to update a function's call information as we're handling +/// the entry and exit events. +/// +/// This approach allows us to maintain a shadow stack, which represents the +/// currently executing path, and on function exits quickly compute the amount +/// of time elapsed from the entry, then update the counters for the node +/// already represented in the trie. This necessitates an efficient +/// representation of the various data structures (the list of callees must be +/// cache-aware and efficient to look up, and the histogram must be compact and +/// quick to update) to enable us to keep the overheads of this implementation +/// to the minimum. +class FunctionCallTrie { +public: +  struct Node; + +  // We use a NodeIdPair type instead of a std::pair<...> to not rely on the +  // standard library types in this header. +  struct NodeIdPair { +    Node *NodePtr; +    int32_t FId; + +    // Constructor for inplace-construction. +    NodeIdPair(Node *N, int32_t F) : NodePtr(N), FId(F) {} +  }; + +  using NodeIdPairArray = Array<NodeIdPair>; +  using NodeIdPairAllocatorType = NodeIdPairArray::AllocatorType; + +  // A Node in the FunctionCallTrie gives us a list of callees, the cumulative +  // number of times this node actually appeared, the cumulative amount of time +  // for this particular node including its children call times, and just the +  // local time spent on this node. Each Node will have the ID of the XRay +  // instrumented function that it is associated to. +  struct Node { +    Node *Parent; +    NodeIdPairArray Callees; +    int64_t CallCount; +    int64_t CumulativeLocalTime; // Typically in TSC deltas, not wall-time. +    int32_t FId; + +    // We add a constructor here to allow us to inplace-construct through +    // Array<...>'s AppendEmplace. +    Node(Node *P, NodeIdPairAllocatorType &A, int64_t CC, int64_t CLT, +         int32_t F) +        : Parent(P), Callees(A), CallCount(CC), CumulativeLocalTime(CLT), +          FId(F) {} + +    // TODO: Include the compact histogram. +  }; + +private: +  struct ShadowStackEntry { +    uint64_t EntryTSC; +    Node *NodePtr; + +    // We add a constructor here to allow us to inplace-construct through +    // Array<...>'s AppendEmplace. +    ShadowStackEntry(uint64_t T, Node *N) : EntryTSC{T}, NodePtr{N} {} +  }; + +  using NodeArray = Array<Node>; +  using RootArray = Array<Node *>; +  using ShadowStackArray = Array<ShadowStackEntry>; + +public: +  // We collate the allocators we need into a single struct, as a convenience to +  // allow us to initialize these as a group. +  struct Allocators { +    using NodeAllocatorType = NodeArray::AllocatorType; +    using RootAllocatorType = RootArray::AllocatorType; +    using ShadowStackAllocatorType = ShadowStackArray::AllocatorType; + +    NodeAllocatorType *NodeAllocator = nullptr; +    RootAllocatorType *RootAllocator = nullptr; +    ShadowStackAllocatorType *ShadowStackAllocator = nullptr; +    NodeIdPairAllocatorType *NodeIdPairAllocator = nullptr; + +    Allocators() {} +    Allocators(const Allocators &) = delete; +    Allocators &operator=(const Allocators &) = delete; + +    Allocators(Allocators &&O) +        : NodeAllocator(O.NodeAllocator), RootAllocator(O.RootAllocator), +          ShadowStackAllocator(O.ShadowStackAllocator), +          NodeIdPairAllocator(O.NodeIdPairAllocator) { +      O.NodeAllocator = nullptr; +      O.RootAllocator = nullptr; +      O.ShadowStackAllocator = nullptr; +      O.NodeIdPairAllocator = nullptr; +    } + +    Allocators &operator=(Allocators &&O) { +      { +        auto Tmp = O.NodeAllocator; +        O.NodeAllocator = this->NodeAllocator; +        this->NodeAllocator = Tmp; +      } +      { +        auto Tmp = O.RootAllocator; +        O.RootAllocator = this->RootAllocator; +        this->RootAllocator = Tmp; +      } +      { +        auto Tmp = O.ShadowStackAllocator; +        O.ShadowStackAllocator = this->ShadowStackAllocator; +        this->ShadowStackAllocator = Tmp; +      } +      { +        auto Tmp = O.NodeIdPairAllocator; +        O.NodeIdPairAllocator = this->NodeIdPairAllocator; +        this->NodeIdPairAllocator = Tmp; +      } +      return *this; +    } + +    ~Allocators() { +      // Note that we cannot use delete on these pointers, as they need to be +      // returned to the sanitizer_common library's internal memory tracking +      // system. +      if (NodeAllocator != nullptr) { +        NodeAllocator->~NodeAllocatorType(); +        InternalFree(NodeAllocator); +        NodeAllocator = nullptr; +      } +      if (RootAllocator != nullptr) { +        RootAllocator->~RootAllocatorType(); +        InternalFree(RootAllocator); +        RootAllocator = nullptr; +      } +      if (ShadowStackAllocator != nullptr) { +        ShadowStackAllocator->~ShadowStackAllocatorType(); +        InternalFree(ShadowStackAllocator); +        ShadowStackAllocator = nullptr; +      } +      if (NodeIdPairAllocator != nullptr) { +        NodeIdPairAllocator->~NodeIdPairAllocatorType(); +        InternalFree(NodeIdPairAllocator); +        NodeIdPairAllocator = nullptr; +      } +    } +  }; + +  // TODO: Support configuration of options through the arguments. +  static Allocators InitAllocators() { +    return InitAllocatorsCustom(profilingFlags()->per_thread_allocator_max); +  } + +  static Allocators InitAllocatorsCustom(uptr Max) { +    Allocators A; +    auto NodeAllocator = reinterpret_cast<Allocators::NodeAllocatorType *>( +        InternalAlloc(sizeof(Allocators::NodeAllocatorType))); +    new (NodeAllocator) Allocators::NodeAllocatorType(Max); +    A.NodeAllocator = NodeAllocator; + +    auto RootAllocator = reinterpret_cast<Allocators::RootAllocatorType *>( +        InternalAlloc(sizeof(Allocators::RootAllocatorType))); +    new (RootAllocator) Allocators::RootAllocatorType(Max); +    A.RootAllocator = RootAllocator; + +    auto ShadowStackAllocator = +        reinterpret_cast<Allocators::ShadowStackAllocatorType *>( +            InternalAlloc(sizeof(Allocators::ShadowStackAllocatorType))); +    new (ShadowStackAllocator) Allocators::ShadowStackAllocatorType(Max); +    A.ShadowStackAllocator = ShadowStackAllocator; + +    auto NodeIdPairAllocator = reinterpret_cast<NodeIdPairAllocatorType *>( +        InternalAlloc(sizeof(NodeIdPairAllocatorType))); +    new (NodeIdPairAllocator) NodeIdPairAllocatorType(Max); +    A.NodeIdPairAllocator = NodeIdPairAllocator; +    return A; +  } + +private: +  NodeArray Nodes; +  RootArray Roots; +  ShadowStackArray ShadowStack; +  NodeIdPairAllocatorType *NodeIdPairAllocator = nullptr; + +public: +  explicit FunctionCallTrie(const Allocators &A) +      : Nodes(*A.NodeAllocator), Roots(*A.RootAllocator), +        ShadowStack(*A.ShadowStackAllocator), +        NodeIdPairAllocator(A.NodeIdPairAllocator) {} + +  void enterFunction(const int32_t FId, uint64_t TSC) { +    DCHECK_NE(FId, 0); +    // This function primarily deals with ensuring that the ShadowStack is +    // consistent and ready for when an exit event is encountered. +    if (UNLIKELY(ShadowStack.empty())) { +      auto NewRoot = +          Nodes.AppendEmplace(nullptr, *NodeIdPairAllocator, 0, 0, FId); +      if (UNLIKELY(NewRoot == nullptr)) +        return; +      Roots.Append(NewRoot); +      ShadowStack.AppendEmplace(TSC, NewRoot); +      return; +    } + +    auto &Top = ShadowStack.back(); +    auto TopNode = Top.NodePtr; +    DCHECK_NE(TopNode, nullptr); + +    // If we've seen this callee before, then we just access that node and place +    // that on the top of the stack. +    auto Callee = TopNode->Callees.find_element( +        [FId](const NodeIdPair &NR) { return NR.FId == FId; }); +    if (Callee != nullptr) { +      CHECK_NE(Callee->NodePtr, nullptr); +      ShadowStack.AppendEmplace(TSC, Callee->NodePtr); +      return; +    } + +    // This means we've never seen this stack before, create a new node here. +    auto NewNode = +        Nodes.AppendEmplace(TopNode, *NodeIdPairAllocator, 0, 0, FId); +    if (UNLIKELY(NewNode == nullptr)) +      return; +    DCHECK_NE(NewNode, nullptr); +    TopNode->Callees.AppendEmplace(NewNode, FId); +    ShadowStack.AppendEmplace(TSC, NewNode); +    DCHECK_NE(ShadowStack.back().NodePtr, nullptr); +    return; +  } + +  void exitFunction(int32_t FId, uint64_t TSC) { +    // When we exit a function, we look up the ShadowStack to see whether we've +    // entered this function before. We do as little processing here as we can, +    // since most of the hard work would have already been done at function +    // entry. +    uint64_t CumulativeTreeTime = 0; +    while (!ShadowStack.empty()) { +      const auto &Top = ShadowStack.back(); +      auto TopNode = Top.NodePtr; +      DCHECK_NE(TopNode, nullptr); +      auto LocalTime = TSC - Top.EntryTSC; +      TopNode->CallCount++; +      TopNode->CumulativeLocalTime += LocalTime - CumulativeTreeTime; +      CumulativeTreeTime += LocalTime; +      ShadowStack.trim(1); + +      // TODO: Update the histogram for the node. +      if (TopNode->FId == FId) +        break; +    } +  } + +  const RootArray &getRoots() const { return Roots; } + +  // The deepCopyInto operation will update the provided FunctionCallTrie by +  // re-creating the contents of this particular FunctionCallTrie in the other +  // FunctionCallTrie. It will do this using a Depth First Traversal from the +  // roots, and while doing so recreating the traversal in the provided +  // FunctionCallTrie. +  // +  // This operation will *not* destroy the state in `O`, and thus may cause some +  // duplicate entries in `O` if it is not empty. +  // +  // This function is *not* thread-safe, and may require external +  // synchronisation of both "this" and |O|. +  // +  // This function must *not* be called with a non-empty FunctionCallTrie |O|. +  void deepCopyInto(FunctionCallTrie &O) const { +    DCHECK(O.getRoots().empty()); + +    // We then push the root into a stack, to use as the parent marker for new +    // nodes we push in as we're traversing depth-first down the call tree. +    struct NodeAndParent { +      FunctionCallTrie::Node *Node; +      FunctionCallTrie::Node *NewNode; +    }; +    using Stack = Array<NodeAndParent>; + +    typename Stack::AllocatorType StackAllocator( +        profilingFlags()->stack_allocator_max); +    Stack DFSStack(StackAllocator); + +    for (const auto Root : getRoots()) { +      // Add a node in O for this root. +      auto NewRoot = O.Nodes.AppendEmplace( +          nullptr, *O.NodeIdPairAllocator, Root->CallCount, +          Root->CumulativeLocalTime, Root->FId); + +      // Because we cannot allocate more memory we should bail out right away. +      if (UNLIKELY(NewRoot == nullptr)) +        return; + +      O.Roots.Append(NewRoot); + +      // TODO: Figure out what to do if we fail to allocate any more stack +      // space. Maybe warn or report once? +      DFSStack.AppendEmplace(Root, NewRoot); +      while (!DFSStack.empty()) { +        NodeAndParent NP = DFSStack.back(); +        DCHECK_NE(NP.Node, nullptr); +        DCHECK_NE(NP.NewNode, nullptr); +        DFSStack.trim(1); +        for (const auto Callee : NP.Node->Callees) { +          auto NewNode = O.Nodes.AppendEmplace( +              NP.NewNode, *O.NodeIdPairAllocator, Callee.NodePtr->CallCount, +              Callee.NodePtr->CumulativeLocalTime, Callee.FId); +          if (UNLIKELY(NewNode == nullptr)) +            return; +          NP.NewNode->Callees.AppendEmplace(NewNode, Callee.FId); +          DFSStack.AppendEmplace(Callee.NodePtr, NewNode); +        } +      } +    } +  } + +  // The mergeInto operation will update the provided FunctionCallTrie by +  // traversing the current trie's roots and updating (i.e. merging) the data in +  // the nodes with the data in the target's nodes. If the node doesn't exist in +  // the provided trie, we add a new one in the right position, and inherit the +  // data from the original (current) trie, along with all its callees. +  // +  // This function is *not* thread-safe, and may require external +  // synchronisation of both "this" and |O|. +  void mergeInto(FunctionCallTrie &O) const { +    struct NodeAndTarget { +      FunctionCallTrie::Node *OrigNode; +      FunctionCallTrie::Node *TargetNode; +    }; +    using Stack = Array<NodeAndTarget>; +    typename Stack::AllocatorType StackAllocator( +        profilingFlags()->stack_allocator_max); +    Stack DFSStack(StackAllocator); + +    for (const auto Root : getRoots()) { +      Node *TargetRoot = nullptr; +      auto R = O.Roots.find_element( +          [&](const Node *Node) { return Node->FId == Root->FId; }); +      if (R == nullptr) { +        TargetRoot = O.Nodes.AppendEmplace(nullptr, *O.NodeIdPairAllocator, 0, +                                           0, Root->FId); +        if (UNLIKELY(TargetRoot == nullptr)) +          return; + +        O.Roots.Append(TargetRoot); +      } else { +        TargetRoot = *R; +      } + +      DFSStack.Append(NodeAndTarget{Root, TargetRoot}); +      while (!DFSStack.empty()) { +        NodeAndTarget NT = DFSStack.back(); +        DCHECK_NE(NT.OrigNode, nullptr); +        DCHECK_NE(NT.TargetNode, nullptr); +        DFSStack.trim(1); +        // TODO: Update the histogram as well when we have it ready. +        NT.TargetNode->CallCount += NT.OrigNode->CallCount; +        NT.TargetNode->CumulativeLocalTime += NT.OrigNode->CumulativeLocalTime; +        for (const auto Callee : NT.OrigNode->Callees) { +          auto TargetCallee = NT.TargetNode->Callees.find_element( +              [&](const FunctionCallTrie::NodeIdPair &C) { +                return C.FId == Callee.FId; +              }); +          if (TargetCallee == nullptr) { +            auto NewTargetNode = O.Nodes.AppendEmplace( +                NT.TargetNode, *O.NodeIdPairAllocator, 0, 0, Callee.FId); + +            if (UNLIKELY(NewTargetNode == nullptr)) +              return; + +            TargetCallee = +                NT.TargetNode->Callees.AppendEmplace(NewTargetNode, Callee.FId); +          } +          DFSStack.AppendEmplace(Callee.NodePtr, TargetCallee->NodePtr); +        } +      } +    } +  } +}; + +} // namespace __xray + +#endif // XRAY_FUNCTION_CALL_TRIE_H diff --git a/lib/xray/xray_init.cc b/lib/xray/xray_init.cc index 11892cb8b7a31..b4e0697951954 100644 --- a/lib/xray/xray_init.cc +++ b/lib/xray/xray_init.cc @@ -38,32 +38,29 @@ using namespace __xray;  //  // FIXME: Support DSO instrumentation maps too. The current solution only works  // for statically linked executables. -__sanitizer::atomic_uint8_t XRayInitialized{0}; +atomic_uint8_t XRayInitialized{0};  // This should always be updated before XRayInitialized is updated. -__sanitizer::SpinMutex XRayInstrMapMutex; +SpinMutex XRayInstrMapMutex;  XRaySledMap XRayInstrMap;  // Global flag to determine whether the flags have been initialized. -__sanitizer::atomic_uint8_t XRayFlagsInitialized{0}; +atomic_uint8_t XRayFlagsInitialized{0};  // A mutex to allow only one thread to initialize the XRay data structures. -__sanitizer::SpinMutex XRayInitMutex; +SpinMutex XRayInitMutex;  // __xray_init() will do the actual loading of the current process' memory map  // and then proceed to look for the .xray_instr_map section/segment.  void __xray_init() XRAY_NEVER_INSTRUMENT { -  __sanitizer::SpinMutexLock Guard(&XRayInitMutex); +  SpinMutexLock Guard(&XRayInitMutex);    // Short-circuit if we've already initialized XRay before. -  if (__sanitizer::atomic_load(&XRayInitialized, -                               __sanitizer::memory_order_acquire)) +  if (atomic_load(&XRayInitialized, memory_order_acquire))      return; -  if (!__sanitizer::atomic_load(&XRayFlagsInitialized, -                                __sanitizer::memory_order_acquire)) { +  if (!atomic_load(&XRayFlagsInitialized, memory_order_acquire)) {      initializeFlags(); -    __sanitizer::atomic_store(&XRayFlagsInitialized, true, -                              __sanitizer::memory_order_release); +    atomic_store(&XRayFlagsInitialized, true, memory_order_release);    }    if (__start_xray_instr_map == nullptr) { @@ -73,14 +70,13 @@ void __xray_init() XRAY_NEVER_INSTRUMENT {    }    { -    __sanitizer::SpinMutexLock Guard(&XRayInstrMapMutex); +    SpinMutexLock Guard(&XRayInstrMapMutex);      XRayInstrMap.Sleds = __start_xray_instr_map;      XRayInstrMap.Entries = __stop_xray_instr_map - __start_xray_instr_map;      XRayInstrMap.SledsIndex = __start_xray_fn_idx;      XRayInstrMap.Functions = __stop_xray_fn_idx - __start_xray_fn_idx;    } -  __sanitizer::atomic_store(&XRayInitialized, true, -                            __sanitizer::memory_order_release); +  atomic_store(&XRayInitialized, true, memory_order_release);  #ifndef XRAY_NO_PREINIT    if (flags()->patch_premain) @@ -88,7 +84,13 @@ void __xray_init() XRAY_NEVER_INSTRUMENT {  #endif  } -#if !defined(XRAY_NO_PREINIT) && SANITIZER_CAN_USE_PREINIT_ARRAY +// FIXME: Make check-xray tests work on FreeBSD without +// SANITIZER_CAN_USE_PREINIT_ARRAY. +// See sanitizer_internal_defs.h where the macro is defined. +// Calling unresolved PLT functions in .preinit_array can lead to deadlock on +// FreeBSD but here it seems benign. +#if !defined(XRAY_NO_PREINIT) &&                                               \ +    (SANITIZER_CAN_USE_PREINIT_ARRAY || SANITIZER_FREEBSD)  // Only add the preinit array initialization if the sanitizers can.  __attribute__((section(".preinit_array"),                 used)) void (*__local_xray_preinit)(void) = __xray_init; diff --git a/lib/xray/xray_interface.cc b/lib/xray/xray_interface.cc index 766313e85c584..01bf6ddc607e9 100644 --- a/lib/xray/xray_interface.cc +++ b/lib/xray/xray_interface.cc @@ -19,9 +19,12 @@  #include <cstdio>  #include <errno.h>  #include <limits> +#include <string.h>  #include <sys/mman.h> +#include "sanitizer_common/sanitizer_addrhashmap.h"  #include "sanitizer_common/sanitizer_common.h" +  #include "xray_defs.h"  #include "xray_flags.h" @@ -48,26 +51,40 @@ static const int16_t cSledLength = 8;  #endif /* CPU architecture */  // This is the function to call when we encounter the entry or exit sleds. -__sanitizer::atomic_uintptr_t XRayPatchedFunction{0}; +atomic_uintptr_t XRayPatchedFunction{0};  // This is the function to call from the arg1-enabled sleds/trampolines. -__sanitizer::atomic_uintptr_t XRayArgLogger{0}; +atomic_uintptr_t XRayArgLogger{0};  // This is the function to call when we encounter a custom event log call. -__sanitizer::atomic_uintptr_t XRayPatchedCustomEvent{0}; +atomic_uintptr_t XRayPatchedCustomEvent{0}; + +// This is the function to call when we encounter a typed event log call. +atomic_uintptr_t XRayPatchedTypedEvent{0};  // This is the global status to determine whether we are currently  // patching/unpatching. -__sanitizer::atomic_uint8_t XRayPatching{0}; +atomic_uint8_t XRayPatching{0}; + +struct TypeDescription { +  uint32_t type_id; +  std::size_t description_string_length; +}; + +using TypeDescriptorMapType = AddrHashMap<TypeDescription, 11>; +// An address map from immutable descriptors to type ids. +TypeDescriptorMapType TypeDescriptorAddressMap{}; -// MProtectHelper is an RAII wrapper for calls to mprotect(...) that will undo -// any successful mprotect(...) changes. This is used to make a page writeable -// and executable, and upon destruction if it was successful in doing so returns -// the page into a read-only and executable page. +atomic_uint32_t TypeEventDescriptorCounter{0}; + +// MProtectHelper is an RAII wrapper for calls to mprotect(...) that will +// undo any successful mprotect(...) changes. This is used to make a page +// writeable and executable, and upon destruction if it was successful in +// doing so returns the page into a read-only and executable page.  //  // This is only used specifically for runtime-patching of the XRay -// instrumentation points. This assumes that the executable pages are originally -// read-and-execute only. +// instrumentation points. This assumes that the executable pages are +// originally read-and-execute only.  class MProtectHelper {    void *PageAlignedAddr;    std::size_t MProtectLen; @@ -116,6 +133,9 @@ bool patchSled(const XRaySledEntry &Sled, bool Enable,    case XRayEntryType::CUSTOM_EVENT:      Success = patchCustomEvent(Enable, FuncId, Sled);      break; +  case XRayEntryType::TYPED_EVENT: +    Success = patchTypedEvent(Enable, FuncId, Sled); +    break;    default:      Report("Unsupported sled kind '%d' @%04x\n", Sled.Address, int(Sled.Kind));      return false; @@ -125,19 +145,19 @@ bool patchSled(const XRaySledEntry &Sled, bool Enable,  XRayPatchingStatus patchFunction(int32_t FuncId,                                   bool Enable) XRAY_NEVER_INSTRUMENT { -  if (!__sanitizer::atomic_load(&XRayInitialized, -                                __sanitizer::memory_order_acquire)) +  if (!atomic_load(&XRayInitialized, +                                memory_order_acquire))      return XRayPatchingStatus::NOT_INITIALIZED; // Not initialized.    uint8_t NotPatching = false; -  if (!__sanitizer::atomic_compare_exchange_strong( -          &XRayPatching, &NotPatching, true, __sanitizer::memory_order_acq_rel)) +  if (!atomic_compare_exchange_strong( +          &XRayPatching, &NotPatching, true, memory_order_acq_rel))      return XRayPatchingStatus::ONGOING; // Already patching.    // Next, we look for the function index.    XRaySledMap InstrMap;    { -    __sanitizer::SpinMutexLock Guard(&XRayInstrMapMutex); +    SpinMutexLock Guard(&XRayInstrMapMutex);      InstrMap = XRayInstrMap;    } @@ -161,8 +181,8 @@ XRayPatchingStatus patchFunction(int32_t FuncId,    while (f != e)      SucceedOnce |= patchSled(*f++, Enable, FuncId); -  __sanitizer::atomic_store(&XRayPatching, false, -                            __sanitizer::memory_order_release); +  atomic_store(&XRayPatching, false, +                            memory_order_release);    if (!SucceedOnce) {      Report("Failed patching any sled for function '%d'.", FuncId); @@ -176,26 +196,26 @@ XRayPatchingStatus patchFunction(int32_t FuncId,  // implementation. |Enable| defines whether we're enabling or disabling the  // runtime XRay instrumentation.  XRayPatchingStatus controlPatching(bool Enable) XRAY_NEVER_INSTRUMENT { -  if (!__sanitizer::atomic_load(&XRayInitialized, -                                __sanitizer::memory_order_acquire)) +  if (!atomic_load(&XRayInitialized, +                                memory_order_acquire))      return XRayPatchingStatus::NOT_INITIALIZED; // Not initialized.    uint8_t NotPatching = false; -  if (!__sanitizer::atomic_compare_exchange_strong( -          &XRayPatching, &NotPatching, true, __sanitizer::memory_order_acq_rel)) +  if (!atomic_compare_exchange_strong( +          &XRayPatching, &NotPatching, true, memory_order_acq_rel))      return XRayPatchingStatus::ONGOING; // Already patching.    uint8_t PatchingSuccess = false;    auto XRayPatchingStatusResetter = -      __sanitizer::at_scope_exit([&PatchingSuccess] { +      at_scope_exit([&PatchingSuccess] {          if (!PatchingSuccess) -          __sanitizer::atomic_store(&XRayPatching, false, -                                    __sanitizer::memory_order_release); +          atomic_store(&XRayPatching, false, +                                    memory_order_release);        });    XRaySledMap InstrMap;    { -    __sanitizer::SpinMutexLock Guard(&XRayInstrMapMutex); +    SpinMutexLock Guard(&XRayInstrMapMutex);      InstrMap = XRayInstrMap;    }    if (InstrMap.Entries == 0) @@ -251,8 +271,8 @@ XRayPatchingStatus controlPatching(bool Enable) XRAY_NEVER_INSTRUMENT {      }      patchSled(Sled, Enable, FuncId);    } -  __sanitizer::atomic_store(&XRayPatching, false, -                            __sanitizer::memory_order_release); +  atomic_store(&XRayPatching, false, +                            memory_order_release);    PatchingSuccess = true;    return XRayPatchingStatus::SUCCESS;  } @@ -261,7 +281,7 @@ XRayPatchingStatus mprotectAndPatchFunction(int32_t FuncId,                                              bool Enable) XRAY_NEVER_INSTRUMENT {    XRaySledMap InstrMap;    { -    __sanitizer::SpinMutexLock Guard(&XRayInstrMapMutex); +    SpinMutexLock Guard(&XRayInstrMapMutex);      InstrMap = XRayInstrMap;    } @@ -318,12 +338,12 @@ using namespace __xray;  int __xray_set_handler(void (*entry)(int32_t,                                       XRayEntryType)) XRAY_NEVER_INSTRUMENT { -  if (__sanitizer::atomic_load(&XRayInitialized, -                               __sanitizer::memory_order_acquire)) { +  if (atomic_load(&XRayInitialized, +                               memory_order_acquire)) { -    __sanitizer::atomic_store(&__xray::XRayPatchedFunction, +    atomic_store(&__xray::XRayPatchedFunction,                                reinterpret_cast<uintptr_t>(entry), -                              __sanitizer::memory_order_release); +                              memory_order_release);      return 1;    }    return 0; @@ -331,11 +351,23 @@ int __xray_set_handler(void (*entry)(int32_t,  int __xray_set_customevent_handler(void (*entry)(void *, size_t))      XRAY_NEVER_INSTRUMENT { -  if (__sanitizer::atomic_load(&XRayInitialized, -                               __sanitizer::memory_order_acquire)) { -    __sanitizer::atomic_store(&__xray::XRayPatchedCustomEvent, +  if (atomic_load(&XRayInitialized, +                               memory_order_acquire)) { +    atomic_store(&__xray::XRayPatchedCustomEvent, +                              reinterpret_cast<uintptr_t>(entry), +                              memory_order_release); +    return 1; +  } +  return 0; +} + +int __xray_set_typedevent_handler(void (*entry)( +    uint16_t, const void *, size_t)) XRAY_NEVER_INSTRUMENT { +  if (atomic_load(&XRayInitialized, +                               memory_order_acquire)) { +    atomic_store(&__xray::XRayPatchedTypedEvent,                                reinterpret_cast<uintptr_t>(entry), -                              __sanitizer::memory_order_release); +                              memory_order_release);      return 1;    }    return 0; @@ -349,6 +381,21 @@ int __xray_remove_customevent_handler() XRAY_NEVER_INSTRUMENT {    return __xray_set_customevent_handler(nullptr);  } +int __xray_remove_typedevent_handler() XRAY_NEVER_INSTRUMENT { +  return __xray_set_typedevent_handler(nullptr); +} + +uint16_t __xray_register_event_type( +    const char *const event_type) XRAY_NEVER_INSTRUMENT { +  TypeDescriptorMapType::Handle h(&TypeDescriptorAddressMap, (uptr)event_type); +  if (h.created()) { +    h->type_id = atomic_fetch_add( +        &TypeEventDescriptorCounter, 1, memory_order_acq_rel); +    h->description_string_length = strnlen(event_type, 1024); +  } +  return h->type_id; +} +  XRayPatchingStatus __xray_patch() XRAY_NEVER_INSTRUMENT {    return controlPatching(true);  } @@ -367,22 +414,22 @@ __xray_unpatch_function(int32_t FuncId) XRAY_NEVER_INSTRUMENT {  }  int __xray_set_handler_arg1(void (*entry)(int32_t, XRayEntryType, uint64_t)) { -  if (!__sanitizer::atomic_load(&XRayInitialized, -                                __sanitizer::memory_order_acquire)) +  if (!atomic_load(&XRayInitialized, +                                memory_order_acquire))      return 0;    // A relaxed write might not be visible even if the current thread gets    // scheduled on a different CPU/NUMA node.  We need to wait for everyone to    // have this handler installed for consistency of collected data across CPUs. -  __sanitizer::atomic_store(&XRayArgLogger, reinterpret_cast<uint64_t>(entry), -                            __sanitizer::memory_order_release); +  atomic_store(&XRayArgLogger, reinterpret_cast<uint64_t>(entry), +                            memory_order_release);    return 1;  }  int __xray_remove_handler_arg1() { return __xray_set_handler_arg1(nullptr); }  uintptr_t __xray_function_address(int32_t FuncId) XRAY_NEVER_INSTRUMENT { -  __sanitizer::SpinMutexLock Guard(&XRayInstrMapMutex); +  SpinMutexLock Guard(&XRayInstrMapMutex);    if (FuncId <= 0 || static_cast<size_t>(FuncId) > XRayInstrMap.Functions)      return 0;    return XRayInstrMap.SledsIndex[FuncId - 1].Begin->Function @@ -396,6 +443,6 @@ uintptr_t __xray_function_address(int32_t FuncId) XRAY_NEVER_INSTRUMENT {  }  size_t __xray_max_function_id() XRAY_NEVER_INSTRUMENT { -  __sanitizer::SpinMutexLock Guard(&XRayInstrMapMutex); +  SpinMutexLock Guard(&XRayInstrMapMutex);    return XRayInstrMap.Functions;  } diff --git a/lib/xray/xray_interface_internal.h b/lib/xray/xray_interface_internal.h index 5811e2b7300a6..8ca87457437e9 100644 --- a/lib/xray/xray_interface_internal.h +++ b/lib/xray/xray_interface_internal.h @@ -43,8 +43,8 @@ struct XRaySledEntry {  };  struct XRayFunctionSledIndex { -  const XRaySledEntry* Begin; -  const XRaySledEntry* End; +  const XRaySledEntry *Begin; +  const XRaySledEntry *End;  };  } @@ -57,12 +57,13 @@ struct XRaySledMap {    size_t Functions;  }; -bool patchFunctionEntry(bool Enable, uint32_t FuncId, -                        const XRaySledEntry &Sled, void (*Trampoline)()); +bool patchFunctionEntry(bool Enable, uint32_t FuncId, const XRaySledEntry &Sled, +                        void (*Trampoline)());  bool patchFunctionExit(bool Enable, uint32_t FuncId, const XRaySledEntry &Sled);  bool patchFunctionTailExit(bool Enable, uint32_t FuncId,                             const XRaySledEntry &Sled);  bool patchCustomEvent(bool Enable, uint32_t FuncId, const XRaySledEntry &Sled); +bool patchTypedEvent(bool Enable, uint32_t FuncId, const XRaySledEntry &Sled);  } // namespace __xray @@ -74,6 +75,7 @@ extern void __xray_FunctionExit();  extern void __xray_FunctionTailExit();  extern void __xray_ArgLoggerEntry();  extern void __xray_CustomEvent(); +extern void __xray_TypedEvent();  }  #endif diff --git a/lib/xray/xray_log_interface.cc b/lib/xray/xray_log_interface.cc index 783f004d292aa..0886fd0d12108 100644 --- a/lib/xray/xray_log_interface.cc +++ b/lib/xray/xray_log_interface.cc @@ -18,9 +18,20 @@  #include "xray/xray_interface.h"  #include "xray_defs.h" -__sanitizer::SpinMutex XRayImplMutex; -XRayLogImpl CurrentXRayImpl{nullptr, nullptr, nullptr, nullptr}; -XRayLogImpl *GlobalXRayImpl = nullptr; +namespace __xray { +static SpinMutex XRayImplMutex; +static XRayLogImpl CurrentXRayImpl{nullptr, nullptr, nullptr, nullptr}; +static XRayLogImpl *GlobalXRayImpl = nullptr; + +// This is the default implementation of a buffer iterator, which always yields +// a null buffer. +XRayBuffer NullBufferIterator(XRayBuffer) XRAY_NEVER_INSTRUMENT { +  return {nullptr, 0}; +} + +// This is the global function responsible for iterating through given buffers. +atomic_uintptr_t XRayBufferIterator{ +    reinterpret_cast<uintptr_t>(&NullBufferIterator)};  // We use a linked list of Mode to XRayLogImpl mappings. This is a linked list  // when it should be a map because we're avoiding having to depend on C++ @@ -31,9 +42,24 @@ struct ModeImpl {    XRayLogImpl Impl;  }; -ModeImpl SentinelModeImpl{ +static ModeImpl SentinelModeImpl{      nullptr, nullptr, {nullptr, nullptr, nullptr, nullptr}}; -ModeImpl *ModeImpls = &SentinelModeImpl; +static ModeImpl *ModeImpls = &SentinelModeImpl; +static const ModeImpl *CurrentMode = nullptr; + +} // namespace __xray + +using namespace __xray; + +void __xray_log_set_buffer_iterator(XRayBuffer (*Iterator)(XRayBuffer)) +    XRAY_NEVER_INSTRUMENT { +  atomic_store(&__xray::XRayBufferIterator, +               reinterpret_cast<uintptr_t>(Iterator), memory_order_release); +} + +void __xray_log_remove_buffer_iterator() XRAY_NEVER_INSTRUMENT { +  __xray_log_set_buffer_iterator(&NullBufferIterator); +}  XRayLogRegisterStatus  __xray_log_register_mode(const char *Mode, @@ -42,16 +68,15 @@ __xray_log_register_mode(const char *Mode,        Impl.log_finalize == nullptr || Impl.log_init == nullptr)      return XRayLogRegisterStatus::XRAY_INCOMPLETE_IMPL; -  __sanitizer::SpinMutexLock Guard(&XRayImplMutex); +  SpinMutexLock Guard(&XRayImplMutex);    // First, look for whether the mode already has a registered implementation.    for (ModeImpl *it = ModeImpls; it != &SentinelModeImpl; it = it->Next) { -    if (!__sanitizer::internal_strcmp(Mode, it->Mode)) +    if (!internal_strcmp(Mode, it->Mode))        return XRayLogRegisterStatus::XRAY_DUPLICATE_MODE;    } -  auto *NewModeImpl = -      static_cast<ModeImpl *>(__sanitizer::InternalAlloc(sizeof(ModeImpl))); +  auto *NewModeImpl = static_cast<ModeImpl *>(InternalAlloc(sizeof(ModeImpl)));    NewModeImpl->Next = ModeImpls; -  NewModeImpl->Mode = __sanitizer::internal_strdup(Mode); +  NewModeImpl->Mode = internal_strdup(Mode);    NewModeImpl->Impl = Impl;    ModeImpls = NewModeImpl;    return XRayLogRegisterStatus::XRAY_REGISTRATION_OK; @@ -59,9 +84,10 @@ __xray_log_register_mode(const char *Mode,  XRayLogRegisterStatus  __xray_log_select_mode(const char *Mode) XRAY_NEVER_INSTRUMENT { -  __sanitizer::SpinMutexLock Guard(&XRayImplMutex); +  SpinMutexLock Guard(&XRayImplMutex);    for (ModeImpl *it = ModeImpls; it != &SentinelModeImpl; it = it->Next) { -    if (!__sanitizer::internal_strcmp(Mode, it->Mode)) { +    if (!internal_strcmp(Mode, it->Mode)) { +      CurrentMode = it;        CurrentXRayImpl = it->Impl;        GlobalXRayImpl = &CurrentXRayImpl;        __xray_set_handler(it->Impl.handle_arg0); @@ -71,24 +97,32 @@ __xray_log_select_mode(const char *Mode) XRAY_NEVER_INSTRUMENT {    return XRayLogRegisterStatus::XRAY_MODE_NOT_FOUND;  } +const char *__xray_log_get_current_mode() XRAY_NEVER_INSTRUMENT { +  SpinMutexLock Guard(&XRayImplMutex); +  if (CurrentMode != nullptr) +    return CurrentMode->Mode; +  return nullptr; +} +  void __xray_set_log_impl(XRayLogImpl Impl) XRAY_NEVER_INSTRUMENT {    if (Impl.log_init == nullptr || Impl.log_finalize == nullptr ||        Impl.handle_arg0 == nullptr || Impl.flush_log == nullptr) { -    __sanitizer::SpinMutexLock Guard(&XRayImplMutex); +    SpinMutexLock Guard(&XRayImplMutex);      GlobalXRayImpl = nullptr; +    CurrentMode = nullptr;      __xray_remove_handler();      __xray_remove_handler_arg1();      return;    } -  __sanitizer::SpinMutexLock Guard(&XRayImplMutex); +  SpinMutexLock Guard(&XRayImplMutex);    CurrentXRayImpl = Impl;    GlobalXRayImpl = &CurrentXRayImpl;    __xray_set_handler(Impl.handle_arg0);  }  void __xray_remove_log_impl() XRAY_NEVER_INSTRUMENT { -  __sanitizer::SpinMutexLock Guard(&XRayImplMutex); +  SpinMutexLock Guard(&XRayImplMutex);    GlobalXRayImpl = nullptr;    __xray_remove_handler();    __xray_remove_handler_arg1(); @@ -97,22 +131,80 @@ void __xray_remove_log_impl() XRAY_NEVER_INSTRUMENT {  XRayLogInitStatus __xray_log_init(size_t BufferSize, size_t MaxBuffers,                                    void *Args,                                    size_t ArgsSize) XRAY_NEVER_INSTRUMENT { -  __sanitizer::SpinMutexLock Guard(&XRayImplMutex); +  SpinMutexLock Guard(&XRayImplMutex);    if (!GlobalXRayImpl)      return XRayLogInitStatus::XRAY_LOG_UNINITIALIZED;    return GlobalXRayImpl->log_init(BufferSize, MaxBuffers, Args, ArgsSize);  } +XRayLogInitStatus __xray_log_init_mode(const char *Mode, const char *Config) +    XRAY_NEVER_INSTRUMENT { +  SpinMutexLock Guard(&XRayImplMutex); +  if (!GlobalXRayImpl) +    return XRayLogInitStatus::XRAY_LOG_UNINITIALIZED; + +  if (Config == nullptr) +    return XRayLogInitStatus::XRAY_LOG_UNINITIALIZED; + +  // Check first whether the current mode is the same as what we expect. +  if (CurrentMode == nullptr || internal_strcmp(CurrentMode->Mode, Mode) != 0) +    return XRayLogInitStatus::XRAY_LOG_UNINITIALIZED; + +  // Here we do some work to coerce the pointer we're provided, so that +  // the implementations that still take void* pointers can handle the +  // data provided in the Config argument. +  return GlobalXRayImpl->log_init( +      0, 0, const_cast<void *>(static_cast<const void *>(Config)), 0); +} + +XRayLogInitStatus +__xray_log_init_mode_bin(const char *Mode, const char *Config, +                         size_t ConfigSize) XRAY_NEVER_INSTRUMENT { +  SpinMutexLock Guard(&XRayImplMutex); +  if (!GlobalXRayImpl) +    return XRayLogInitStatus::XRAY_LOG_UNINITIALIZED; + +  if (Config == nullptr) +    return XRayLogInitStatus::XRAY_LOG_UNINITIALIZED; + +  // Check first whether the current mode is the same as what we expect. +  if (CurrentMode == nullptr || internal_strcmp(CurrentMode->Mode, Mode) != 0) +    return XRayLogInitStatus::XRAY_LOG_UNINITIALIZED; + +  // Here we do some work to coerce the pointer we're provided, so that +  // the implementations that still take void* pointers can handle the +  // data provided in the Config argument. +  return GlobalXRayImpl->log_init( +      0, 0, const_cast<void *>(static_cast<const void *>(Config)), ConfigSize); +} +  XRayLogInitStatus __xray_log_finalize() XRAY_NEVER_INSTRUMENT { -  __sanitizer::SpinMutexLock Guard(&XRayImplMutex); +  SpinMutexLock Guard(&XRayImplMutex);    if (!GlobalXRayImpl)      return XRayLogInitStatus::XRAY_LOG_UNINITIALIZED;    return GlobalXRayImpl->log_finalize();  }  XRayLogFlushStatus __xray_log_flushLog() XRAY_NEVER_INSTRUMENT { -  __sanitizer::SpinMutexLock Guard(&XRayImplMutex); +  SpinMutexLock Guard(&XRayImplMutex);    if (!GlobalXRayImpl)      return XRayLogFlushStatus::XRAY_LOG_NOT_FLUSHING;    return GlobalXRayImpl->flush_log();  } + +XRayLogFlushStatus __xray_log_process_buffers( +    void (*Processor)(const char *, XRayBuffer)) XRAY_NEVER_INSTRUMENT { +  // We want to make sure that there will be no changes to the global state for +  // the log by synchronising on the XRayBufferIteratorMutex. +  if (!GlobalXRayImpl) +    return XRayLogFlushStatus::XRAY_LOG_NOT_FLUSHING; +  auto Iterator = reinterpret_cast<XRayBuffer (*)(XRayBuffer)>( +      atomic_load(&XRayBufferIterator, memory_order_acquire)); +  auto Buffer = (*Iterator)(XRayBuffer{nullptr, 0}); +  auto Mode = CurrentMode ? CurrentMode->Mode : nullptr; +  while (Buffer.Data != nullptr) { +    (*Processor)(Mode, Buffer); +    Buffer = (*Iterator)(Buffer); +  } +  return XRayLogFlushStatus::XRAY_LOG_FLUSHED; +} diff --git a/lib/xray/xray_mips.cc b/lib/xray/xray_mips.cc index cd863304db294..6f82438286689 100644 --- a/lib/xray/xray_mips.cc +++ b/lib/xray/xray_mips.cc @@ -158,6 +158,12 @@ bool patchCustomEvent(const bool Enable, const uint32_t FuncId,    return false;  } +bool patchTypedEvent(const bool Enable, const uint32_t FuncId, +                     const XRaySledEntry &Sled) XRAY_NEVER_INSTRUMENT { +  // FIXME: Implement in mips? +  return false; +} +  } // namespace __xray  extern "C" void __xray_ArgLoggerEntry() XRAY_NEVER_INSTRUMENT { diff --git a/lib/xray/xray_mips64.cc b/lib/xray/xray_mips64.cc index fa8fdd5abccc3..f1bdf1d7d22d0 100644 --- a/lib/xray/xray_mips64.cc +++ b/lib/xray/xray_mips64.cc @@ -166,6 +166,12 @@ bool patchCustomEvent(const bool Enable, const uint32_t FuncId,    // FIXME: Implement in mips64?    return false;  } + +bool patchTypedEvent(const bool Enable, const uint32_t FuncId, +                     const XRaySledEntry &Sled) XRAY_NEVER_INSTRUMENT { +  // FIXME: Implement in mips64? +  return false; +}  } // namespace __xray  extern "C" void __xray_ArgLoggerEntry() XRAY_NEVER_INSTRUMENT { diff --git a/lib/xray/xray_powerpc64.cc b/lib/xray/xray_powerpc64.cc index ab03cb10042ff..5e4938361c0c3 100644 --- a/lib/xray/xray_powerpc64.cc +++ b/lib/xray/xray_powerpc64.cc @@ -99,6 +99,12 @@ bool patchCustomEvent(const bool Enable, const uint32_t FuncId,    return false;  } +bool patchTypedEvent(const bool Enable, const uint32_t FuncId, +                     const XRaySledEntry &Sled) XRAY_NEVER_INSTRUMENT { +  // FIXME: Implement in powerpc64? +  return false; +} +  } // namespace __xray  extern "C" void __xray_ArgLoggerEntry() XRAY_NEVER_INSTRUMENT { diff --git a/lib/xray/xray_profile_collector.cc b/lib/xray/xray_profile_collector.cc new file mode 100644 index 0000000000000..a43744d9a0cb2 --- /dev/null +++ b/lib/xray/xray_profile_collector.cc @@ -0,0 +1,318 @@ +//===-- xray_profile_collector.cc ------------------------------*- C++ -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of XRay, a dynamic runtime instrumentation system. +// +// This implements the interface for the profileCollectorService. +// +//===----------------------------------------------------------------------===// +#include "xray_profile_collector.h" +#include "sanitizer_common/sanitizer_allocator_internal.h" +#include "sanitizer_common/sanitizer_common.h" +#include "sanitizer_common/sanitizer_vector.h" +#include "xray_profiling_flags.h" +#include <memory> +#include <pthread.h> +#include <utility> + +namespace __xray { +namespace profileCollectorService { + +namespace { + +SpinMutex GlobalMutex; +struct ThreadTrie { +  tid_t TId; +  FunctionCallTrie *Trie; +}; + +struct ProfileBuffer { +  void *Data; +  size_t Size; +}; + +struct BlockHeader { +  u32 BlockSize; +  u32 BlockNum; +  u64 ThreadId; +}; + +// These need to be pointers that point to heap/internal-allocator-allocated +// objects because these are accessed even at program exit. +Vector<ThreadTrie> *ThreadTries = nullptr; +Vector<ProfileBuffer> *ProfileBuffers = nullptr; +FunctionCallTrie::Allocators *GlobalAllocators = nullptr; + +} // namespace + +void post(const FunctionCallTrie &T, tid_t TId) { +  static pthread_once_t Once = PTHREAD_ONCE_INIT; +  pthread_once(&Once, +[] { +    SpinMutexLock Lock(&GlobalMutex); +    GlobalAllocators = reinterpret_cast<FunctionCallTrie::Allocators *>( +        InternalAlloc(sizeof(FunctionCallTrie::Allocators))); +    new (GlobalAllocators) FunctionCallTrie::Allocators(); +    *GlobalAllocators = FunctionCallTrie::InitAllocatorsCustom( +        profilingFlags()->global_allocator_max); +    ThreadTries = reinterpret_cast<Vector<ThreadTrie> *>( +        InternalAlloc(sizeof(Vector<ThreadTrie>))); +    new (ThreadTries) Vector<ThreadTrie>(); +    ProfileBuffers = reinterpret_cast<Vector<ProfileBuffer> *>( +        InternalAlloc(sizeof(Vector<ProfileBuffer>))); +    new (ProfileBuffers) Vector<ProfileBuffer>(); +  }); +  DCHECK_NE(GlobalAllocators, nullptr); +  DCHECK_NE(ThreadTries, nullptr); +  DCHECK_NE(ProfileBuffers, nullptr); + +  ThreadTrie *Item = nullptr; +  { +    SpinMutexLock Lock(&GlobalMutex); +    if (GlobalAllocators == nullptr) +      return; + +    Item = ThreadTries->PushBack(); +    Item->TId = TId; + +    // Here we're using the internal allocator instead of the managed allocator +    // because: +    // +    // 1) We're not using the segmented array data structure to host +    //    FunctionCallTrie objects. We're using a Vector (from sanitizer_common) +    //    which works like a std::vector<...> keeping elements contiguous in +    //    memory. The segmented array data structure assumes that elements are +    //    trivially destructible, where FunctionCallTrie isn't. +    // +    // 2) Using a managed allocator means we need to manage that separately, +    //    which complicates the nature of this code. To get around that, we're +    //    using the internal allocator instead, which has its own global state +    //    and is decoupled from the lifetime management required by the managed +    //    allocator we have in XRay. +    // +    Item->Trie = reinterpret_cast<FunctionCallTrie *>(InternalAlloc( +        sizeof(FunctionCallTrie), nullptr, alignof(FunctionCallTrie))); +    DCHECK_NE(Item->Trie, nullptr); +    new (Item->Trie) FunctionCallTrie(*GlobalAllocators); +  } + +  T.deepCopyInto(*Item->Trie); +} + +// A PathArray represents the function id's representing a stack trace. In this +// context a path is almost always represented from the leaf function in a call +// stack to a root of the call trie. +using PathArray = Array<int32_t>; + +struct ProfileRecord { +  using PathAllocator = typename PathArray::AllocatorType; + +  // The Path in this record is the function id's from the leaf to the root of +  // the function call stack as represented from a FunctionCallTrie. +  PathArray *Path = nullptr; +  const FunctionCallTrie::Node *Node = nullptr; + +  // Constructor for in-place construction. +  ProfileRecord(PathAllocator &A, const FunctionCallTrie::Node *N) +      : Path([&] { +          auto P = +              reinterpret_cast<PathArray *>(InternalAlloc(sizeof(PathArray))); +          new (P) PathArray(A); +          return P; +        }()), +        Node(N) {} +}; + +namespace { + +using ProfileRecordArray = Array<ProfileRecord>; + +// Walk a depth-first traversal of each root of the FunctionCallTrie to generate +// the path(s) and the data associated with the path. +static void populateRecords(ProfileRecordArray &PRs, +                            ProfileRecord::PathAllocator &PA, +                            const FunctionCallTrie &Trie) { +  using StackArray = Array<const FunctionCallTrie::Node *>; +  using StackAllocator = typename StackArray::AllocatorType; +  StackAllocator StackAlloc(profilingFlags()->stack_allocator_max); +  StackArray DFSStack(StackAlloc); +  for (const auto R : Trie.getRoots()) { +    DFSStack.Append(R); +    while (!DFSStack.empty()) { +      auto Node = DFSStack.back(); +      DFSStack.trim(1); +      auto Record = PRs.AppendEmplace(PA, Node); +      if (Record == nullptr) +        return; +      DCHECK_NE(Record, nullptr); + +      // Traverse the Node's parents and as we're doing so, get the FIds in +      // the order they appear. +      for (auto N = Node; N != nullptr; N = N->Parent) +        Record->Path->Append(N->FId); +      DCHECK(!Record->Path->empty()); + +      for (const auto C : Node->Callees) +        DFSStack.Append(C.NodePtr); +    } +  } +} + +static void serializeRecords(ProfileBuffer *Buffer, const BlockHeader &Header, +                             const ProfileRecordArray &ProfileRecords) { +  auto NextPtr = static_cast<char *>( +                     internal_memcpy(Buffer->Data, &Header, sizeof(Header))) + +                 sizeof(Header); +  for (const auto &Record : ProfileRecords) { +    // List of IDs follow: +    for (const auto FId : *Record.Path) +      NextPtr = +          static_cast<char *>(internal_memcpy(NextPtr, &FId, sizeof(FId))) + +          sizeof(FId); + +    // Add the sentinel here. +    constexpr int32_t SentinelFId = 0; +    NextPtr = static_cast<char *>( +                  internal_memset(NextPtr, SentinelFId, sizeof(SentinelFId))) + +              sizeof(SentinelFId); + +    // Add the node data here. +    NextPtr = +        static_cast<char *>(internal_memcpy(NextPtr, &Record.Node->CallCount, +                                            sizeof(Record.Node->CallCount))) + +        sizeof(Record.Node->CallCount); +    NextPtr = static_cast<char *>( +                  internal_memcpy(NextPtr, &Record.Node->CumulativeLocalTime, +                                  sizeof(Record.Node->CumulativeLocalTime))) + +              sizeof(Record.Node->CumulativeLocalTime); +  } + +  DCHECK_EQ(NextPtr - static_cast<char *>(Buffer->Data), Buffer->Size); +} + +} // namespace + +void serialize() { +  SpinMutexLock Lock(&GlobalMutex); + +  // Clear out the global ProfileBuffers. +  for (uptr I = 0; I < ProfileBuffers->Size(); ++I) +    InternalFree((*ProfileBuffers)[I].Data); +  ProfileBuffers->Reset(); + +  if (ThreadTries->Size() == 0) +    return; + +  // Then repopulate the global ProfileBuffers. +  for (u32 I = 0; I < ThreadTries->Size(); ++I) { +    using ProfileRecordAllocator = typename ProfileRecordArray::AllocatorType; +    ProfileRecordAllocator PRAlloc(profilingFlags()->global_allocator_max); +    ProfileRecord::PathAllocator PathAlloc( +        profilingFlags()->global_allocator_max); +    ProfileRecordArray ProfileRecords(PRAlloc); + +    // First, we want to compute the amount of space we're going to need. We'll +    // use a local allocator and an __xray::Array<...> to store the intermediary +    // data, then compute the size as we're going along. Then we'll allocate the +    // contiguous space to contain the thread buffer data. +    const auto &Trie = *(*ThreadTries)[I].Trie; +    if (Trie.getRoots().empty()) +      continue; +    populateRecords(ProfileRecords, PathAlloc, Trie); +    DCHECK(!Trie.getRoots().empty()); +    DCHECK(!ProfileRecords.empty()); + +    // Go through each record, to compute the sizes. +    // +    // header size = block size (4 bytes) +    //   + block number (4 bytes) +    //   + thread id (8 bytes) +    // record size = path ids (4 bytes * number of ids + sentinel 4 bytes) +    //   + call count (8 bytes) +    //   + local time (8 bytes) +    //   + end of record (8 bytes) +    u32 CumulativeSizes = 0; +    for (const auto &Record : ProfileRecords) +      CumulativeSizes += 20 + (4 * Record.Path->size()); + +    BlockHeader Header{16 + CumulativeSizes, I, (*ThreadTries)[I].TId}; +    auto Buffer = ProfileBuffers->PushBack(); +    Buffer->Size = sizeof(Header) + CumulativeSizes; +    Buffer->Data = InternalAlloc(Buffer->Size, nullptr, 64); +    DCHECK_NE(Buffer->Data, nullptr); +    serializeRecords(Buffer, Header, ProfileRecords); + +    // Now clean up the ProfileRecords array, one at a time. +    for (auto &Record : ProfileRecords) { +      Record.Path->~PathArray(); +      InternalFree(Record.Path); +    } +  } +} + +void reset() { +  SpinMutexLock Lock(&GlobalMutex); +  if (ProfileBuffers != nullptr) { +    // Clear out the profile buffers that have been serialized. +    for (uptr I = 0; I < ProfileBuffers->Size(); ++I) +      InternalFree((*ProfileBuffers)[I].Data); +    ProfileBuffers->Reset(); +    InternalFree(ProfileBuffers); +    ProfileBuffers = nullptr; +  } + +  if (ThreadTries != nullptr) { +    // Clear out the function call tries per thread. +    for (uptr I = 0; I < ThreadTries->Size(); ++I) { +      auto &T = (*ThreadTries)[I]; +      T.Trie->~FunctionCallTrie(); +      InternalFree(T.Trie); +    } +    ThreadTries->Reset(); +    InternalFree(ThreadTries); +    ThreadTries = nullptr; +  } + +  // Reset the global allocators. +  if (GlobalAllocators != nullptr) { +    GlobalAllocators->~Allocators(); +    InternalFree(GlobalAllocators); +    GlobalAllocators = nullptr; +  } +  GlobalAllocators = reinterpret_cast<FunctionCallTrie::Allocators *>( +      InternalAlloc(sizeof(FunctionCallTrie::Allocators))); +  new (GlobalAllocators) FunctionCallTrie::Allocators(); +  *GlobalAllocators = FunctionCallTrie::InitAllocators(); +  ThreadTries = reinterpret_cast<Vector<ThreadTrie> *>( +      InternalAlloc(sizeof(Vector<ThreadTrie>))); +  new (ThreadTries) Vector<ThreadTrie>(); +  ProfileBuffers = reinterpret_cast<Vector<ProfileBuffer> *>( +      InternalAlloc(sizeof(Vector<ProfileBuffer>))); +  new (ProfileBuffers) Vector<ProfileBuffer>(); +} + +XRayBuffer nextBuffer(XRayBuffer B) { +  SpinMutexLock Lock(&GlobalMutex); + +  if (ProfileBuffers == nullptr || ProfileBuffers->Size() == 0) +    return {nullptr, 0}; + +  if (B.Data == nullptr) +    return {(*ProfileBuffers)[0].Data, (*ProfileBuffers)[0].Size}; + +  BlockHeader Header; +  internal_memcpy(&Header, B.Data, sizeof(BlockHeader)); +  auto NextBlock = Header.BlockNum + 1; +  if (NextBlock < ProfileBuffers->Size()) +    return {(*ProfileBuffers)[NextBlock].Data, +            (*ProfileBuffers)[NextBlock].Size}; +  return {nullptr, 0}; +} + +} // namespace profileCollectorService +} // namespace __xray diff --git a/lib/xray/xray_profile_collector.h b/lib/xray/xray_profile_collector.h new file mode 100644 index 0000000000000..335043db95265 --- /dev/null +++ b/lib/xray/xray_profile_collector.h @@ -0,0 +1,88 @@ +//===-- xray_profile_collector.h -------------------------------*- C++ -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of XRay, a dynamic runtime instrumentation system. +// +// This file defines the interface for a data collection service, for XRay +// profiling. What we implement here is an in-process service where +// FunctionCallTrie instances can be handed off by threads, to be +// consolidated/collected. +// +//===----------------------------------------------------------------------===// +#ifndef XRAY_XRAY_PROFILE_COLLECTOR_H +#define XRAY_XRAY_PROFILE_COLLECTOR_H + +#include "xray_function_call_trie.h" + +#include "xray/xray_log_interface.h" + +namespace __xray { + +/// The ProfileCollectorService implements a centralised mechanism for +/// collecting FunctionCallTrie instances, indexed by thread ID. On demand, the +/// ProfileCollectorService can be queried for the most recent state of the +/// data, in a form that allows traversal. +namespace profileCollectorService { + +/// Posts the FunctionCallTrie associated with a specific Thread ID. This +/// will: +/// +///   - Make a copy of the FunctionCallTrie and store that against the Thread +///     ID. This will use the global allocator for the service-managed +///     FunctionCallTrie instances. +///   - Queue up a pointer to the FunctionCallTrie. +///   - If the queue is long enough (longer than some arbitrary threshold) we +///     then pre-calculate a single FunctionCallTrie for the whole process. +/// +/// +/// We are making a copy of the FunctionCallTrie because the intent is to have +/// this function be called at thread exit, or soon after the profiling +/// handler is finalized through the XRay APIs. By letting threads each +/// process their own thread-local FunctionCallTrie instances, we're removing +/// the need for synchronisation across threads while we're profiling. +/// However, once we're done profiling, we can then collect copies of these +/// FunctionCallTrie instances and pay the cost of the copy. +/// +/// NOTE: In the future, if this turns out to be more costly than "moving" the +/// FunctionCallTrie instances from the owning thread to the collector +/// service, then we can change the implementation to do it this way (moving) +/// instead. +void post(const FunctionCallTrie &T, tid_t TId); + +/// The serialize will process all FunctionCallTrie instances in memory, and +/// turn those into specifically formatted blocks, each describing the +/// function call trie's contents in a compact form. In memory, this looks +/// like the following layout: +/// +///   - block size (32 bits) +///   - block number (32 bits) +///   - thread id (64 bits) +///   - list of records: +///     - function ids in leaf to root order, terminated by +///       0 (32 bits per function id) +///     - call count (64 bit) +///     - cumulative local time (64 bit) +///     - record delimiter (64 bit, 0x0) +/// +void serialize(); + +/// The reset function will clear out any internal memory held by the +/// service. The intent is to have the resetting be done in calls to the +/// initialization routine, or explicitly through the flush log API. +void reset(); + +/// This nextBuffer function is meant to implement the iterator functionality, +/// provided in the XRay API. +XRayBuffer nextBuffer(XRayBuffer B); + +} // namespace profileCollectorService + +} // namespace __xray + +#endif // XRAY_XRAY_PROFILE_COLLECTOR_H diff --git a/lib/xray/xray_profiling.cc b/lib/xray/xray_profiling.cc new file mode 100644 index 0000000000000..786084c772268 --- /dev/null +++ b/lib/xray/xray_profiling.cc @@ -0,0 +1,372 @@ +//===-- xray_profiling.cc ---------------------------------------*- C++ -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of XRay, a dynamic runtime instrumentation system. +// +// This is the implementation of a profiling handler. +// +//===----------------------------------------------------------------------===// +#include <memory> +#include <time.h> + +#include "sanitizer_common/sanitizer_atomic.h" +#include "sanitizer_common/sanitizer_flags.h" +#include "xray/xray_interface.h" +#include "xray/xray_log_interface.h" + +#include "xray_flags.h" +#include "xray_profile_collector.h" +#include "xray_profiling_flags.h" +#include "xray_recursion_guard.h" +#include "xray_tsc.h" +#include "xray_utils.h" +#include <pthread.h> + +namespace __xray { + +namespace { + +constexpr uptr XRayProfilingVersion = 0x20180424; + +struct XRayProfilingFileHeader { +  const u64 MagicBytes = 0x7872617970726f66; // Identifier for XRay profiling +                                             // files 'xrayprof' in hex. +  const uptr Version = XRayProfilingVersion; +  uptr Timestamp = 0; // System time in nanoseconds. +  uptr PID = 0;       // Process ID. +}; + +atomic_sint32_t ProfilerLogFlushStatus = { +    XRayLogFlushStatus::XRAY_LOG_NOT_FLUSHING}; + +atomic_sint32_t ProfilerLogStatus = {XRayLogInitStatus::XRAY_LOG_UNINITIALIZED}; + +SpinMutex ProfilerOptionsMutex; + +struct alignas(64) ProfilingData { +  FunctionCallTrie::Allocators *Allocators = nullptr; +  FunctionCallTrie *FCT = nullptr; +}; + +static pthread_key_t ProfilingKey; + +thread_local std::aligned_storage<sizeof(ProfilingData)>::type ThreadStorage{}; +static ProfilingData &getThreadLocalData() XRAY_NEVER_INSTRUMENT { +  thread_local auto ThreadOnce = [] { +    new (&ThreadStorage) ProfilingData{}; +    pthread_setspecific(ProfilingKey, &ThreadStorage); +    return false; +  }(); +  (void)ThreadOnce; + +  auto &TLD = *reinterpret_cast<ProfilingData *>(&ThreadStorage); + +  // We need to check whether the global flag to finalizing/finalized has been +  // switched. If it is, then we ought to not actually initialise the data. +  auto Status = atomic_load(&ProfilerLogStatus, memory_order_acquire); +  if (Status == XRayLogInitStatus::XRAY_LOG_FINALIZING || +      Status == XRayLogInitStatus::XRAY_LOG_FINALIZED) +    return TLD; + +  // If we're live, then we re-initialize TLD if the pointers are not null. +  if (UNLIKELY(TLD.Allocators == nullptr && TLD.FCT == nullptr)) { +    TLD.Allocators = reinterpret_cast<FunctionCallTrie::Allocators *>( +        InternalAlloc(sizeof(FunctionCallTrie::Allocators))); +    new (TLD.Allocators) FunctionCallTrie::Allocators(); +    *TLD.Allocators = FunctionCallTrie::InitAllocators(); +    TLD.FCT = reinterpret_cast<FunctionCallTrie *>( +        InternalAlloc(sizeof(FunctionCallTrie))); +    new (TLD.FCT) FunctionCallTrie(*TLD.Allocators); +  } + +  return TLD; +} + +static void cleanupTLD() XRAY_NEVER_INSTRUMENT { +  auto &TLD = *reinterpret_cast<ProfilingData *>(&ThreadStorage); +  if (TLD.Allocators != nullptr && TLD.FCT != nullptr) { +    TLD.FCT->~FunctionCallTrie(); +    TLD.Allocators->~Allocators(); +    InternalFree(TLD.FCT); +    InternalFree(TLD.Allocators); +    TLD.FCT = nullptr; +    TLD.Allocators = nullptr; +  } +} + +} // namespace + +const char *profilingCompilerDefinedFlags() XRAY_NEVER_INSTRUMENT { +#ifdef XRAY_PROFILER_DEFAULT_OPTIONS +  return SANITIZER_STRINGIFY(XRAY_PROFILER_DEFAULT_OPTIONS); +#else +  return ""; +#endif +} + +atomic_sint32_t ProfileFlushStatus = { +    XRayLogFlushStatus::XRAY_LOG_NOT_FLUSHING}; + +XRayLogFlushStatus profilingFlush() XRAY_NEVER_INSTRUMENT { +  if (atomic_load(&ProfilerLogStatus, memory_order_acquire) != +      XRayLogInitStatus::XRAY_LOG_FINALIZED) { +    if (Verbosity()) +      Report("Not flushing profiles, profiling not been finalized.\n"); +    return XRayLogFlushStatus::XRAY_LOG_NOT_FLUSHING; +  } + +  s32 Result = XRayLogFlushStatus::XRAY_LOG_NOT_FLUSHING; +  if (!atomic_compare_exchange_strong(&ProfilerLogFlushStatus, &Result, +                                      XRayLogFlushStatus::XRAY_LOG_FLUSHING, +                                      memory_order_acq_rel)) { +    if (Verbosity()) +      Report("Not flushing profiles, implementation still finalizing.\n"); +  } + +  // At this point, we'll create the file that will contain the profile, but +  // only if the options say so. +  if (!profilingFlags()->no_flush) { +    // First check whether we have data in the profile collector service +    // before we try and write anything down. +    XRayBuffer B = profileCollectorService::nextBuffer({nullptr, 0}); +    if (B.Data == nullptr) { +      if (Verbosity()) +        Report("profiling: No data to flush.\n"); +    } else { +      int Fd = getLogFD(); +      if (Fd == -1) { +        if (Verbosity()) +          Report("profiling: Failed to flush to file, dropping data.\n"); +      } else { +        XRayProfilingFileHeader Header; +        Header.Timestamp = NanoTime(); +        Header.PID = internal_getpid(); +        retryingWriteAll(Fd, reinterpret_cast<const char *>(&Header), +                         reinterpret_cast<const char *>(&Header) + +                             sizeof(Header)); + +        // Now for each of the threads, write out the profile data as we would +        // see it in memory, verbatim. +        while (B.Data != nullptr && B.Size != 0) { +          retryingWriteAll(Fd, reinterpret_cast<const char *>(B.Data), +                           reinterpret_cast<const char *>(B.Data) + B.Size); +          B = profileCollectorService::nextBuffer(B); +        } +        // Then we close out the file. +        internal_close(Fd); +      } +    } +  } + +  profileCollectorService::reset(); + +  // Flush the current thread's local data structures as well. +  cleanupTLD(); + +  atomic_store(&ProfilerLogStatus, XRayLogFlushStatus::XRAY_LOG_FLUSHED, +               memory_order_release); + +  return XRayLogFlushStatus::XRAY_LOG_FLUSHED; +} + +namespace { + +thread_local atomic_uint8_t ReentranceGuard{0}; + +static void postCurrentThreadFCT(ProfilingData &TLD) { +  if (TLD.Allocators == nullptr || TLD.FCT == nullptr) +    return; + +  profileCollectorService::post(*TLD.FCT, GetTid()); +  cleanupTLD(); +} + +} // namespace + +void profilingHandleArg0(int32_t FuncId, +                         XRayEntryType Entry) XRAY_NEVER_INSTRUMENT { +  unsigned char CPU; +  auto TSC = readTSC(CPU); +  RecursionGuard G(ReentranceGuard); +  if (!G) +    return; + +  auto Status = atomic_load(&ProfilerLogStatus, memory_order_acquire); +  auto &TLD = getThreadLocalData(); +  if (UNLIKELY(Status == XRayLogInitStatus::XRAY_LOG_FINALIZED || +               Status == XRayLogInitStatus::XRAY_LOG_FINALIZING)) { +    postCurrentThreadFCT(TLD); +    return; +  } + +  switch (Entry) { +  case XRayEntryType::ENTRY: +  case XRayEntryType::LOG_ARGS_ENTRY: +    TLD.FCT->enterFunction(FuncId, TSC); +    break; +  case XRayEntryType::EXIT: +  case XRayEntryType::TAIL: +    TLD.FCT->exitFunction(FuncId, TSC); +    break; +  default: +    // FIXME: Handle bugs. +    break; +  } +} + +void profilingHandleArg1(int32_t FuncId, XRayEntryType Entry, +                         uint64_t) XRAY_NEVER_INSTRUMENT { +  return profilingHandleArg0(FuncId, Entry); +} + +XRayLogInitStatus profilingFinalize() XRAY_NEVER_INSTRUMENT { +  s32 CurrentStatus = XRayLogInitStatus::XRAY_LOG_INITIALIZED; +  if (!atomic_compare_exchange_strong(&ProfilerLogStatus, &CurrentStatus, +                                      XRayLogInitStatus::XRAY_LOG_FINALIZING, +                                      memory_order_release)) { +    if (Verbosity()) +      Report("Cannot finalize profile, the profiling is not initialized.\n"); +    return static_cast<XRayLogInitStatus>(CurrentStatus); +  } + +  // Wait a grace period to allow threads to see that we're finalizing. +  SleepForMillis(profilingFlags()->grace_period_ms); + +  // We also want to make sure that the current thread's data is cleaned up, +  // if we have any. +  auto &TLD = getThreadLocalData(); +  postCurrentThreadFCT(TLD); + +  // Then we force serialize the log data. +  profileCollectorService::serialize(); + +  atomic_store(&ProfilerLogStatus, XRayLogInitStatus::XRAY_LOG_FINALIZED, +               memory_order_release); +  return XRayLogInitStatus::XRAY_LOG_FINALIZED; +} + +XRayLogInitStatus +profilingLoggingInit(size_t BufferSize, size_t BufferMax, void *Options, +                     size_t OptionsSize) XRAY_NEVER_INSTRUMENT { +  if (BufferSize != 0 || BufferMax != 0) { +    if (Verbosity()) +      Report("__xray_log_init() being used, and is unsupported. Use " +             "__xray_log_init_mode(...) instead. Bailing out."); +    return XRayLogInitStatus::XRAY_LOG_UNINITIALIZED; +  } + +  s32 CurrentStatus = XRayLogInitStatus::XRAY_LOG_UNINITIALIZED; +  if (!atomic_compare_exchange_strong(&ProfilerLogStatus, &CurrentStatus, +                                      XRayLogInitStatus::XRAY_LOG_INITIALIZING, +                                      memory_order_release)) { +    if (Verbosity()) +      Report("Cannot initialize already initialised profiling " +             "implementation.\n"); +    return static_cast<XRayLogInitStatus>(CurrentStatus); +  } + +  { +    SpinMutexLock Lock(&ProfilerOptionsMutex); +    FlagParser ConfigParser; +    ProfilerFlags Flags; +    Flags.setDefaults(); +    registerProfilerFlags(&ConfigParser, &Flags); +    ConfigParser.ParseString(profilingCompilerDefinedFlags()); +    const char *Env = GetEnv("XRAY_PROFILING_OPTIONS"); +    if (Env == nullptr) +      Env = ""; +    ConfigParser.ParseString(Env); + +    // Then parse the configuration string provided. +    ConfigParser.ParseString(static_cast<const char *>(Options)); +    if (Verbosity()) +      ReportUnrecognizedFlags(); +    *profilingFlags() = Flags; +  } + +  // We need to reset the profile data collection implementation now. +  profileCollectorService::reset(); + +  // We need to set up the exit handlers. +  static pthread_once_t Once = PTHREAD_ONCE_INIT; +  pthread_once(&Once, +[] { +    pthread_key_create(&ProfilingKey, +[](void *P) { +      // This is the thread-exit handler. +      auto &TLD = *reinterpret_cast<ProfilingData *>(P); +      if (TLD.Allocators == nullptr && TLD.FCT == nullptr) +        return; + +      postCurrentThreadFCT(TLD); +    }); + +    // We also need to set up an exit handler, so that we can get the profile +    // information at exit time. We use the C API to do this, to not rely on C++ +    // ABI functions for registering exit handlers. +    Atexit(+[] { +      // Finalize and flush. +      if (profilingFinalize() != XRAY_LOG_FINALIZED) { +        cleanupTLD(); +        return; +      } +      if (profilingFlush() != XRAY_LOG_FLUSHED) { +        cleanupTLD(); +        return; +      } +      if (Verbosity()) +        Report("XRay Profile flushed at exit."); +    }); +  }); + +  __xray_log_set_buffer_iterator(profileCollectorService::nextBuffer); +  __xray_set_handler(profilingHandleArg0); +  __xray_set_handler_arg1(profilingHandleArg1); + +  atomic_store(&ProfilerLogStatus, XRayLogInitStatus::XRAY_LOG_INITIALIZED, +               memory_order_release); +  if (Verbosity()) +    Report("XRay Profiling init successful.\n"); + +  return XRayLogInitStatus::XRAY_LOG_INITIALIZED; +} + +bool profilingDynamicInitializer() XRAY_NEVER_INSTRUMENT { +  // Set up the flag defaults from the static defaults and the +  // compiler-provided defaults. +  { +    SpinMutexLock Lock(&ProfilerOptionsMutex); +    auto *F = profilingFlags(); +    F->setDefaults(); +    FlagParser ProfilingParser; +    registerProfilerFlags(&ProfilingParser, F); +    ProfilingParser.ParseString(profilingCompilerDefinedFlags()); +  } + +  XRayLogImpl Impl{ +      profilingLoggingInit, +      profilingFinalize, +      profilingHandleArg0, +      profilingFlush, +  }; +  auto RegistrationResult = __xray_log_register_mode("xray-profiling", Impl); +  if (RegistrationResult != XRayLogRegisterStatus::XRAY_REGISTRATION_OK) { +    if (Verbosity()) +      Report("Cannot register XRay Profiling mode to 'xray-profiling'; error = " +             "%d\n", +             RegistrationResult); +    return false; +  } + +  if (!internal_strcmp(flags()->xray_mode, "xray-profiling")) +    __xray_log_select_mode("xray_profiling"); +  return true; +} + +} // namespace __xray + +static auto UNUSED Unused = __xray::profilingDynamicInitializer(); diff --git a/lib/xray/xray_profiling_flags.cc b/lib/xray/xray_profiling_flags.cc new file mode 100644 index 0000000000000..593e66a78ad2d --- /dev/null +++ b/lib/xray/xray_profiling_flags.cc @@ -0,0 +1,40 @@ +//===-- xray_flags.h -------------------------------------------*- C++ -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of XRay, a dynamic runtime instrumentation system. +// +// XRay runtime flags. +//===----------------------------------------------------------------------===// + +#include "xray_profiling_flags.h" +#include "sanitizer_common/sanitizer_common.h" +#include "sanitizer_common/sanitizer_flag_parser.h" +#include "sanitizer_common/sanitizer_libc.h" +#include "xray_defs.h" + +namespace __xray { + +// Storage for the profiling flags. +ProfilerFlags xray_profiling_flags_dont_use_directly; + +void ProfilerFlags::setDefaults() XRAY_NEVER_INSTRUMENT { +#define XRAY_FLAG(Type, Name, DefaultValue, Description) Name = DefaultValue; +#include "xray_profiling_flags.inc" +#undef XRAY_FLAG +} + +void registerProfilerFlags(FlagParser *P, +                           ProfilerFlags *F) XRAY_NEVER_INSTRUMENT { +#define XRAY_FLAG(Type, Name, DefaultValue, Description)                       \ +  RegisterFlag(P, #Name, Description, &F->Name); +#include "xray_profiling_flags.inc" +#undef XRAY_FLAG +} + +} // namespace __xray diff --git a/lib/xray/xray_profiling_flags.h b/lib/xray/xray_profiling_flags.h new file mode 100644 index 0000000000000..2f9a7514799a6 --- /dev/null +++ b/lib/xray/xray_profiling_flags.h @@ -0,0 +1,39 @@ +//===-- xray_profiling_flags.h ----------------------------------*- C++ -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of XRay, a dynamic runtime instrumentation system. +// +// XRay profiling runtime flags. +//===----------------------------------------------------------------------===// + +#ifndef XRAY_PROFILER_FLAGS_H +#define XRAY_PROFILER_FLAGS_H + +#include "sanitizer_common/sanitizer_flag_parser.h" +#include "sanitizer_common/sanitizer_internal_defs.h" + +namespace __xray { + +struct ProfilerFlags { +#define XRAY_FLAG(Type, Name, DefaultValue, Description) Type Name; +#include "xray_profiling_flags.inc" +#undef XRAY_FLAG + +  void setDefaults(); +}; + +extern ProfilerFlags xray_profiling_flags_dont_use_directly; +inline ProfilerFlags *profilingFlags() { +  return &xray_profiling_flags_dont_use_directly; +} +void registerProfilerFlags(FlagParser *P, ProfilerFlags *F); + +} // namespace __xray + +#endif // XRAY_PROFILER_FLAGS_H diff --git a/lib/xray/xray_profiling_flags.inc b/lib/xray/xray_profiling_flags.inc new file mode 100644 index 0000000000000..e9230ae641872 --- /dev/null +++ b/lib/xray/xray_profiling_flags.inc @@ -0,0 +1,29 @@ +//===-- xray_profiling_flags.inc --------------------------------*- C++ -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// XRay profiling runtime flags. +// +//===----------------------------------------------------------------------===// +#ifndef XRAY_FLAG +#error "Define XRAY_FLAG prior to including this file!" +#endif + +XRAY_FLAG(uptr, per_thread_allocator_max, 2 << 20, +          "Maximum size of any single per-thread allocator.") +XRAY_FLAG(uptr, global_allocator_max, 2 << 24, +          "Maximum size of the global allocator for profile storage.") +XRAY_FLAG(uptr, stack_allocator_max, 2 << 20, +          "Maximum size of the traversal stack allocator.") +XRAY_FLAG(int, grace_period_ms, 1, +          "Profile collection will wait this much time in milliseconds before " +          "resetting the global state. This gives a chance to threads to " +          "notice that the profiler has been finalized and clean up.") +XRAY_FLAG(bool, no_flush, false, +          "Set to true if we want the profiling implementation to not write " +          "out files.") diff --git a/lib/xray/xray_recursion_guard.h b/lib/xray/xray_recursion_guard.h new file mode 100644 index 0000000000000..6edadea563bc1 --- /dev/null +++ b/lib/xray/xray_recursion_guard.h @@ -0,0 +1,57 @@ +//===-- xray_recursion_guard.h ---------------------------------*- C++ -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of XRay, a dynamic runtime instrumentation system. +// +//===----------------------------------------------------------------------===// +#ifndef XRAY_XRAY_RECURSION_GUARD_H +#define XRAY_XRAY_RECURSION_GUARD_H + +#include "sanitizer_common/sanitizer_atomic.h" + +namespace __xray { + +/// The RecursionGuard is useful for guarding against signal handlers which are +/// also potentially calling XRay-instrumented functions. To use the +/// RecursionGuard, you'll typically need a thread_local atomic_uint8_t: +/// +///   thread_local atomic_uint8_t Guard{0}; +/// +///   // In a handler function: +///   void handleArg0(int32_t F, XRayEntryType T) { +///     RecursionGuard G(Guard); +///     if (!G) +///       return;  // Failed to acquire the guard. +///     ... +///   } +/// +class RecursionGuard { +  atomic_uint8_t &Running; +  const bool Valid; + +public: +  explicit inline RecursionGuard(atomic_uint8_t &R) +      : Running(R), Valid(!atomic_exchange(&R, 1, memory_order_acq_rel)) {} + +  inline RecursionGuard(const RecursionGuard &) = delete; +  inline RecursionGuard(RecursionGuard &&) = delete; +  inline RecursionGuard &operator=(const RecursionGuard &) = delete; +  inline RecursionGuard &operator=(RecursionGuard &&) = delete; + +  explicit inline operator bool() const { return Valid; } + +  inline ~RecursionGuard() noexcept { +    if (Valid) +      atomic_store(&Running, 0, memory_order_release); +  } +}; + +} // namespace __xray + +#endif // XRAY_XRAY_RECURSION_GUARD_H diff --git a/lib/xray/xray_segmented_array.h b/lib/xray/xray_segmented_array.h new file mode 100644 index 0000000000000..11dd794fa5207 --- /dev/null +++ b/lib/xray/xray_segmented_array.h @@ -0,0 +1,375 @@ +//===-- xray_segmented_array.h ---------------------------------*- C++ -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of XRay, a dynamic runtime instrumentation system. +// +// Defines the implementation of a segmented array, with fixed-size segments +// backing the segments. +// +//===----------------------------------------------------------------------===// +#ifndef XRAY_SEGMENTED_ARRAY_H +#define XRAY_SEGMENTED_ARRAY_H + +#include "sanitizer_common/sanitizer_allocator.h" +#include "xray_allocator.h" +#include "xray_utils.h" +#include <cassert> +#include <type_traits> +#include <utility> + +namespace __xray { + +/// The Array type provides an interface similar to std::vector<...> but does +/// not shrink in size. Once constructed, elements can be appended but cannot be +/// removed. The implementation is heavily dependent on the contract provided by +/// the Allocator type, in that all memory will be released when the Allocator +/// is destroyed. When an Array is destroyed, it will destroy elements in the +/// backing store but will not free the memory. +template <class T> class Array { +  struct SegmentBase { +    SegmentBase *Prev; +    SegmentBase *Next; +  }; + +  // We want each segment of the array to be cache-line aligned, and elements of +  // the array be offset from the beginning of the segment. +  struct Segment : SegmentBase { +    char Data[1]; +  }; + +public: +  // Each segment of the array will be laid out with the following assumptions: +  // +  //   - Each segment will be on a cache-line address boundary (kCacheLineSize +  //     aligned). +  // +  //   - The elements will be accessed through an aligned pointer, dependent on +  //     the alignment of T. +  // +  //   - Each element is at least two-pointers worth from the beginning of the +  //     Segment, aligned properly, and the rest of the elements are accessed +  //     through appropriate alignment. +  // +  // We then compute the size of the segment to follow this logic: +  // +  //   - Compute the number of elements that can fit within +  //     kCacheLineSize-multiple segments, minus the size of two pointers. +  // +  //   - Request cacheline-multiple sized elements from the allocator. +  static constexpr size_t AlignedElementStorageSize = +      sizeof(typename std::aligned_storage<sizeof(T), alignof(T)>::type); + +  static constexpr size_t SegmentSize = +      nearest_boundary(sizeof(Segment) + next_pow2(sizeof(T)), kCacheLineSize); + +  using AllocatorType = Allocator<SegmentSize>; + +  static constexpr size_t ElementsPerSegment = +      (SegmentSize - sizeof(Segment)) / next_pow2(sizeof(T)); + +  static_assert(ElementsPerSegment > 0, +                "Must have at least 1 element per segment."); + +  static SegmentBase SentinelSegment; + +private: +  AllocatorType *Alloc; +  SegmentBase *Head = &SentinelSegment; +  SegmentBase *Tail = &SentinelSegment; +  size_t Size = 0; + +  // Here we keep track of segments in the freelist, to allow us to re-use +  // segments when elements are trimmed off the end. +  SegmentBase *Freelist = &SentinelSegment; + +  Segment *NewSegment() { +    // We need to handle the case in which enough elements have been trimmed to +    // allow us to re-use segments we've allocated before. For this we look into +    // the Freelist, to see whether we need to actually allocate new blocks or +    // just re-use blocks we've already seen before. +    if (Freelist != &SentinelSegment) { +      auto *FreeSegment = Freelist; +      Freelist = FreeSegment->Next; +      FreeSegment->Next = &SentinelSegment; +      Freelist->Prev = &SentinelSegment; +      return static_cast<Segment *>(FreeSegment); +    } + +    auto SegmentBlock = Alloc->Allocate(); +    if (SegmentBlock.Data == nullptr) +      return nullptr; + +    // Placement-new the Segment element at the beginning of the SegmentBlock. +    auto S = reinterpret_cast<Segment *>(SegmentBlock.Data); +    new (S) SegmentBase{&SentinelSegment, &SentinelSegment}; +    return S; +  } + +  Segment *InitHeadAndTail() { +    DCHECK_EQ(Head, &SentinelSegment); +    DCHECK_EQ(Tail, &SentinelSegment); +    auto Segment = NewSegment(); +    if (Segment == nullptr) +      return nullptr; +    DCHECK_EQ(Segment->Next, &SentinelSegment); +    DCHECK_EQ(Segment->Prev, &SentinelSegment); +    Head = Tail = static_cast<SegmentBase *>(Segment); +    return Segment; +  } + +  Segment *AppendNewSegment() { +    auto S = NewSegment(); +    if (S == nullptr) +      return nullptr; +    DCHECK_NE(Tail, &SentinelSegment); +    DCHECK_EQ(Tail->Next, &SentinelSegment); +    DCHECK_EQ(S->Prev, &SentinelSegment); +    DCHECK_EQ(S->Next, &SentinelSegment); +    Tail->Next = S; +    S->Prev = Tail; +    Tail = S; +    return static_cast<Segment *>(Tail); +  } + +  // This Iterator models a BidirectionalIterator. +  template <class U> class Iterator { +    SegmentBase *S = &SentinelSegment; +    size_t Offset = 0; +    size_t Size = 0; + +  public: +    Iterator(SegmentBase *IS, size_t Off, size_t S) +        : S(IS), Offset(Off), Size(S) {} +    Iterator(const Iterator &) noexcept = default; +    Iterator() noexcept = default; +    Iterator(Iterator &&) noexcept = default; +    Iterator &operator=(const Iterator &) = default; +    Iterator &operator=(Iterator &&) = default; +    ~Iterator() = default; + +    Iterator &operator++() { +      if (++Offset % ElementsPerSegment || Offset == Size) +        return *this; + +      // At this point, we know that Offset % N == 0, so we must advance the +      // segment pointer. +      DCHECK_EQ(Offset % ElementsPerSegment, 0); +      DCHECK_NE(Offset, Size); +      DCHECK_NE(S, &SentinelSegment); +      DCHECK_NE(S->Next, &SentinelSegment); +      S = S->Next; +      DCHECK_NE(S, &SentinelSegment); +      return *this; +    } + +    Iterator &operator--() { +      DCHECK_NE(S, &SentinelSegment); +      DCHECK_GT(Offset, 0); + +      auto PreviousOffset = Offset--; +      if (PreviousOffset != Size && PreviousOffset % ElementsPerSegment == 0) { +        DCHECK_NE(S->Prev, &SentinelSegment); +        S = S->Prev; +      } + +      return *this; +    } + +    Iterator operator++(int) { +      Iterator Copy(*this); +      ++(*this); +      return Copy; +    } + +    Iterator operator--(int) { +      Iterator Copy(*this); +      --(*this); +      return Copy; +    } + +    template <class V, class W> +    friend bool operator==(const Iterator<V> &L, const Iterator<W> &R) { +      return L.S == R.S && L.Offset == R.Offset; +    } + +    template <class V, class W> +    friend bool operator!=(const Iterator<V> &L, const Iterator<W> &R) { +      return !(L == R); +    } + +    U &operator*() const { +      DCHECK_NE(S, &SentinelSegment); +      auto RelOff = Offset % ElementsPerSegment; + +      // We need to compute the character-aligned pointer, offset from the +      // segment's Data location to get the element in the position of Offset. +      auto Base = static_cast<Segment *>(S)->Data; +      auto AlignedOffset = Base + (RelOff * AlignedElementStorageSize); +      return *reinterpret_cast<U *>(AlignedOffset); +    } + +    U *operator->() const { return &(**this); } +  }; + +public: +  explicit Array(AllocatorType &A) : Alloc(&A) {} + +  Array(const Array &) = delete; +  Array(Array &&O) NOEXCEPT : Alloc(O.Alloc), +                              Head(O.Head), +                              Tail(O.Tail), +                              Size(O.Size) { +    O.Head = &SentinelSegment; +    O.Tail = &SentinelSegment; +    O.Size = 0; +  } + +  bool empty() const { return Size == 0; } + +  AllocatorType &allocator() const { +    DCHECK_NE(Alloc, nullptr); +    return *Alloc; +  } + +  size_t size() const { return Size; } + +  T *Append(const T &E) { +    if (UNLIKELY(Head == &SentinelSegment)) +      if (InitHeadAndTail() == nullptr) +        return nullptr; + +    auto Offset = Size % ElementsPerSegment; +    if (UNLIKELY(Size != 0 && Offset == 0)) +      if (AppendNewSegment() == nullptr) +        return nullptr; + +    auto Base = static_cast<Segment *>(Tail)->Data; +    auto AlignedOffset = Base + (Offset * AlignedElementStorageSize); +    auto Position = reinterpret_cast<T *>(AlignedOffset); +    *Position = E; +    ++Size; +    return Position; +  } + +  template <class... Args> T *AppendEmplace(Args &&... args) { +    if (UNLIKELY(Head == &SentinelSegment)) +      if (InitHeadAndTail() == nullptr) +        return nullptr; + +    auto Offset = Size % ElementsPerSegment; +    auto *LatestSegment = Tail; +    if (UNLIKELY(Size != 0 && Offset == 0)) { +      LatestSegment = AppendNewSegment(); +      if (LatestSegment == nullptr) +        return nullptr; +    } + +    DCHECK_NE(Tail, &SentinelSegment); +    auto Base = static_cast<Segment *>(LatestSegment)->Data; +    auto AlignedOffset = Base + (Offset * AlignedElementStorageSize); +    auto Position = reinterpret_cast<T *>(AlignedOffset); + +    // In-place construct at Position. +    new (Position) T{std::forward<Args>(args)...}; +    ++Size; +    return reinterpret_cast<T *>(Position); +  } + +  T &operator[](size_t Offset) const { +    DCHECK_LE(Offset, Size); +    // We need to traverse the array enough times to find the element at Offset. +    auto S = Head; +    while (Offset >= ElementsPerSegment) { +      S = S->Next; +      Offset -= ElementsPerSegment; +      DCHECK_NE(S, &SentinelSegment); +    } +    auto Base = static_cast<Segment *>(S)->Data; +    auto AlignedOffset = Base + (Offset * AlignedElementStorageSize); +    auto Position = reinterpret_cast<T *>(AlignedOffset); +    return *reinterpret_cast<T *>(Position); +  } + +  T &front() const { +    DCHECK_NE(Head, &SentinelSegment); +    DCHECK_NE(Size, 0u); +    return *begin(); +  } + +  T &back() const { +    DCHECK_NE(Tail, &SentinelSegment); +    DCHECK_NE(Size, 0u); +    auto It = end(); +    --It; +    return *It; +  } + +  template <class Predicate> T *find_element(Predicate P) const { +    if (empty()) +      return nullptr; + +    auto E = end(); +    for (auto I = begin(); I != E; ++I) +      if (P(*I)) +        return &(*I); + +    return nullptr; +  } + +  /// Remove N Elements from the end. This leaves the blocks behind, and not +  /// require allocation of new blocks for new elements added after trimming. +  void trim(size_t Elements) { +    DCHECK_LE(Elements, Size); +    DCHECK_GT(Size, 0); +    auto OldSize = Size; +    Size -= Elements; + +    DCHECK_NE(Head, &SentinelSegment); +    DCHECK_NE(Tail, &SentinelSegment); + +    for (auto SegmentsToTrim = (nearest_boundary(OldSize, ElementsPerSegment) - +                                nearest_boundary(Size, ElementsPerSegment)) / +                               ElementsPerSegment; +         SegmentsToTrim > 0; --SegmentsToTrim) { +      DCHECK_NE(Head, &SentinelSegment); +      DCHECK_NE(Tail, &SentinelSegment); +      // Put the tail into the Freelist. +      auto *FreeSegment = Tail; +      Tail = Tail->Prev; +      if (Tail == &SentinelSegment) +        Head = Tail; +      else +        Tail->Next = &SentinelSegment; + +      DCHECK_EQ(Tail->Next, &SentinelSegment); +      FreeSegment->Next = Freelist; +      FreeSegment->Prev = &SentinelSegment; +      if (Freelist != &SentinelSegment) +        Freelist->Prev = FreeSegment; +      Freelist = FreeSegment; +    } +  } + +  // Provide iterators. +  Iterator<T> begin() const { return Iterator<T>(Head, 0, Size); } +  Iterator<T> end() const { return Iterator<T>(Tail, Size, Size); } +  Iterator<const T> cbegin() const { return Iterator<const T>(Head, 0, Size); } +  Iterator<const T> cend() const { return Iterator<const T>(Tail, Size, Size); } +}; + +// We need to have this storage definition out-of-line so that the compiler can +// ensure that storage for the SentinelSegment is defined and has a single +// address. +template <class T> +typename Array<T>::SegmentBase Array<T>::SentinelSegment{ +    &Array<T>::SentinelSegment, &Array<T>::SentinelSegment}; + +} // namespace __xray + +#endif // XRAY_SEGMENTED_ARRAY_H diff --git a/lib/xray/xray_trampoline_x86_64.S b/lib/xray/xray_trampoline_x86_64.S index 350afd9265fde..99ad3966ee3a5 100644 --- a/lib/xray/xray_trampoline_x86_64.S +++ b/lib/xray/xray_trampoline_x86_64.S @@ -19,47 +19,56 @@  .macro SAVE_REGISTERS -	subq $192, %rsp -	CFI_DEF_CFA_OFFSET(200) -	// At this point, the stack pointer should be aligned to an 8-byte boundary, -	// because any call instructions that come after this will add another 8 -	// bytes and therefore align it to 16-bytes. -	movq %rbp, 184(%rsp) -	movupd	%xmm0, 168(%rsp) -	movupd	%xmm1, 152(%rsp) -	movupd	%xmm2, 136(%rsp) -	movupd	%xmm3, 120(%rsp) -	movupd	%xmm4, 104(%rsp) -	movupd	%xmm5, 88(%rsp) -	movupd	%xmm6, 72(%rsp) -	movupd	%xmm7, 56(%rsp) -	movq	%rdi, 48(%rsp) -	movq	%rax, 40(%rsp) -	movq	%rdx, 32(%rsp) -	movq	%rsi, 24(%rsp) -	movq	%rcx, 16(%rsp) -	movq	%r8, 8(%rsp) -	movq	%r9, 0(%rsp) +	subq $240, %rsp +	CFI_DEF_CFA_OFFSET(248) +	movq %rbp, 232(%rsp) +	movupd	%xmm0, 216(%rsp) +	movupd	%xmm1, 200(%rsp) +	movupd	%xmm2, 184(%rsp) +	movupd	%xmm3, 168(%rsp) +	movupd	%xmm4, 152(%rsp) +	movupd	%xmm5, 136(%rsp) +	movupd	%xmm6, 120(%rsp) +	movupd	%xmm7, 104(%rsp) +	movq	%rdi, 96(%rsp) +	movq	%rax, 88(%rsp) +	movq	%rdx, 80(%rsp) +	movq	%rsi, 72(%rsp) +	movq	%rcx, 64(%rsp) +	movq	%r8, 56(%rsp) +	movq	%r9, 48(%rsp) +	movq  %r10, 40(%rsp) +	movq  %r11, 32(%rsp) +	movq  %r12, 24(%rsp) +	movq  %r13, 16(%rsp) +	movq  %r14, 8(%rsp) +	movq  %r15, 0(%rsp)  .endm  .macro RESTORE_REGISTERS -	movq  184(%rsp), %rbp -	movupd	168(%rsp), %xmm0 -	movupd	152(%rsp), %xmm1 -	movupd	136(%rsp), %xmm2 -	movupd	120(%rsp), %xmm3 -	movupd	104(%rsp), %xmm4 -	movupd	88(%rsp), %xmm5 -	movupd	72(%rsp) , %xmm6 -	movupd	56(%rsp) , %xmm7 -	movq	48(%rsp), %rdi -	movq	40(%rsp), %rax -	movq	32(%rsp), %rdx -	movq	24(%rsp), %rsi -	movq	16(%rsp), %rcx -	movq	8(%rsp), %r8 -	movq	0(%rsp), %r9 -	addq	$192, %rsp +	movq  232(%rsp), %rbp +	movupd	216(%rsp), %xmm0 +	movupd	200(%rsp), %xmm1 +	movupd	184(%rsp), %xmm2 +	movupd	168(%rsp), %xmm3 +	movupd	152(%rsp), %xmm4 +	movupd	136(%rsp), %xmm5 +	movupd	120(%rsp) , %xmm6 +	movupd	104(%rsp) , %xmm7 +	movq	96(%rsp), %rdi +	movq	88(%rsp), %rax +	movq	80(%rsp), %rdx +	movq	72(%rsp), %rsi +	movq	64(%rsp), %rcx +	movq	56(%rsp), %r8 +	movq	48(%rsp), %r9 +	movq  40(%rsp), %r10 +	movq  32(%rsp), %r11 +	movq  24(%rsp), %r12 +	movq  16(%rsp), %r13 +	movq  8(%rsp), %r14 +	movq  0(%rsp), %r15 +	addq	$240, %rsp  	CFI_DEF_CFA_OFFSET(8)  .endm @@ -90,6 +99,7 @@  	.globl ASM_SYMBOL(__xray_FunctionEntry)  	.align 16, 0x90  	ASM_TYPE_FUNCTION(__xray_FunctionEntry) +# LLVM-MCA-BEGIN __xray_FunctionEntry  ASM_SYMBOL(__xray_FunctionEntry):  	CFI_STARTPROC  	SAVE_REGISTERS @@ -100,7 +110,7 @@ ASM_SYMBOL(__xray_FunctionEntry):  	testq	%rax, %rax  	je	.Ltmp0 -	// The patched function prolog puts its xray_instr_map index into %r10d. +	// The patched function prologue puts its xray_instr_map index into %r10d.  	movl	%r10d, %edi  	xor	%esi,%esi  	ALIGNED_CALL_RAX @@ -108,6 +118,7 @@ ASM_SYMBOL(__xray_FunctionEntry):  .Ltmp0:  	RESTORE_REGISTERS  	retq +# LLVM-MCA-END  	ASM_SIZE(__xray_FunctionEntry)  	CFI_ENDPROC @@ -116,6 +127,7 @@ ASM_SYMBOL(__xray_FunctionEntry):  	.globl ASM_SYMBOL(__xray_FunctionExit)  	.align 16, 0x90  	ASM_TYPE_FUNCTION(__xray_FunctionExit) +# LLVM-MCA-BEGIN __xray_FunctionExit  ASM_SYMBOL(__xray_FunctionExit):  	CFI_STARTPROC  	// Save the important registers first. Since we're assuming that this @@ -146,6 +158,7 @@ ASM_SYMBOL(__xray_FunctionExit):  	addq	$56, %rsp  	CFI_DEF_CFA_OFFSET(8)  	retq +# LLVM-MCA-END  	ASM_SIZE(__xray_FunctionExit)  	CFI_ENDPROC @@ -154,6 +167,7 @@ ASM_SYMBOL(__xray_FunctionExit):  	.globl ASM_SYMBOL(__xray_FunctionTailExit)  	.align 16, 0x90  	ASM_TYPE_FUNCTION(__xray_FunctionTailExit) +# LLVM-MCA-BEGIN __xray_FunctionTailExit  ASM_SYMBOL(__xray_FunctionTailExit):  	CFI_STARTPROC  	SAVE_REGISTERS @@ -170,6 +184,7 @@ ASM_SYMBOL(__xray_FunctionTailExit):  .Ltmp4:  	RESTORE_REGISTERS  	retq +# LLVM-MCA-END  	ASM_SIZE(__xray_FunctionTailExit)  	CFI_ENDPROC @@ -178,6 +193,7 @@ ASM_SYMBOL(__xray_FunctionTailExit):  	.globl ASM_SYMBOL(__xray_ArgLoggerEntry)  	.align 16, 0x90  	ASM_TYPE_FUNCTION(__xray_ArgLoggerEntry) +# LLVM-MCA-BEGIN __xray_ArgLoggerEntry  ASM_SYMBOL(__xray_ArgLoggerEntry):  	CFI_STARTPROC  	SAVE_REGISTERS @@ -207,6 +223,7 @@ ASM_SYMBOL(__xray_ArgLoggerEntry):  .Larg1entryFail:  	RESTORE_REGISTERS  	retq +# LLVM-MCA-END  	ASM_SIZE(__xray_ArgLoggerEntry)  	CFI_ENDPROC @@ -215,13 +232,13 @@ ASM_SYMBOL(__xray_ArgLoggerEntry):  	.global ASM_SYMBOL(__xray_CustomEvent)  	.align 16, 0x90  	ASM_TYPE_FUNCTION(__xray_CustomEvent) +# LLVM-MCA-BEGIN __xray_CustomEvent  ASM_SYMBOL(__xray_CustomEvent):  	CFI_STARTPROC  	SAVE_REGISTERS  	// We take two arguments to this trampoline, which should be in rdi	and rsi -	// already. We also make sure that we stash %rax because we use that register -	// to call the logging handler. +	// already.  	movq ASM_SYMBOL(_ZN6__xray22XRayPatchedCustomEventE)(%rip), %rax  	testq %rax,%rax  	je .LcustomEventCleanup @@ -231,7 +248,35 @@ ASM_SYMBOL(__xray_CustomEvent):  .LcustomEventCleanup:  	RESTORE_REGISTERS  	retq +# LLVM-MCA-END  	ASM_SIZE(__xray_CustomEvent)  	CFI_ENDPROC +//===----------------------------------------------------------------------===// + +	.global ASM_SYMBOL(__xray_TypedEvent) +	.align 16, 0x90 +	ASM_TYPE_FUNCTION(__xray_TypedEvent) +# LLVM-MCA-BEGIN __xray_TypedEvent +ASM_SYMBOL(__xray_TypedEvent): +	CFI_STARTPROC +	SAVE_REGISTERS + +	// We pass three arguments to this trampoline, which should be in rdi, rsi +	// and rdx without our intervention. +	movq ASM_SYMBOL(_ZN6__xray21XRayPatchedTypedEventE)(%rip), %rax +	testq %rax,%rax +	je .LtypedEventCleanup + +	ALIGNED_CALL_RAX + +.LtypedEventCleanup: +	RESTORE_REGISTERS +	retq +# LLVM-MCA-END +	ASM_SIZE(__xray_TypedEvent) +	CFI_ENDPROC + +//===----------------------------------------------------------------------===// +  NO_EXEC_STACK_DIRECTIVE diff --git a/lib/xray/xray_utils.cc b/lib/xray/xray_utils.cc index cf800d3aeaf88..68f4e8c1094c1 100644 --- a/lib/xray/xray_utils.cc +++ b/lib/xray/xray_utils.cc @@ -15,11 +15,11 @@  #include "sanitizer_common/sanitizer_common.h"  #include "xray_defs.h"  #include "xray_flags.h" -#include <stdlib.h>  #include <cstdio>  #include <errno.h>  #include <fcntl.h>  #include <iterator> +#include <stdlib.h>  #include <sys/types.h>  #include <tuple>  #include <unistd.h> @@ -31,7 +31,7 @@ void printToStdErr(const char *Buffer) XRAY_NEVER_INSTRUMENT {    fprintf(stderr, "%s", Buffer);  } -void retryingWriteAll(int Fd, char *Begin, char *End) XRAY_NEVER_INSTRUMENT { +void retryingWriteAll(int Fd, const char *Begin, const char *End) XRAY_NEVER_INSTRUMENT {    if (Begin == End)      return;    auto TotalBytes = std::distance(Begin, End); @@ -82,7 +82,7 @@ bool readValueFromFile(const char *Filename,    if (!Success)      return false;    close(Fd); -  char *End = nullptr; +  const char *End = nullptr;    long long Tmp = internal_simple_strtoll(Line, &End, 10);    bool Result = false;    if (Line[0] != '\0' && (*End == '\n' || *End == '\0')) { @@ -94,10 +94,10 @@ bool readValueFromFile(const char *Filename,  int getLogFD() XRAY_NEVER_INSTRUMENT {    // Open a temporary file once for the log. -  static char TmpFilename[256] = {}; -  static char TmpWildcardPattern[] = "XXXXXX"; -  auto Argv = GetArgv(); -  const char *Progname = Argv[0] == nullptr ? "(unknown)" : Argv[0]; +  char TmpFilename[256] = {}; +  char TmpWildcardPattern[] = "XXXXXX"; +  auto **Argv = GetArgv(); +  const char *Progname = !Argv ? "(unknown)" : Argv[0];    const char *LastSlash = internal_strrchr(Progname, '/');    if (LastSlash != nullptr) @@ -117,7 +117,7 @@ int getLogFD() XRAY_NEVER_INSTRUMENT {             TmpFilename);      return -1;    } -  if (__sanitizer::Verbosity()) +  if (Verbosity())      Report("XRay: Log file in '%s'\n", TmpFilename);    return Fd; diff --git a/lib/xray/xray_utils.h b/lib/xray/xray_utils.h index 1ecc74a2dce87..eafa16e1a9d5d 100644 --- a/lib/xray/xray_utils.h +++ b/lib/xray/xray_utils.h @@ -15,6 +15,8 @@  #ifndef XRAY_UTILS_H  #define XRAY_UTILS_H +#include <cstddef> +#include <cstdint>  #include <sys/types.h>  #include <utility> @@ -24,7 +26,7 @@ namespace __xray {  void printToStdErr(const char *Buffer);  // EINTR-safe write routine, provided a file descriptor and a character range. -void retryingWriteAll(int Fd, char *Begin, char *End); +void retryingWriteAll(int Fd, const char *Begin, const char *End);  // Reads a long long value from a provided file.  bool readValueFromFile(const char *Filename, long long *Value); @@ -36,6 +38,32 @@ std::pair<ssize_t, bool> retryingReadSome(int Fd, char *Begin, char *End);  // file.  int getLogFD(); +constexpr size_t gcd(size_t a, size_t b) { +  return (b == 0) ? a : gcd(b, a % b); +} + +constexpr size_t lcm(size_t a, size_t b) { return a * b / gcd(a, b); } + +constexpr size_t nearest_boundary(size_t number, size_t multiple) { +  return multiple * ((number / multiple) + (number % multiple ? 1 : 0)); +} + +constexpr size_t next_pow2_helper(size_t num, size_t acc) { +  return (1u << acc) >= num ? (1u << acc) : next_pow2_helper(num, acc + 1); +} + +constexpr size_t next_pow2(size_t number) { +  return next_pow2_helper(number, 1); +} + +template <class T> constexpr T &max(T &A, T &B) { return A > B ? A : B; } + +template <class T> constexpr T &min(T &A, T &B) { return A <= B ? A : B; } + +constexpr ptrdiff_t diff(uintptr_t A, uintptr_t B) { +  return max(A, B) - min(A, B); +} +  } // namespace __xray  #endif // XRAY_UTILS_H diff --git a/lib/xray/xray_x86_64.cc b/lib/xray/xray_x86_64.cc index e17f00ac3a62a..51dc4ce43b1c6 100644 --- a/lib/xray/xray_x86_64.cc +++ b/lib/xray/xray_x86_64.cc @@ -3,6 +3,15 @@  #include "xray_defs.h"  #include "xray_interface_internal.h" +#if SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_OPENBSD +#include <sys/types.h> +#if SANITIZER_OPENBSD +#include <sys/time.h> +#include <machine/cpu.h> +#endif +#include <sys/sysctl.h> +#endif +  #include <atomic>  #include <cstdint>  #include <errno.h> @@ -14,6 +23,7 @@  namespace __xray { +#if SANITIZER_LINUX  static std::pair<ssize_t, bool>  retryingReadSome(int Fd, char *Begin, char *End) XRAY_NEVER_INSTRUMENT {    auto BytesToRead = std::distance(Begin, End); @@ -47,7 +57,7 @@ static bool readValueFromFile(const char *Filename,    close(Fd);    if (!Success)      return false; -  char *End = nullptr; +  const char *End = nullptr;    long long Tmp = internal_simple_strtoll(Line, &End, 10);    bool Result = false;    if (Line[0] != '\0' && (*End == '\n' || *End == '\0')) { @@ -71,6 +81,31 @@ uint64_t getTSCFrequency() XRAY_NEVER_INSTRUMENT {    }    return TSCFrequency == -1 ? 0 : static_cast<uint64_t>(TSCFrequency);  } +#elif SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_OPENBSD +uint64_t getTSCFrequency() XRAY_NEVER_INSTRUMENT { +    long long TSCFrequency = -1; +    size_t tscfreqsz = sizeof(TSCFrequency); +#if SANITIZER_OPENBSD +    int Mib[2] = { CTL_MACHDEP, CPU_TSCFREQ }; +    if (sysctl(Mib, 2, &TSCFrequency, &tscfreqsz, NULL, 0) != -1) { + +#else +    if (sysctlbyname("machdep.tsc_freq", &TSCFrequency, &tscfreqsz, +        NULL, 0) != -1) { +#endif +        return static_cast<uint64_t>(TSCFrequency); +    } else { +      Report("Unable to determine CPU frequency for TSC accounting.\n"); +    } + +    return 0; +} +#else +uint64_t getTSCFrequency() XRAY_NEVER_INSTRUMENT { +    /* Not supported */ +    return 0; +} +#endif  static constexpr uint8_t CallOpCode = 0xe8;  static constexpr uint16_t MovR10Seq = 0xba41; @@ -184,8 +219,8 @@ bool patchFunctionTailExit(const bool Enable, const uint32_t FuncId,        reinterpret_cast<int64_t>(__xray_FunctionTailExit) -        (static_cast<int64_t>(Sled.Address) + 11);    if (TrampolineOffset < MinOffset || TrampolineOffset > MaxOffset) { -    Report("XRay Exit trampoline (%p) too far from sled (%p)\n", -           __xray_FunctionExit, reinterpret_cast<void *>(Sled.Address)); +    Report("XRay Tail Exit trampoline (%p) too far from sled (%p)\n", +           __xray_FunctionTailExit, reinterpret_cast<void *>(Sled.Address));      return false;    }    if (Enable) { @@ -251,6 +286,37 @@ bool patchCustomEvent(const bool Enable, const uint32_t FuncId,    return false;  } +bool patchTypedEvent(const bool Enable, const uint32_t FuncId, +                      const XRaySledEntry &Sled) XRAY_NEVER_INSTRUMENT { +  // Here we do the dance of replacing the following sled: +  // +  // xray_sled_n: +  //   jmp +20          // 2 byte instruction +  //   ... +  // +  // With the following: +  // +  //   nopw             // 2 bytes +  //   ... +  // +  // +  // The "unpatch" should just turn the 'nopw' back to a 'jmp +20'. +  // The 20 byte sled stashes three argument registers, calls the trampoline, +  // unstashes the registers and returns. If the arguments are already in +  // the correct registers, the stashing and unstashing become equivalently +  // sized nops. +  if (Enable) { +    std::atomic_store_explicit( +        reinterpret_cast<std::atomic<uint16_t> *>(Sled.Address), NopwSeq, +        std::memory_order_release); +  } else { +      std::atomic_store_explicit( +          reinterpret_cast<std::atomic<uint16_t> *>(Sled.Address), Jmp20Seq, +          std::memory_order_release); +  } +  return false; +} +  // We determine whether the CPU we're running on has the correct features we  // need. In x86_64 this will be rdtscp support.  bool probeRequiredCPUFeatures() XRAY_NEVER_INSTRUMENT { @@ -259,7 +325,8 @@ bool probeRequiredCPUFeatures() XRAY_NEVER_INSTRUMENT {    // We check whether rdtscp support is enabled. According to the x86_64 manual,    // level should be set at 0x80000001, and we should have a look at bit 27 in    // EDX. That's 0x8000000 (or 1u << 27). -  __get_cpuid(0x80000001, &EAX, &EBX, &ECX, &EDX); +  __asm__ __volatile__("cpuid" : "=a"(EAX), "=b"(EBX), "=c"(ECX), "=d"(EDX) +    : "0"(0x80000001));    if (!(EDX & (1u << 27))) {      Report("Missing rdtscp support.\n");      return false; diff --git a/lib/xray/xray_x86_64.inc b/lib/xray/xray_x86_64.inc index 4ad3f98109461..b3c475f9110c2 100644 --- a/lib/xray/xray_x86_64.inc +++ b/lib/xray/xray_x86_64.inc @@ -21,9 +21,10 @@ namespace __xray {  ALWAYS_INLINE uint64_t readTSC(uint8_t &CPU) XRAY_NEVER_INSTRUMENT {    unsigned LongCPU; -  uint64_t TSC = __rdtscp(&LongCPU); +  unsigned long Rax, Rdx; +  __asm__ __volatile__("rdtscp\n" : "=a"(Rax), "=d"(Rdx), "=c"(LongCPU) ::);    CPU = LongCPU; -  return TSC; +  return (Rdx << 32) + Rax;  }  uint64_t getTSCFrequency(); diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index ab16f42d33d4f..554ba5fa0f0eb 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -61,7 +61,8 @@ if(COMPILER_RT_CAN_EXECUTE_TESTS)      compiler_rt_test_runtime(ubsan cfi)      compiler_rt_test_runtime(sanitizer_common) -    if(COMPILER_RT_BUILD_LIBFUZZER) +    # OpenBSD not supporting asan, cannot run the tests +    if(COMPILER_RT_BUILD_LIBFUZZER AND NOT "${CMAKE_SYSTEM_NAME}" STREQUAL "OpenBSD" AND NOT ANDROID)        compiler_rt_test_runtime(fuzzer)      endif() @@ -78,6 +79,9 @@ if(COMPILER_RT_CAN_EXECUTE_TESTS)    if(COMPILER_RT_BUILD_XRAY)      compiler_rt_test_runtime(xray)    endif() +  # ShadowCallStack does not yet provide a runtime with compiler-rt, the tests +  # include their own minimal runtime +  add_subdirectory(shadowcallstack)  endif()  if(COMPILER_RT_STANDALONE_BUILD) diff --git a/test/asan/CMakeLists.txt b/test/asan/CMakeLists.txt index 739ae56e782bc..e6d1df5e039a7 100644 --- a/test/asan/CMakeLists.txt +++ b/test/asan/CMakeLists.txt @@ -8,7 +8,7 @@ set(ASAN_DYNAMIC_TESTSUITES)  # unreliable. Remove the asan tests from check-all in this configuration.  set(SHADOW_MAPPING_UNRELIABLE FALSE)  if(OS_NAME MATCHES "Windows" AND CMAKE_SIZEOF_VOID_P EQUAL 8 AND -    ${CMAKE_SYSTEM_VERSION} LESS 6.2) +    CMAKE_SYSTEM_VERSION LESS 6.2)    set(SHADOW_MAPPING_UNRELIABLE TRUE)    message(WARNING "Disabling ASan tests because they are unreliable on Windows 7 and earlier")  endif() @@ -18,10 +18,10 @@ if (SHADOW_MAPPING_UNRELIABLE)  endif()  macro(get_bits_for_arch arch bits) -  if (${arch} MATCHES "i386|arm|mips|mipsel") -    set(${bits} 32) -  elseif (${arch} MATCHES "x86_64|powerpc64|powerpc64le|aarch64|mips64|mips64el|s390x") +  if (${arch} MATCHES "x86_64|powerpc64|powerpc64le|aarch64|arm64|mips64|mips64el|s390x")      set(${bits} 64) +  elseif (${arch} MATCHES "i386|arm|mips|mipsel") +    set(${bits} 32)    else()      message(FATAL_ERROR "Unknown target architecture: ${arch}")    endif() @@ -40,6 +40,9 @@ set(ASAN_TEST_ARCH ${ASAN_SUPPORTED_ARCH})  if(APPLE)    darwin_filter_host_archs(ASAN_SUPPORTED_ARCH ASAN_TEST_ARCH)  endif() +if(OS_NAME MATCHES "SunOS") +  list(REMOVE_ITEM ASAN_TEST_ARCH x86_64) +endif()  foreach(arch ${ASAN_TEST_ARCH})    if(ANDROID) @@ -48,10 +51,7 @@ foreach(arch ${ASAN_TEST_ARCH})      set(ASAN_TEST_TARGET_ARCH ${arch})    endif() -  set(ASAN_TEST_IOS "0") -  pythonize_bool(ASAN_TEST_IOS) -  set(ASAN_TEST_IOSSIM "0") -  pythonize_bool(ASAN_TEST_IOSSIM) +  set(ASAN_TEST_APPLE_PLATFORM "osx")    string(TOLOWER "-${arch}-${OS_NAME}" ASAN_TEST_CONFIG_SUFFIX)    get_bits_for_arch(${arch} ASAN_TEST_BITS) @@ -90,16 +90,13 @@ if(APPLE)    set(EXCLUDE_FROM_ALL ON)    set(ASAN_TEST_TARGET_CC ${COMPILER_RT_TEST_COMPILER}) -  set(ASAN_TEST_IOS "1") -  pythonize_bool(ASAN_TEST_IOS)    set(ASAN_TEST_DYNAMIC True)    foreach(arch ${DARWIN_iossim_ARCHS}) -    set(ASAN_TEST_IOSSIM "1") -    pythonize_bool(ASAN_TEST_IOSSIM) +    set(ASAN_TEST_APPLE_PLATFORM "iossim")      set(ASAN_TEST_TARGET_ARCH ${arch})      set(ASAN_TEST_TARGET_CFLAGS "-arch ${arch} -isysroot ${DARWIN_iossim_SYSROOT} ${COMPILER_RT_TEST_COMPILER_CFLAGS}") -    set(ASAN_TEST_CONFIG_SUFFIX "-${arch}-iossim") +    set(ASAN_TEST_CONFIG_SUFFIX "-${arch}-${ASAN_TEST_APPLE_PLATFORM}")      get_bits_for_arch(${arch} ASAN_TEST_BITS)      string(TOUPPER ${arch} ARCH_UPPER_CASE)      set(CONFIG_NAME "IOSSim${ARCH_UPPER_CASE}Config") @@ -113,11 +110,10 @@ if(APPLE)    endforeach()    foreach (arch ${DARWIN_ios_ARCHS}) -    set(ASAN_TEST_IOSSIM "0") -    pythonize_bool(ASAN_TEST_IOSSIM) +    set(ASAN_TEST_APPLE_PLATFORM "ios")      set(ASAN_TEST_TARGET_ARCH ${arch})      set(ASAN_TEST_TARGET_CFLAGS "-arch ${arch} -isysroot ${DARWIN_ios_SYSROOT} ${COMPILER_RT_TEST_COMPILER_CFLAGS}") -    set(ASAN_TEST_CONFIG_SUFFIX "-${arch}-ios") +    set(ASAN_TEST_CONFIG_SUFFIX "-${arch}-${ASAN_TEST_APPLE_PLATFORM}")      get_bits_for_arch(${arch} ASAN_TEST_BITS)      string(TOUPPER ${arch} ARCH_UPPER_CASE)      set(CONFIG_NAME "IOS${ARCH_UPPER_CASE}Config") diff --git a/test/asan/TestCases/Darwin/asan_gen_prefixes.cc b/test/asan/TestCases/Darwin/asan_gen_prefixes.cc index 9f3a66a7a7080..fe337433d08db 100644 --- a/test/asan/TestCases/Darwin/asan_gen_prefixes.cc +++ b/test/asan/TestCases/Darwin/asan_gen_prefixes.cc @@ -1,4 +1,4 @@ -// Make sure __asan_gen_* strings have the correct prefixes on Darwin +// Make sure ___asan_gen_* strings have the correct prefixes on Darwin  // ("L" in __TEXT,__cstring, "l" in __TEXT,__const  // RUN: %clang_asan %s -S -o %t.s @@ -9,8 +9,8 @@  int x, y, z;  int main() { return 0; }  // CHECK: .section{{.*}}__TEXT,__const -// CHECK: l___asan_gen_ +// CHECK: l____asan_gen_  // CHECK: .section{{.*}}__TEXT,__cstring,cstring_literals -// CHECK: L___asan_gen_ -// CHECK: L___asan_gen_ -// CHECK: L___asan_gen_ +// CHECK: L____asan_gen_ +// CHECK: L____asan_gen_ +// CHECK: L____asan_gen_ diff --git a/test/asan/TestCases/Darwin/odr-lto.cc b/test/asan/TestCases/Darwin/odr-lto.cc index 40abec5827d5f..56dd89b164c22 100644 --- a/test/asan/TestCases/Darwin/odr-lto.cc +++ b/test/asan/TestCases/Darwin/odr-lto.cc @@ -3,15 +3,10 @@  // REQUIRES: lto -// RUN: %clangxx_asan -DPART=0 -c %s -o %t-1.o -flto -// RUN: %clangxx_asan -DPART=1 -c %s -o %t-2.o -flto -// RUN: %clangxx_asan %t-1.o %t-2.o -o %t -flto -// RUN: not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-ODR -  // RUN: %clangxx_asan -DPART=0 -c %s -o %t-1.o -flto -mllvm -asan-use-private-alias  // RUN: %clangxx_asan -DPART=1 -c %s -o %t-2.o -flto -mllvm -asan-use-private-alias  // RUN: %clangxx_asan %t-1.o %t-2.o -o %t -flto -// RUN: %env_asan_opts=use_odr_indicator=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-NO-ODR +// RUN: %env_asan_opts=use_odr_indicator=1 %run %t 2>&1 | FileCheck %s  #include <stdio.h>  #include <stdlib.h> @@ -40,6 +35,5 @@ void putstest()  #endif // PART == 1 -// CHECK-ODR: ERROR: AddressSanitizer: odr-violation -// CHECK-NO-ODR-NOT: ERROR: AddressSanitizer: odr-violation -// CHECK-NO-ODR: Done. +// CHECK-NOT: ERROR: AddressSanitizer: odr-violation +// CHECK: Done. diff --git a/test/asan/TestCases/Linux/activation-options.cc b/test/asan/TestCases/Linux/activation-options.cc index 1a1ad3f8c4991..39924c4b1d031 100644 --- a/test/asan/TestCases/Linux/activation-options.cc +++ b/test/asan/TestCases/Linux/activation-options.cc @@ -28,7 +28,6 @@  // RUN:   ASAN_ACTIVATION_OPTIONS=include=%t.asan.options.%b %run %t --fix-name 2>&1 | \  // RUN:   FileCheck %s --check-prefix=CHECK-HELP --check-prefix=CHECK-FOUND -// XFAIL: arm-linux-gnueabi  // XFAIL: android  #if !defined(SHARED_LIB) diff --git a/test/asan/TestCases/Linux/allocator_oom_test.cc b/test/asan/TestCases/Linux/allocator_oom_test.cc index 6382003781ce7..c450ae5bb8e91 100644 --- a/test/asan/TestCases/Linux/allocator_oom_test.cc +++ b/test/asan/TestCases/Linux/allocator_oom_test.cc @@ -32,7 +32,7 @@  // AArch64 bots fail on this test.  // TODO(alekseys): Android lit do not run ulimit on device.  // REQUIRES: shadow-scale-3 -// UNSUPPORTED: s390,android,arm,aarch64 +// UNSUPPORTED: s390,android,aarch64  #include <stdlib.h>  #include <string.h> @@ -84,5 +84,5 @@ int main(int argc, char **argv) {  // CHECK-REALLOC: realloc:  // CHECK-MALLOC-REALLOC: realloc-after-malloc: -// CHECK-CRASH: AddressSanitizer's allocator is terminating the process +// CHECK-CRASH: SUMMARY: AddressSanitizer: out-of-memory  // CHECK-NULL: x: 0 diff --git a/test/asan/TestCases/Linux/clang_gcc_abi.cc b/test/asan/TestCases/Linux/clang_gcc_abi.cc index 79710dc837b9f..e0ae3f1f8afd4 100644 --- a/test/asan/TestCases/Linux/clang_gcc_abi.cc +++ b/test/asan/TestCases/Linux/clang_gcc_abi.cc @@ -3,8 +3,7 @@  // RUN: %clangxx_asan -O2 -x c %s -o %t && not %run %t 2>&1 | FileCheck %s  // RUN: %clangxx_asan -O3 -x c %s -o %t && not %run %t 2>&1 | FileCheck %s -// REQUIRES: arm-target-arch, fast-unwinder-works -// XFAIL: armv7l-unknown-linux-gnueabihf +// REQUIRES: (arm-target-arch || armhf-target-arch), fast-unwinder-works  #include <stdlib.h> diff --git a/test/asan/TestCases/Linux/clone_test.cc b/test/asan/TestCases/Linux/clone_test.cc index f6eb26100f5e1..0b86238ccad6a 100644 --- a/test/asan/TestCases/Linux/clone_test.cc +++ b/test/asan/TestCases/Linux/clone_test.cc @@ -5,7 +5,6 @@  // RUN: %clangxx_asan -O1 %s -o %t && %run %t | FileCheck %s  // RUN: %clangxx_asan -O2 %s -o %t && %run %t | FileCheck %s  // RUN: %clangxx_asan -O3 %s -o %t && %run %t | FileCheck %s -// XFAIL: arm-linux-gnueabi  #include <stdio.h>  #include <sched.h> diff --git a/test/asan/TestCases/Linux/coverage-missing.cc b/test/asan/TestCases/Linux/coverage-missing.cc index 585aee69a029f..32aada645deb2 100644 --- a/test/asan/TestCases/Linux/coverage-missing.cc +++ b/test/asan/TestCases/Linux/coverage-missing.cc @@ -2,18 +2,18 @@  // First case: coverage from executable. main() is called on every code path.  // RUN: %clangxx_asan -fsanitize-coverage=func,trace-pc-guard %s -o %t -DFOOBAR -DMAIN -// RUN: rm -rf %T/coverage-missing -// RUN: mkdir -p %T/coverage-missing -// RUN: cd %T/coverage-missing -// RUN: %env_asan_opts=coverage=1:coverage_dir=%T/coverage-missing %run %t +// RUN: rm -rf %t-dir +// RUN: mkdir -p %t-dir +// RUN: cd %t-dir +// RUN: %env_asan_opts=coverage=1:coverage_dir=%t-dir %run %t  // RUN: %sancov print *.sancov > main.txt  // RUN: rm *.sancov  // RUN: count 1 < main.txt -// RUN: %env_asan_opts=coverage=1:coverage_dir=%T/coverage-missing %run %t x +// RUN: %env_asan_opts=coverage=1:coverage_dir=%t-dir %run %t x  // RUN: %sancov print *.sancov > foo.txt  // RUN: rm *.sancov  // RUN: count 3 < foo.txt -// RUN: %env_asan_opts=coverage=1:coverage_dir=%T/coverage-missing %run %t x x +// RUN: %env_asan_opts=coverage=1:coverage_dir=%t-dir %run %t x x  // RUN: %sancov print *.sancov > bar.txt  // RUN: rm *.sancov  // RUN: count 4 < bar.txt @@ -26,18 +26,18 @@  // RUN: not grep "^<" %t.log  // Second case: coverage from DSO. -// cd %T +// cd %t-dir  // RUN: %clangxx_asan -fsanitize-coverage=func,trace-pc-guard %s -o %dynamiclib -DFOOBAR -shared -fPIC  // RUN: %clangxx_asan -fsanitize-coverage=func,trace-pc-guard %s %dynamiclib -o %t -DMAIN  // RUN: cd .. -// RUN: rm -rf %T/coverage-missing -// RUN: mkdir -p %T/coverage-missing -// RUN: cd %T/coverage-missing -// RUN: %env_asan_opts=coverage=1:coverage_dir=%T/coverage-missing %run %t x +// RUN: rm -rf %t-dir +// RUN: mkdir -p %t-dir +// RUN: cd %t-dir +// RUN: %env_asan_opts=coverage=1:coverage_dir=%t-dir %run %t x  // RUN: %sancov print %xdynamiclib_filename.*.sancov > foo.txt  // RUN: rm *.sancov  // RUN: count 2 < foo.txt -// RUN: %env_asan_opts=coverage=1:coverage_dir=%T/coverage-missing %run %t x x +// RUN: %env_asan_opts=coverage=1:coverage_dir=%t-dir %run %t x x  // RUN: %sancov print %xdynamiclib_filename.*.sancov > bar.txt  // RUN: rm *.sancov  // RUN: count 3 < bar.txt diff --git a/test/asan/TestCases/Linux/interception_readdir_r_test.cc b/test/asan/TestCases/Linux/interception_readdir_r_test.cc index 93b553c3744fa..987dff27523ad 100644 --- a/test/asan/TestCases/Linux/interception_readdir_r_test.cc +++ b/test/asan/TestCases/Linux/interception_readdir_r_test.cc @@ -1,15 +1,18 @@  // FIXME: https://code.google.com/p/address-sanitizer/issues/detail?id=316  // XFAIL: android + +// RUN: rm -rf %t-dir +// RUN: mkdir -p %t-dir  // -// RUN: %clangxx_asan -O0 %s -DTEMP_DIR='"'"%T"'"' -o %t && %run %t 2>&1 | FileCheck %s -// RUN: %clangxx_asan -O1 %s -DTEMP_DIR='"'"%T"'"' -o %t && %run %t 2>&1 | FileCheck %s -// RUN: %clangxx_asan -O2 %s -DTEMP_DIR='"'"%T"'"' -o %t && %run %t 2>&1 | FileCheck %s -// RUN: %clangxx_asan -O3 %s -DTEMP_DIR='"'"%T"'"' -o %t && %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O0 %s -DTEMP_DIR='"'"%t-dir"'"' -o %t && %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O1 %s -DTEMP_DIR='"'"%t-dir"'"' -o %t && %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O2 %s -DTEMP_DIR='"'"%t-dir"'"' -o %t && %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O3 %s -DTEMP_DIR='"'"%t-dir"'"' -o %t && %run %t 2>&1 | FileCheck %s  // -// RUN: %clangxx_asan -O0 %s -D_FILE_OFFSET_BITS=64 -DTEMP_DIR='"'"%T"'"' -o %t && %run %t 2>&1 | FileCheck %s -// RUN: %clangxx_asan -O1 %s -D_FILE_OFFSET_BITS=64 -DTEMP_DIR='"'"%T"'"' -o %t && %run %t 2>&1 | FileCheck %s -// RUN: %clangxx_asan -O2 %s -D_FILE_OFFSET_BITS=64 -DTEMP_DIR='"'"%T"'"' -o %t && %run %t 2>&1 | FileCheck %s -// RUN: %clangxx_asan -O3 %s -D_FILE_OFFSET_BITS=64 -DTEMP_DIR='"'"%T"'"' -o %t && %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O0 %s -D_FILE_OFFSET_BITS=64 -DTEMP_DIR='"'"%t-dir"'"' -o %t && %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O1 %s -D_FILE_OFFSET_BITS=64 -DTEMP_DIR='"'"%t-dir"'"' -o %t && %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O2 %s -D_FILE_OFFSET_BITS=64 -DTEMP_DIR='"'"%t-dir"'"' -o %t && %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O3 %s -D_FILE_OFFSET_BITS=64 -DTEMP_DIR='"'"%t-dir"'"' -o %t && %run %t 2>&1 | FileCheck %s  #include <dirent.h>  #include <memory.h> diff --git a/test/asan/TestCases/Linux/local_alias.cc b/test/asan/TestCases/Linux/local_alias.cc index 8c80f878594df..266d3fe6bc8ff 100644 --- a/test/asan/TestCases/Linux/local_alias.cc +++ b/test/asan/TestCases/Linux/local_alias.cc @@ -7,10 +7,6 @@  // FIXME: https://github.com/google/sanitizers/issues/316  // XFAIL: android  // -// This test requires the integrated assembler to be the default. -// XFAIL: target-is-mips64 -// XFAIL: target-is-mips64el -//  // RUN: %clangxx_asan -DBUILD_INSTRUMENTED_DSO=1 -fPIC -shared -mllvm -asan-use-private-alias %s -o %t-INSTRUMENTED-SO.so  // RUN: %clangxx -DBUILD_UNINSTRUMENTED_DSO=1 -fPIC -shared %s -o %t-UNINSTRUMENTED-SO.so  // RUN: %clangxx %s -c -mllvm -asan-use-private-alias -o %t.o diff --git a/test/asan/TestCases/Linux/long-object-path.cc b/test/asan/TestCases/Linux/long-object-path.cc new file mode 100644 index 0000000000000..592b0abb07d72 --- /dev/null +++ b/test/asan/TestCases/Linux/long-object-path.cc @@ -0,0 +1,7 @@ +// RUN: mkdir -p %T/a-long-directory-name-to-test-allocations-for-exceptions-in-_dl_lookup_symbol_x-since-glibc-2.27 +// RUN: %clangxx_asan -g %s -o %T/long-object-path +// RUN: %run %T/a-*/../a-*/../a-*/../a-*/../a-*/../a-*/../a-*/../a-*/../long-object-path + +int main(void) { +    return 0; +} diff --git a/test/asan/TestCases/Linux/odr-violation.cc b/test/asan/TestCases/Linux/odr-violation.cc index d909143a86a13..70437a8321b91 100644 --- a/test/asan/TestCases/Linux/odr-violation.cc +++ b/test/asan/TestCases/Linux/odr-violation.cc @@ -1,10 +1,6 @@  // FIXME: https://code.google.com/p/address-sanitizer/issues/detail?id=316  // XFAIL: android  // -// This test requires the integrated assembler to be the default. -// XFAIL: target-is-mips64 -// XFAIL: target-is-mips64el -//  // We use fast_unwind_on_malloc=0 to have full unwinding even w/o frame  // pointers. This setting is not on by default because it's too expensive.  // diff --git a/test/asan/TestCases/Linux/pvalloc-overflow.cc b/test/asan/TestCases/Linux/pvalloc-overflow.cc deleted file mode 100644 index b47c6266b93be..0000000000000 --- a/test/asan/TestCases/Linux/pvalloc-overflow.cc +++ /dev/null @@ -1,41 +0,0 @@ -// RUN: %clangxx_asan  %s -o %t -// RUN: ASAN_OPTIONS=allocator_may_return_null=0 not %run %t m1 2>&1 | FileCheck %s -// RUN: ASAN_OPTIONS=allocator_may_return_null=1     %run %t m1 2>&1 -// RUN: ASAN_OPTIONS=allocator_may_return_null=0 not %run %t psm1 2>&1 | FileCheck %s -// RUN: ASAN_OPTIONS=allocator_may_return_null=1     %run %t psm1 2>&1 - -// UNSUPPORTED: freebsd, android - -// Checks that pvalloc overflows are caught. If the allocator is allowed to -// return null, the errno should be set to ENOMEM. - -#include <assert.h> -#include <errno.h> -#include <malloc.h> -#include <stdint.h> -#include <string.h> -#include <unistd.h> - -int main(int argc, char *argv[]) { -  void *p; -  size_t page_size; - -  assert(argc == 2); - -  page_size = sysconf(_SC_PAGESIZE); - -  if (!strcmp(argv[1], "m1")) { -    p = pvalloc((uintptr_t)-1); -    assert(!p); -    assert(errno == ENOMEM); -  } -  if (!strcmp(argv[1], "psm1")) { -    p = pvalloc((uintptr_t)-(page_size - 1)); -    assert(!p); -    assert(errno == ENOMEM); -  } - -  return 0; -} - -// CHECK: AddressSanitizer's allocator is terminating the process diff --git a/test/asan/TestCases/Linux/quarantine_size_mb.cc b/test/asan/TestCases/Linux/quarantine_size_mb.cc index 239eeabee1707..f7bccbfbe8db8 100644 --- a/test/asan/TestCases/Linux/quarantine_size_mb.cc +++ b/test/asan/TestCases/Linux/quarantine_size_mb.cc @@ -5,6 +5,10 @@  // RUN: %env_asan_opts=quarantine_size_mb=10:quarantine_size=20:verbosity=1  not %run %t  2>&1 | FileCheck %s  --check-prefix=BOTH  // RUN: %env_asan_opts=quarantine_size_mb=1000:hard_rss_limit_mb=50 not  %run %t          2>&1 | FileCheck %s  --check-prefix=RSS_LIMIT  // RUN: %env_asan_opts=hard_rss_limit_mb=20                         not  %run %t          2>&1 | FileCheck %s  --check-prefix=RSS_LIMIT + +// https://github.com/google/sanitizers/issues/981 +// UNSUPPORTED: android-26 +  #include <string.h>  char *g; diff --git a/test/asan/TestCases/Linux/stack-trace-dlclose.cc b/test/asan/TestCases/Linux/stack-trace-dlclose.cc index e604f1e4f73f6..899e0dfc6bda5 100644 --- a/test/asan/TestCases/Linux/stack-trace-dlclose.cc +++ b/test/asan/TestCases/Linux/stack-trace-dlclose.cc @@ -1,8 +1,10 @@  // FIXME: https://code.google.com/p/address-sanitizer/issues/detail?id=316  // XFAIL: android  // -// RUN: %clangxx_asan -DSHARED %s -shared -o %T/stack_trace_dlclose.so -fPIC -// RUN: %clangxx_asan -DSO_DIR=\"%T\" %s %libdl -o %t +// RUN: rm -rf %t-dir +// RUN: mkdir -p %t-dir +// RUN: %clangxx_asan -DSHARED %s -shared -o %t-dir/stack_trace_dlclose.so -fPIC +// RUN: %clangxx_asan -DSO_DIR=\"%t-dir\" %s %libdl -o %t  // RUN: %env_asan_opts=exitcode=0 %run %t 2>&1 | FileCheck %s  // REQUIRES: stable-runtime diff --git a/test/asan/TestCases/Linux/syscalls.cc b/test/asan/TestCases/Linux/syscalls.cc index bcdd5bc821195..ec14bca76129d 100644 --- a/test/asan/TestCases/Linux/syscalls.cc +++ b/test/asan/TestCases/Linux/syscalls.cc @@ -1,6 +1,3 @@ -// FIXME: https://code.google.com/p/address-sanitizer/issues/detail?id=316 -// XFAIL: android -//  // RUN: %clangxx_asan -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s  // RUN: %clangxx_asan -O3 %s -o %t && not %run %t 2>&1 | FileCheck %s diff --git a/test/asan/TestCases/Posix/asan-sigbus.cpp b/test/asan/TestCases/Posix/asan-sigbus.cpp index c91ecbd756f64..baf1e4266866c 100644 --- a/test/asan/TestCases/Posix/asan-sigbus.cpp +++ b/test/asan/TestCases/Posix/asan-sigbus.cpp @@ -5,6 +5,8 @@  // RUN: %env_asan_opts=handle_sigbus=0 not --crash %run %t 2>&1 | FileCheck %s  // UNSUPPORTED: ios +// Instead of getting a SIGBUS error, we get a SIGSEGV +// XFAIL: freebsd  #include <assert.h>  #include <fcntl.h> @@ -14,6 +16,10 @@  #include <unistd.h>  #include <string> +#ifndef MAP_FILE +#define MAP_FILE 0 +#endif +  char array[4096];  int main(int argc, char **argv) {    int fd = open((std::string(argv[0]) + ".m").c_str(), O_RDWR | O_CREAT, 0700); diff --git a/test/asan/TestCases/Posix/asan-symbolize-bad-path.cc b/test/asan/TestCases/Posix/asan-symbolize-bad-path.cc index 22c03e8ddcedc..3f93122e9099e 100644 --- a/test/asan/TestCases/Posix/asan-symbolize-bad-path.cc +++ b/test/asan/TestCases/Posix/asan-symbolize-bad-path.cc @@ -1,4 +1,4 @@  // Test that asan_symbolize does not hang when provided with an non-existing  // path. -// RUN: echo '#0 0xabcdabcd (%T/bad/path+0x1234)' | %asan_symbolize | FileCheck %s +// RUN: echo '#0 0xabcdabcd (%t/bad/path+0x1234)' | %asan_symbolize | FileCheck %s  // CHECK: #0 0xabcdabcd diff --git a/test/asan/TestCases/Posix/concurrent_overflow.cc b/test/asan/TestCases/Posix/concurrent_overflow.cc index e9b9899c31a20..345b546851ba3 100644 --- a/test/asan/TestCases/Posix/concurrent_overflow.cc +++ b/test/asan/TestCases/Posix/concurrent_overflow.cc @@ -20,11 +20,12 @@ static void *start_routine(void *arg) {  int main(void) {    const int n_threads = 8;    int i, counter = n_threads; -  pthread_t thread; +  pthread_t thread[n_threads];    for (i = 0; i < n_threads; ++i) -    pthread_create(&thread, NULL, &start_routine, (void *)&counter); -  sleep(5); +    pthread_create(&thread[i], NULL, &start_routine, (void *)&counter); +  for (i = 0; i < n_threads; ++i) +    pthread_join(thread[i], NULL);    return 0;  } diff --git a/test/asan/TestCases/Posix/coverage-fork.cc b/test/asan/TestCases/Posix/coverage-fork.cc index da6e3c2c1b383..22d2e35842a83 100644 --- a/test/asan/TestCases/Posix/coverage-fork.cc +++ b/test/asan/TestCases/Posix/coverage-fork.cc @@ -1,6 +1,6 @@  // RUN: %clangxx_asan -fsanitize-coverage=func,trace-pc-guard %s -o %t -// RUN: rm -rf %T/coverage-fork -// RUN: mkdir -p %T/coverage-fork && cd %T/coverage-fork +// RUN: rm -rf %t-dir +// RUN: mkdir -p %t-dir && cd %t-dir  // RUN: %env_asan_opts=coverage=1:verbosity=1 %run %t 2>&1 | FileCheck %s  //  // UNSUPPORTED: android diff --git a/test/asan/TestCases/Posix/coverage-reset.cc b/test/asan/TestCases/Posix/coverage-reset.cc index 201bf8e532527..6d76a309b76f8 100644 --- a/test/asan/TestCases/Posix/coverage-reset.cc +++ b/test/asan/TestCases/Posix/coverage-reset.cc @@ -1,6 +1,6 @@  // RUN: %clangxx_asan -fsanitize-coverage=func,trace-pc-guard -DSHARED %s -shared -o %dynamiclib -fPIC %ld_flags_rpath_so  // RUN: %clangxx_asan -fsanitize-coverage=func,trace-pc-guard %s %ld_flags_rpath_exe -o %t -// RUN: rm -rf %T/coverage-reset && mkdir -p %T/coverage-reset && cd %T/coverage-reset +// RUN: rm -rf %t-dir && mkdir -p %t-dir && cd %t-dir  // RUN: %env_asan_opts=coverage=1:verbosity=1 %run %t 2>&1 | FileCheck %s  //  // UNSUPPORTED: ios diff --git a/test/asan/TestCases/Posix/coverage.cc b/test/asan/TestCases/Posix/coverage.cc index a78560a72a006..12a88402eb5aa 100644 --- a/test/asan/TestCases/Posix/coverage.cc +++ b/test/asan/TestCases/Posix/coverage.cc @@ -1,6 +1,6 @@  // RUN: %clangxx_asan -fsanitize-coverage=func,trace-pc-guard -DSHARED %s -shared -o %dynamiclib -fPIC %ld_flags_rpath_so  // RUN: %clangxx_asan -fsanitize-coverage=func,trace-pc-guard %s %ld_flags_rpath_exe -o %t -// RUN: rm -rf %T/coverage && mkdir -p %T/coverage && cd %T/coverage +// RUN: rm -rf %t-dir && mkdir -p %t-dir && cd %t-dir  // RUN: %env_asan_opts=coverage=1:verbosity=1 %run %t 2>&1         | FileCheck %s --check-prefix=CHECK-main  // RUN: %sancov print coverage.*sancov 2>&1 | FileCheck %s --check-prefix=CHECK-SANCOV1  // RUN: %env_asan_opts=coverage=1:verbosity=1 %run %t foo 2>&1     | FileCheck %s --check-prefix=CHECK-foo @@ -14,7 +14,7 @@  // RUN: %sancov print merged-cov 2>&1 | FileCheck %s --check-prefix=CHECK-SANCOV2  // RUN: %env_asan_opts=coverage=1:verbosity=1 not %run %t foo bar 4    2>&1 | FileCheck %s --check-prefix=CHECK-report  // RUN: %env_asan_opts=coverage=1:verbosity=1 not %run %t foo bar 4 5  2>&1 | FileCheck %s --check-prefix=CHECK-segv -// RUN: rm -r %T/coverage +// RUN: cd .. && rm -rf %t-dir  //  // https://code.google.com/p/address-sanitizer/issues/detail?id=263  // XFAIL: android diff --git a/test/asan/TestCases/Posix/fgets_fputs.cc b/test/asan/TestCases/Posix/fgets_fputs.cc new file mode 100644 index 0000000000000..34c952f2e02ef --- /dev/null +++ b/test/asan/TestCases/Posix/fgets_fputs.cc @@ -0,0 +1,54 @@ +// RUN: %clangxx_asan -g %s -o %t +// RUN: not %run %t 1 2>&1 | FileCheck %s --check-prefix=CHECK-FGETS +// RUN: not %run %t 2 2>&1 | FileCheck %s --check-prefix=CHECK-FPUTS +// RUN: not %run %t 3 2>&1 | FileCheck %s --check-prefix=CHECK-PUTS + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +int test_fgets(const char *testfile) { +  char buf[2]; +  FILE *fp = fopen(testfile, "r"); +  assert(fp); +  fgets(buf, sizeof(buf) + 1, fp); // BOOM +  fclose(fp); +  return 0; +} + +int test_fputs() { +  char buf[1] = {'x'}; // Note: not nul-terminated +  FILE *fp = fopen("/dev/null", "w"); +  assert(fp); +  fputs(buf, fp); // BOOM +  fclose(fp); +  return 0; +} + +int test_puts() { +  char *p = strdup("x"); +  free(p); +  puts(p); // BOOM +  return 0; +} + +int main(int argc, char *argv[]) { +  assert(argc >= 2); +  int testno = argv[1][0] - '0'; +  if (testno == 1) { +    return test_fgets(argv[0]); +  } +  if (testno == 2) +    return test_fputs(); +  if (testno == 3) +    return test_puts(); +  return 1; +} + +// CHECK-FGETS: {{.*ERROR: AddressSanitizer: stack-buffer-overflow}} +// CHECK-FGETS: #{{.*}} in {{(wrap_|__interceptor_)?}}fgets +// CHECK-FPUTS: {{.*ERROR: AddressSanitizer: stack-buffer-overflow}} +// CHECK-FPUTS: #{{.*}} in {{(wrap_|__interceptor_)?}}fputs +// CHECK-PUTS: {{.*ERROR: AddressSanitizer: heap-use-after-free}} +// CHECK-PUTS: #{{.*}} in {{(wrap_|__interceptor_)?}}puts diff --git a/test/asan/TestCases/Posix/fread_fwrite.cc b/test/asan/TestCases/Posix/fread_fwrite.cc index c0629260418a3..640248860179f 100644 --- a/test/asan/TestCases/Posix/fread_fwrite.cc +++ b/test/asan/TestCases/Posix/fread_fwrite.cc @@ -1,6 +1,9 @@  // RUN: %clangxx_asan -g %s -o %t  // RUN: not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-FWRITE  // RUN: not %run %t 1 2>&1 | FileCheck %s --check-prefix=CHECK-FREAD +// +// On FreeBSD stack overflow error instead +// XFAIL: freebsd  #include <stdio.h>  #include <stdlib.h> diff --git a/test/asan/TestCases/Posix/glob.cc b/test/asan/TestCases/Posix/glob.cc index 46d4a0d8d43d0..16b4ace8efc50 100644 --- a/test/asan/TestCases/Posix/glob.cc +++ b/test/asan/TestCases/Posix/glob.cc @@ -4,7 +4,6 @@  //  // RUN: %clangxx_asan -O0 %s -o %t && %run %t %p 2>&1 | FileCheck %s  // RUN: %clangxx_asan -O3 %s -o %t && %run %t %p 2>&1 | FileCheck %s -// XFAIL: arm-linux-gnueabi  #include <assert.h>  #include <glob.h> diff --git a/test/asan/TestCases/Posix/invalid-pointer-pairs-threads.cc b/test/asan/TestCases/Posix/invalid-pointer-pairs-threads.cc index 28be9b59117b8..ee8a1c70cf039 100644 --- a/test/asan/TestCases/Posix/invalid-pointer-pairs-threads.cc +++ b/test/asan/TestCases/Posix/invalid-pointer-pairs-threads.cc @@ -1,7 +1,7 @@  // RUN: %clangxx_asan -O0 %s -pthread -o %t -mllvm -asan-detect-invalid-pointer-pair -// RUN: %env_asan_opts=detect_invalid_pointer_pairs=1 %run %t a 2>&1 | FileCheck %s -check-prefix=OK -allow-empty -// RUN: %env_asan_opts=detect_invalid_pointer_pairs=1 not %run %t b 2>&1 | FileCheck %s -check-prefix=B +// RUN: %env_asan_opts=detect_invalid_pointer_pairs=2 %run %t a 2>&1 | FileCheck %s -check-prefix=OK -allow-empty +// RUN: %env_asan_opts=detect_invalid_pointer_pairs=2 not %run %t b 2>&1 | FileCheck %s -check-prefix=B  // pthread barriers are not available on OS X  // UNSUPPORTED: darwin diff --git a/test/asan/TestCases/Posix/ioctl.cc b/test/asan/TestCases/Posix/ioctl.cc index 6cf9fa8e3cd3b..7269dfddb9b31 100644 --- a/test/asan/TestCases/Posix/ioctl.cc +++ b/test/asan/TestCases/Posix/ioctl.cc @@ -10,6 +10,10 @@  #include <sys/socket.h>  #include <unistd.h> +#if defined(__sun__) && defined(__svr4__) +#include <sys/filio.h> +#endif +  int main(int argc, char **argv) {    int fd = socket(AF_INET, SOCK_DGRAM, 0); diff --git a/test/asan/TestCases/Posix/lto-constmerge-odr.cc b/test/asan/TestCases/Posix/lto-constmerge-odr.cc new file mode 100644 index 0000000000000..9dc1397f6f0e3 --- /dev/null +++ b/test/asan/TestCases/Posix/lto-constmerge-odr.cc @@ -0,0 +1,14 @@ +// RUN: %clangxx_asan -O3 -flto %s -o %t +// RUN: %run %t 2>&1 + +// REQUIRES: lto + +int main(int argc, const char * argv[]) { +  struct { long width, height; } a = {16, 16}; +  struct { long width, height; } b = {16, 16}; + +  // Just to make sure 'a' and 'b' don't get optimized out. +  asm volatile("" : : "r" (&a), "r" (&b)); + +  return 0; +} diff --git a/test/asan/TestCases/Posix/mmap_limit_mb.cc b/test/asan/TestCases/Posix/mmap_limit_mb.cc index 379524121a889..508c03fbcb16b 100644 --- a/test/asan/TestCases/Posix/mmap_limit_mb.cc +++ b/test/asan/TestCases/Posix/mmap_limit_mb.cc @@ -9,7 +9,7 @@  // RUN: %env_asan_opts=mmap_limit_mb=300 not %run %t 500 1000000 2>&1 | FileCheck %s  //  // FIXME: Windows doesn't implement mmap_limit_mb. -// XFAIL: arm-linux-gnueabi,win32 +// XFAIL: win32  #include <assert.h>  #include <stdlib.h> diff --git a/test/asan/TestCases/Posix/no_asan_gen_globals.c b/test/asan/TestCases/Posix/no_asan_gen_globals.c index c686f83ac4a89..994f827974be9 100644 --- a/test/asan/TestCases/Posix/no_asan_gen_globals.c +++ b/test/asan/TestCases/Posix/no_asan_gen_globals.c @@ -1,12 +1,10 @@  // FIXME: https://code.google.com/p/address-sanitizer/issues/detail?id=316  // XFAIL: android -// FIXME: http://llvm.org/bugs/show_bug.cgi?id=22682 -// REQUIRES: asan-64-bits -// Make sure __asan_gen_* strings do not end up in the symbol table. +// Make sure ___asan_gen_* strings do not end up in the symbol table.  // RUN: %clang_asan %s -o %t.exe  // RUN: nm %t.exe | FileCheck %s  int x, y, z;  int main() { return 0; } -// CHECK-NOT: __asan_gen_ +// CHECK-NOT: ___asan_gen_ diff --git a/test/asan/TestCases/Posix/shared-lib-test.cc b/test/asan/TestCases/Posix/shared-lib-test.cc index 305942a0792da..6de6d9fdfe5b2 100644 --- a/test/asan/TestCases/Posix/shared-lib-test.cc +++ b/test/asan/TestCases/Posix/shared-lib-test.cc @@ -6,7 +6,6 @@  // RUN: %clangxx_asan -O2 %s %libdl -o %t && not %run %t 2>&1 | FileCheck %s  // RUN: %clangxx_asan -O3 -DSHARED_LIB %s -fPIC -shared -o %t-so.so  // RUN: %clangxx_asan -O3 %s %libdl -o %t && not %run %t 2>&1 | FileCheck %s -// XFAIL: arm-linux-gnueabi  #if !defined(SHARED_LIB)  #include <dlfcn.h> diff --git a/test/asan/TestCases/Posix/stack-use-after-return.cc b/test/asan/TestCases/Posix/stack-use-after-return.cc index 2da1a0590db78..237c880f8e613 100644 --- a/test/asan/TestCases/Posix/stack-use-after-return.cc +++ b/test/asan/TestCases/Posix/stack-use-after-return.cc @@ -16,9 +16,11 @@  // This test runs out of stack on AArch64.  // UNSUPPORTED: aarch64 +// stack size log lower than expected +// XFAIL: freebsd -// FIXME: Fix this test for dynamic runtime on armhf-linux. -// UNSUPPORTED: armhf-linux && asan-dynamic-runtime +// FIXME: Fix this test for dynamic runtime on arm linux. +// UNSUPPORTED: (arm-linux || armhf-linux) && asan-dynamic-runtime  #include <limits.h>  #include <pthread.h> @@ -95,7 +97,7 @@ int main(int argc, char **argv) {      if (stacksize_check != desired_stack_size) {        fprintf(stderr, "Unable to set stack size to %d, the stack size is %d.\n", -              desired_stack_size, stacksize_check); +              (int)desired_stack_size, (int)stacksize_check);        abort();       }    } diff --git a/test/asan/TestCases/Posix/start-deactivated.cc b/test/asan/TestCases/Posix/start-deactivated.cc index 2870ffb2f4540..736d7f698b17b 100644 --- a/test/asan/TestCases/Posix/start-deactivated.cc +++ b/test/asan/TestCases/Posix/start-deactivated.cc @@ -18,7 +18,6 @@  // RUN: %env_asan_opts=start_deactivated=1 \  // RUN:   ASAN_ACTIVATION_OPTIONS=help=1,handle_segv=0,verbosity=1 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-UNSUPPORTED -// XFAIL: arm-linux-gnueabi  // UNSUPPORTED: ios  // END. diff --git a/test/asan/TestCases/Posix/strndup_oob_test.cc b/test/asan/TestCases/Posix/strndup_oob_test.cc index 7ea0b7a33400e..326ddcfd6b065 100644 --- a/test/asan/TestCases/Posix/strndup_oob_test.cc +++ b/test/asan/TestCases/Posix/strndup_oob_test.cc @@ -7,7 +7,7 @@  // RUN: %clangxx_asan -O3 -xc %s -o %t && not %run %t 2>&1 | FileCheck %s  // Unwind problem on arm: "main" is missing from the allocation stack trace. -// UNSUPPORTED: win32,s390,armv7l-unknown-linux-gnueabihf +// UNSUPPORTED: win32,s390,arm && !fast-unwinder-works  #include <string.h> diff --git a/test/asan/TestCases/Posix/strndup_oob_test2.cc b/test/asan/TestCases/Posix/strndup_oob_test2.cc index 903f5e65f98fb..44df6bda9c839 100644 --- a/test/asan/TestCases/Posix/strndup_oob_test2.cc +++ b/test/asan/TestCases/Posix/strndup_oob_test2.cc @@ -7,7 +7,7 @@  // RUN: %clang_asan -O3 -xc %s -o %t && not %run %t 2>&1 | FileCheck %s  // Unwind problem on arm: "main" is missing from the allocation stack trace. -// UNSUPPORTED: win32,s390,armv7l-unknown-linux-gnueabihf +// UNSUPPORTED: win32,s390,arm && !fast-unwinder-works  #include <string.h> @@ -19,4 +19,4 @@ int main(int argc, char **argv) {    // CHECK: AddressSanitizer: global-buffer-overflow    // CHECK: {{.*}}main {{.*}}.cc:[[@LINE-2]]    return *copy; -}
\ No newline at end of file +} diff --git a/test/asan/TestCases/Windows/coverage-basic.cc b/test/asan/TestCases/Windows/coverage-basic.cc index 918872f18f919..1469e1c30ae34 100644 --- a/test/asan/TestCases/Windows/coverage-basic.cc +++ b/test/asan/TestCases/Windows/coverage-basic.cc @@ -1,5 +1,5 @@ -// RUN: rm -rf %T/coverage-basic -// RUN: mkdir %T/coverage-basic && cd %T/coverage-basic +// RUN: rm -rf %t-dir +// RUN: mkdir %t-dir && cd %t-dir  // RUN: %clangxx_asan -fsanitize-coverage=func %s -o test.exe  // RUN: %env_asan_opts=coverage=1 %run ./test.exe  // diff --git a/test/asan/TestCases/Windows/fuse-lld-globals.cc b/test/asan/TestCases/Windows/fuse-lld-globals.cc new file mode 100644 index 0000000000000..4148d562fb408 --- /dev/null +++ b/test/asan/TestCases/Windows/fuse-lld-globals.cc @@ -0,0 +1,18 @@ +// RUN: %clangxx_asan -fuse-ld=lld -O3 %s -o %t && not %run %t 2>&1 | FileCheck %s + +#include <string.h> +int main(int argc, char **argv) { +  static char XXX[10]; +  static char YYY[10]; +  static char ZZZ[10]; +  memset(XXX, 0, 10); +  memset(YYY, 0, 10); +  memset(ZZZ, 0, 10); +  int res = YYY[argc * 10];  // BOOOM +  // CHECK: {{READ of size 1 at 0x.* thread T0}} +  // CHECK: {{    #0 0x.* in main .*fuse-lld-globals.cc:}}[[@LINE-2]] +  // CHECK: {{0x.* is located 0 bytes to the right of global variable}} +  // CHECK:   {{.*YYY.* of size 10}} +  res += XXX[argc] + ZZZ[argc]; +  return res; +} diff --git a/test/asan/TestCases/Windows/oom.cc b/test/asan/TestCases/Windows/oom.cc index 71a9c2a759a90..4d68c145eca70 100644 --- a/test/asan/TestCases/Windows/oom.cc +++ b/test/asan/TestCases/Windows/oom.cc @@ -8,5 +8,5 @@ int main() {    while (true) {      void *ptr = malloc(200 * 1024 * 1024);  // 200MB    } -// CHECK: allocator is terminating the process instead of returning 0 +// CHECK: SUMMARY: AddressSanitizer: out-of-memory  } diff --git a/test/asan/TestCases/Windows/user-exception.cc b/test/asan/TestCases/Windows/user-exception.cc new file mode 100644 index 0000000000000..4cff23fbc02ff --- /dev/null +++ b/test/asan/TestCases/Windows/user-exception.cc @@ -0,0 +1,36 @@ +// RUN: %clang_cl_asan -O0 %s -Fe%t +// RUN: env ASAN_OPTIONS=handle_segv=0 %run %t 2>&1 | FileCheck %s --check-prefix=USER +// RUN: env ASAN_OPTIONS=handle_segv=1 not %run %t 2>&1 | FileCheck %s --check-prefix=ASAN +// Test the default. +// RUN: not %run %t 2>&1 | FileCheck %s --check-prefix=ASAN + +// This test exits zero when its unhandled exception filter is set. ASan should +// not disturb it when handle_segv=0. + +// USER: in main +// USER: in SEHHandler + +// ASAN: in main +// ASAN: ERROR: AddressSanitizer: access-violation + +#include <windows.h> +#include <stdio.h> + +static long WINAPI SEHHandler(EXCEPTION_POINTERS *info) { +  DWORD exception_code = info->ExceptionRecord->ExceptionCode; +  if (exception_code == EXCEPTION_ACCESS_VIOLATION) { +    fprintf(stderr, "in SEHHandler\n"); +    fflush(stderr); +    TerminateProcess(GetCurrentProcess(), 0); +  } +  return EXCEPTION_CONTINUE_SEARCH; +} + +int main() { +  SetUnhandledExceptionFilter(SEHHandler); +  fprintf(stderr, "in main\n"); +  fflush(stderr); + +  volatile int *p = nullptr; +  *p = 42; +} diff --git a/test/asan/TestCases/alloca_constant_size.cc b/test/asan/TestCases/alloca_constant_size.cc index 57aa315705f94..8910ea9f8d8e2 100644 --- a/test/asan/TestCases/alloca_constant_size.cc +++ b/test/asan/TestCases/alloca_constant_size.cc @@ -6,13 +6,14 @@  #include <stdio.h>  #include <string.h> +#include <stdlib.h>  // MSVC provides _alloca instead of alloca.  #if defined(_MSC_VER) && !defined(alloca)  # define alloca _alloca -#elif defined(__FreeBSD__) || defined(__NetBSD__) -#include <stdlib.h> -#else +#endif + +#if defined(__sun__) && defined(__svr4__)  #include <alloca.h>  #endif diff --git a/test/asan/TestCases/alloca_loop_unpoisoning.cc b/test/asan/TestCases/alloca_loop_unpoisoning.cc index 1efada10979ae..f9d32aafdc8f5 100644 --- a/test/asan/TestCases/alloca_loop_unpoisoning.cc +++ b/test/asan/TestCases/alloca_loop_unpoisoning.cc @@ -15,6 +15,10 @@  # define alloca _alloca  #endif +#if defined(__sun__) && defined(__svr4__) +#include <alloca.h> +#endif +  void *top, *bot;  __attribute__((noinline)) void foo(int len) { diff --git a/test/asan/TestCases/alloca_vla_interact.cc b/test/asan/TestCases/alloca_vla_interact.cc index 4717c9d977ed5..92b0afafc8db7 100644 --- a/test/asan/TestCases/alloca_vla_interact.cc +++ b/test/asan/TestCases/alloca_vla_interact.cc @@ -15,6 +15,10 @@  # define alloca _alloca  #endif +#if defined(__sun__) && defined(__svr4__) +#include <alloca.h> +#endif +  #define RZ 32  __attribute__((noinline)) void foo(int len) { diff --git a/test/asan/TestCases/allocator_returns_null.cc b/test/asan/TestCases/allocator_returns_null.cc deleted file mode 100644 index 8ce002f04d61e..0000000000000 --- a/test/asan/TestCases/allocator_returns_null.cc +++ /dev/null @@ -1,131 +0,0 @@ -// Test the behavior of malloc/calloc/realloc/new when the allocation size is -// more than ASan allocator's max allowed one. -// By default (allocator_may_return_null=0) the process should crash. -// With allocator_may_return_null=1 the allocator should return 0, except the -// operator new(), which should crash anyway (operator new(std::nothrow) should -// return nullptr, indeed). -// -// RUN: %clangxx_asan -O0 %s -o %t -// RUN: not %run %t malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mCRASH -// RUN: %env_asan_opts=allocator_may_return_null=0 not %run %t malloc 2>&1 \ -// RUN:   | FileCheck %s --check-prefix=CHECK-mCRASH -// RUN: %env_asan_opts=allocator_may_return_null=1     %run %t malloc 2>&1 \ -// RUN:   | FileCheck %s --check-prefix=CHECK-mNULL -// RUN: %env_asan_opts=allocator_may_return_null=0 not %run %t calloc 2>&1 \ -// RUN:   | FileCheck %s --check-prefix=CHECK-cCRASH -// RUN: %env_asan_opts=allocator_may_return_null=1     %run %t calloc 2>&1 \ -// RUN:   | FileCheck %s --check-prefix=CHECK-cNULL -// RUN: %env_asan_opts=allocator_may_return_null=0 not %run %t calloc-overflow 2>&1 \ -// RUN:   | FileCheck %s --check-prefix=CHECK-coCRASH -// RUN: %env_asan_opts=allocator_may_return_null=1     %run %t calloc-overflow 2>&1 \ -// RUN:   | FileCheck %s --check-prefix=CHECK-coNULL -// RUN: %env_asan_opts=allocator_may_return_null=0 not %run %t realloc 2>&1 \ -// RUN:   | FileCheck %s --check-prefix=CHECK-rCRASH -// RUN: %env_asan_opts=allocator_may_return_null=1     %run %t realloc 2>&1 \ -// RUN:   | FileCheck %s --check-prefix=CHECK-rNULL -// RUN: %env_asan_opts=allocator_may_return_null=0 not %run %t realloc-after-malloc 2>&1 \ -// RUN:   | FileCheck %s --check-prefix=CHECK-mrCRASH -// RUN: %env_asan_opts=allocator_may_return_null=1     %run %t realloc-after-malloc 2>&1 \ -// RUN:   | FileCheck %s --check-prefix=CHECK-mrNULL -// RUN: %env_asan_opts=allocator_may_return_null=0 not %run %t new 2>&1 \ -// RUN:   | FileCheck %s --check-prefix=CHECK-nCRASH -// RUN: %env_asan_opts=allocator_may_return_null=1 not %run %t new 2>&1 \ -// RUN:   | FileCheck %s --check-prefix=CHECK-nCRASH -// RUN: %env_asan_opts=allocator_may_return_null=0 not %run %t new-nothrow 2>&1 \ -// RUN:   | FileCheck %s --check-prefix=CHECK-nnCRASH -// RUN: %env_asan_opts=allocator_may_return_null=1     %run %t new-nothrow 2>&1 \ -// RUN:   | FileCheck %s --check-prefix=CHECK-nnNULL - -// UNSUPPORTED: win32 - -#include <assert.h> -#include <errno.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <limits> -#include <new> - -int main(int argc, char **argv) { -  // Disable stderr buffering. Needed on Windows. -  setvbuf(stderr, NULL, _IONBF, 0); - -  assert(argc == 2); -  const char *action = argv[1]; -  fprintf(stderr, "%s:\n", action); - -  static const size_t kMaxAllowedMallocSizePlusOne = -#if __LP64__ || defined(_WIN64) -      (1ULL << 40) + 1; -#else -      (3UL << 30) + 1; -#endif - -  void *x = 0; -  if (!strcmp(action, "malloc")) { -    x = malloc(kMaxAllowedMallocSizePlusOne); -  } else if (!strcmp(action, "calloc")) { -    x = calloc((kMaxAllowedMallocSizePlusOne / 4) + 1, 4); -  } else if (!strcmp(action, "calloc-overflow")) { -    volatile size_t kMaxSizeT = std::numeric_limits<size_t>::max(); -    size_t kArraySize = 4096; -    volatile size_t kArraySize2 = kMaxSizeT / kArraySize + 10; -    x = calloc(kArraySize, kArraySize2); -  } else if (!strcmp(action, "realloc")) { -    x = realloc(0, kMaxAllowedMallocSizePlusOne); -  } else if (!strcmp(action, "realloc-after-malloc")) { -    char *t = (char*)malloc(100); -    *t = 42; -    x = realloc(t, kMaxAllowedMallocSizePlusOne); -    assert(*t == 42); -    free(t); -  } else if (!strcmp(action, "new")) { -    x = operator new(kMaxAllowedMallocSizePlusOne); -  } else if (!strcmp(action, "new-nothrow")) { -    x = operator new(kMaxAllowedMallocSizePlusOne, std::nothrow); -  } else { -    assert(0); -  } - -  fprintf(stderr, "errno: %d\n", errno); - -  // The NULL pointer is printed differently on different systems, while (long)0 -  // is always the same. -  fprintf(stderr, "x: %lx\n", (long)x); -  free(x); - -  return x != 0; -} - -// CHECK-mCRASH: malloc: -// CHECK-mCRASH: AddressSanitizer's allocator is terminating the process -// CHECK-cCRASH: calloc: -// CHECK-cCRASH: AddressSanitizer's allocator is terminating the process -// CHECK-coCRASH: calloc-overflow: -// CHECK-coCRASH: AddressSanitizer's allocator is terminating the process -// CHECK-rCRASH: realloc: -// CHECK-rCRASH: AddressSanitizer's allocator is terminating the process -// CHECK-mrCRASH: realloc-after-malloc: -// CHECK-mrCRASH: AddressSanitizer's allocator is terminating the process -// CHECK-nCRASH: new: -// CHECK-nCRASH: AddressSanitizer's allocator is terminating the process -// CHECK-nnCRASH: new-nothrow: -// CHECK-nnCRASH: AddressSanitizer's allocator is terminating the process - -// CHECK-mNULL: malloc: -// CHECK-mNULL: errno: 12 -// CHECK-mNULL: x: 0 -// CHECK-cNULL: calloc: -// CHECK-cNULL: errno: 12 -// CHECK-cNULL: x: 0 -// CHECK-coNULL: calloc-overflow: -// CHECK-coNULL: errno: 12 -// CHECK-coNULL: x: 0 -// CHECK-rNULL: realloc: -// CHECK-rNULL: errno: 12 -// CHECK-rNULL: x: 0 -// CHECK-mrNULL: realloc-after-malloc: -// CHECK-mrNULL: errno: 12 -// CHECK-mrNULL: x: 0 -// CHECK-nnNULL: new-nothrow: -// CHECK-nnNULL: x: 0 diff --git a/test/asan/TestCases/calloc-overflow.cc b/test/asan/TestCases/calloc-overflow.cc new file mode 100644 index 0000000000000..74582378fd2f0 --- /dev/null +++ b/test/asan/TestCases/calloc-overflow.cc @@ -0,0 +1,21 @@ +// RUN: %clangxx_asan -O0 %s -o %t +// RUN: %env_asan_opts=allocator_may_return_null=0 not %run %t 2>&1 | FileCheck %s +// RUN: %env_asan_opts=allocator_may_return_null=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-NULL + +// REQUIRES: stable-runtime + +#include <stdio.h> +#include <stdlib.h> + +int main() { +  void *p = calloc(-1, 1000); +  // CHECK: {{ERROR: AddressSanitizer: calloc parameters overflow: count \* size \(.* \* 1000\) cannot be represented in type size_t}} +  // CHECK: {{#0 0x.* in .*calloc}} +  // CHECK: {{#1 0x.* in main .*calloc-overflow.cc:}}[[@LINE-3]] +  // CHECK: SUMMARY: AddressSanitizer: calloc-overflow + +  printf("calloc returned: %zu\n", (size_t)p); +  // CHECK-NULL: calloc returned: 0 + +  return 0; +} diff --git a/test/asan/TestCases/coverage-and-lsan.cc b/test/asan/TestCases/coverage-and-lsan.cc index 591b4e93fac7b..60851dabb6b7f 100644 --- a/test/asan/TestCases/coverage-and-lsan.cc +++ b/test/asan/TestCases/coverage-and-lsan.cc @@ -2,11 +2,11 @@  //  // RUN: %clangxx_asan -fsanitize-coverage=func,trace-pc-guard %s -o %t  // -// RUN: rm -rf %T/coverage-and-lsan +// RUN: rm -rf %t-dir  // -// RUN: mkdir -p %T/coverage-and-lsan/normal -// RUN: %env_asan_opts=coverage=1:coverage_dir=%T/coverage-and-lsan:verbosity=1 not %run %t 2>&1 | FileCheck %s -// RUN: %sancov print %T/coverage-and-lsan/*.sancov 2>&1 +// RUN: mkdir -p %t-dir +// RUN: %env_asan_opts=coverage=1:coverage_dir=%t-dir:verbosity=1 not %run %t 2>&1 | FileCheck %s +// RUN: %sancov print %t-dir/*.sancov 2>&1  //  // REQUIRES: leak-detection diff --git a/test/asan/TestCases/coverage-disabled.cc b/test/asan/TestCases/coverage-disabled.cc index b225035ee4cae..46a822dff08c1 100644 --- a/test/asan/TestCases/coverage-disabled.cc +++ b/test/asan/TestCases/coverage-disabled.cc @@ -1,12 +1,12 @@  // Test that no data is collected without a runtime flag.  // -// RUN: %clangxx_asan -fsanitize-coverage=func %s -o %t +// RUN: rm -rf %t-dir +// RUN: mkdir -p %t-dir  // -// RUN: rm -rf %T/coverage-disabled +// RUN: %clangxx_asan -fsanitize-coverage=func %s -o %t  // -// RUN: mkdir -p %T/coverage-disabled/normal -// RUN: %env_asan_opts=coverage_direct=0:coverage_dir='"%T/coverage-disabled/normal"':verbosity=1 %run %t -// RUN: not %sancov print %T/coverage-disabled/normal/*.sancov 2>&1 +// RUN: %env_asan_opts=coverage_direct=0:coverage_dir='"%t-dir"':verbosity=1 %run %t +// RUN: not %sancov print %t-dir/*.sancov 2>&1  //  // UNSUPPORTED: android diff --git a/test/asan/TestCases/debug_double_free.cc b/test/asan/TestCases/debug_double_free.cc index c3699b9762d82..44c820b638d61 100644 --- a/test/asan/TestCases/debug_double_free.cc +++ b/test/asan/TestCases/debug_double_free.cc @@ -15,6 +15,9 @@  # else  #  define PTR_FMT "0x%08x"  # endif +// Solaris libc omits the leading 0x. +#elif defined(__sun__) && defined(__svr4__) +# define PTR_FMT "0x%p"  #else  # define PTR_FMT "%p"  #endif diff --git a/test/asan/TestCases/debug_ppc64_mapping.cc b/test/asan/TestCases/debug_ppc64_mapping.cc index 0db7956693c58..a67804023c0cd 100644 --- a/test/asan/TestCases/debug_ppc64_mapping.cc +++ b/test/asan/TestCases/debug_ppc64_mapping.cc @@ -6,9 +6,9 @@  #include <stdio.h>  int main() { -// CHECK-PPC64: || `[{{0x180|0x0a0|0x040}}000000000, {{0x3ff|0x0ff}}fffffffff]` || HighMem    || -// CHECK-PPC64: || `[{{0x130|0x034|0x028}}000000000, {{0x17f|0x09f|0x03f}}fffffffff]` || HighShadow || -// CHECK-PPC64: || `[{{0x120|0x024|0x024}}000000000, {{0x12f|0x033|0x027}}fffffffff]` || ShadowGap  || +// CHECK-PPC64: || `[{{0x200|0x180|0x0a0|0x040}}000000000, {{0x7ff|0x3ff|0x0ff}}fffffffff]` || HighMem    || +// CHECK-PPC64: || `[{{0x140|0x130|0x034|0x028}}000000000, {{0x1ff|0x17f|0x09f|0x03f}}fffffffff]` || HighShadow || +// CHECK-PPC64: || `[{{0x120|0x024|0x024}}000000000, {{0x12f|0x13f|0x033|0x027}}fffffffff]` || ShadowGap  ||  // CHECK-PPC64: || `[{{0x100|0x020}}000000000, {{0x11f|0x023}}fffffffff]`       || LowShadow  ||  // CHECK-PPC64: || `[0x000000000000, {{0x0ff|0x01f}}fffffffff]`       || LowMem     ||  // @@ -19,8 +19,16 @@ int main() {  }  /* - * Three different signatures noted. -Newer kernel: (starting with kernel version 4.?) + * Several different signatures noted. + +Newer kernel: (Fedora starting with kernel version 4.?) +|| `[0x200000000000, 0x7fffffffffff]` || HighMem    || +|| `[0x140000000000, 0x1fffffffffff]` || HighShadow || +|| `[0x120000000000, 0x13ffffffffff]` || ShadowGap  || +|| `[0x100000000000, 0x11ffffffffff]` || LowShadow  || +|| `[0x000000000000, 0x0fffffffffff]` || LowMem     || + +Newer kernel: (Ubuntu starting with kernel version 4.?)  || `[0x180000000000, 0x3fffffffffff]` || HighMem    ||  || `[0x130000000000, 0x17ffffffffff]` || HighShadow ||  || `[0x120000000000, 0x12ffffffffff]` || ShadowGap  || diff --git a/test/asan/TestCases/debug_report.cc b/test/asan/TestCases/debug_report.cc index 34bc06eba62c1..14bb70e9f5937 100644 --- a/test/asan/TestCases/debug_report.cc +++ b/test/asan/TestCases/debug_report.cc @@ -30,6 +30,9 @@ int main() {  # else  #  define PTR_FMT "0x%08x"  # endif +// Solaris libc omits the leading 0x. +#elif defined(__sun__) && defined(__svr4__) +# define PTR_FMT "0x%p"  #else  # define PTR_FMT "%p"  #endif diff --git a/test/asan/TestCases/handle_noreturn_bug.cc b/test/asan/TestCases/handle_noreturn_bug.cc new file mode 100644 index 0000000000000..8c3c66a423d50 --- /dev/null +++ b/test/asan/TestCases/handle_noreturn_bug.cc @@ -0,0 +1,13 @@ +// Regression test: __asan_handle_no_return should unpoison stack even with poison_heap=0. +// RUN: %clangxx_asan -O0 %s -o %t && \ +// RUN: %env_asan_opts=poison_heap=1 %run %t && \ +// RUN: %env_asan_opts=poison_heap=0 %run %t + +#include <sanitizer/asan_interface.h> + +int main(int argc, char **argv) { +  int x[2]; +  int * volatile p = &x[0]; +  __asan_handle_no_return(); +  int volatile z = p[2]; +} diff --git a/test/asan/TestCases/heavy_uar_test.cc b/test/asan/TestCases/heavy_uar_test.cc index 9ad29f079d92f..94df0cefc73b0 100644 --- a/test/asan/TestCases/heavy_uar_test.cc +++ b/test/asan/TestCases/heavy_uar_test.cc @@ -1,12 +1,12 @@  // RUN: %clangxx_asan -O0 %s -o %t && %env_asan_opts=detect_stack_use_after_return=1 not %run %t 2>&1 | FileCheck %s  // RUN: %clangxx_asan -O2 %s -o %t && %env_asan_opts=detect_stack_use_after_return=1 not %run %t 2>&1 | FileCheck %s -// XFAIL: arm-linux-gnueabi,win32 +// XFAIL: win32  // FIXME: Fix this test under GCC.  // REQUIRES: Clang -// FIXME: Fix this test for dynamic runtime on armhf-linux. -// UNSUPPORTED: armhf-linux && asan-dynamic-runtime +// FIXME: Fix this test for dynamic runtime on arm linux. +// UNSUPPORTED: (arm-linux || armhf-linux) && asan-dynamic-runtime  // UNSUPPORTED: ios diff --git a/test/asan/TestCases/intercept-rethrow-exception.cc b/test/asan/TestCases/intercept-rethrow-exception.cc new file mode 100644 index 0000000000000..fa9ea7d3b09ec --- /dev/null +++ b/test/asan/TestCases/intercept-rethrow-exception.cc @@ -0,0 +1,64 @@ +// Regression test for +// https://bugs.llvm.org/show_bug.cgi?id=32434 + +// RUN: %clangxx_asan -O0 %s -o %t +// RUN: %run %t + +#include <assert.h> +#include <exception> +#include <sanitizer/asan_interface.h> + +namespace { + +// Not instrumented because std::rethrow_exception is a [[noreturn]] function, +// for which the compiler would emit a call to __asan_handle_no_return which +// unpoisons the stack. +// We emulate here some code not compiled with asan. This function is not +// [[noreturn]] because the scenario we're emulating doesn't always throw. If it +// were [[noreturn]], the calling code would emit a call to +// __asan_handle_no_return. +void __attribute__((no_sanitize("address"))) +uninstrumented_rethrow_exception(std::exception_ptr const &exc_ptr) { +  std::rethrow_exception(exc_ptr); +} + +char *poisoned1; +char *poisoned2; + +// Create redzones for stack variables in shadow memory and call +// std::rethrow_exception which should unpoison the entire stack. +void create_redzones_and_throw(std::exception_ptr const &exc_ptr) { +  char a[100]; +  poisoned1 = a - 1; +  poisoned2 = a + sizeof(a); +  assert(__asan_address_is_poisoned(poisoned1)); +  assert(__asan_address_is_poisoned(poisoned2)); +  uninstrumented_rethrow_exception(exc_ptr); +} + +} // namespace + +// Check that std::rethrow_exception is intercepted by asan and the interception +// unpoisons the stack. +// If std::rethrow_exception is NOT intercepted, then calls to this function +// from instrumented code will still unpoison the stack because +// std::rethrow_exception is a [[noreturn]] function and any [[noreturn]] +// function call will be instrumented with __asan_handle_no_return. +// However, calls to std::rethrow_exception from UNinstrumented code will not +// unpoison the stack, so we need to intercept std::rethrow_exception to +// unpoison the stack. +int main() { +  // In some implementations of std::make_exception_ptr, e.g. libstdc++ prior to +  // gcc 7, this function calls __cxa_throw. The __cxa_throw is intercepted by +  // asan to unpoison the entire stack; since this test essentially tests that +  // the stack is unpoisoned by a call to std::rethrow_exception, we need to +  // generate the exception_ptr BEFORE we have the local variables poison the +  // stack. +  std::exception_ptr my_exception_ptr = std::make_exception_ptr("up"); + +  try { +    create_redzones_and_throw(my_exception_ptr); +  } catch(char const *) { +    assert(!__asan_region_is_poisoned(poisoned1, poisoned2 - poisoned1 + 1)); +  } +} diff --git a/test/asan/TestCases/invalid-pointer-pairs-compare-errors.cc b/test/asan/TestCases/invalid-pointer-pairs-compare-errors.cc index 82f63359ead79..0690d40d2261a 100644 --- a/test/asan/TestCases/invalid-pointer-pairs-compare-errors.cc +++ b/test/asan/TestCases/invalid-pointer-pairs-compare-errors.cc @@ -1,6 +1,6 @@  // RUN: %clangxx_asan -O0 %s -o %t -mllvm -asan-detect-invalid-pointer-pair -// RUN: %env_asan_opts=detect_invalid_pointer_pairs=1:halt_on_error=0 %run %t 2>&1 | FileCheck %s +// RUN: %env_asan_opts=detect_invalid_pointer_pairs=2:halt_on_error=0 %run %t 2>&1 | FileCheck %s  #include <assert.h>  #include <stdlib.h> @@ -10,8 +10,12 @@ int foo(char *p, char *q) {  }  char global1[100] = {}, global2[100] = {}; +char __attribute__((used)) smallest_global[5] = {};  char small_global[7] = {}; +char __attribute__((used)) little_global[10] = {}; +char __attribute__((used)) medium_global[4000] = {};  char large_global[5000] = {}; +char __attribute__((used)) largest_global[6000] = {};  int main() {    // Heap allocated memory. diff --git a/test/asan/TestCases/invalid-pointer-pairs-compare-null.cc b/test/asan/TestCases/invalid-pointer-pairs-compare-null.cc new file mode 100644 index 0000000000000..9f7f7b6f439d5 --- /dev/null +++ b/test/asan/TestCases/invalid-pointer-pairs-compare-null.cc @@ -0,0 +1,42 @@ +// RUN: %clangxx_asan -O0 %s -o %t -mllvm -asan-detect-invalid-pointer-pair + +// RUN: %env_asan_opts=detect_invalid_pointer_pairs=1 %run %t + +#include <assert.h> +#include <stdlib.h> + +int foo(char *p, char *q) { +  return p <= q; +} + +char global[8192] = {}; +char small_global[7] = {}; + +int main() { +  // Heap allocated memory. +  char *p = (char *)malloc(42); +  int r = foo(p, NULL); +  free(p); + +  p = (char *)malloc(1024); +  foo(NULL, p); +  free(p); + +  p = (char *)malloc(4096); +  foo(p, NULL); +  free(p); + +  // Global variable. +  foo(&global[0], NULL); +  foo(&global[1000], NULL); + +  p = &small_global[0]; +  foo(p, NULL); + +  // Stack variable. +  char stack[10000]; +  foo(&stack[0], NULL); +  foo(NULL, &stack[9000]); + +  return 0; +} diff --git a/test/asan/TestCases/invalid-pointer-pairs-compare-success.cc b/test/asan/TestCases/invalid-pointer-pairs-compare-success.cc index 565d39088340c..d0d92265f0023 100644 --- a/test/asan/TestCases/invalid-pointer-pairs-compare-success.cc +++ b/test/asan/TestCases/invalid-pointer-pairs-compare-success.cc @@ -1,6 +1,6 @@  // RUN: %clangxx_asan -O0 %s -o %t -mllvm -asan-detect-invalid-pointer-pair -// RUN: %env_asan_opts=detect_invalid_pointer_pairs=1 %run %t +// RUN: %env_asan_opts=detect_invalid_pointer_pairs=2 %run %t  #include <assert.h>  #include <stdlib.h> diff --git a/test/asan/TestCases/invalid-pointer-pairs-subtract-errors.cc b/test/asan/TestCases/invalid-pointer-pairs-subtract-errors.cc index 546f61f8184de..20aaebeb48e0c 100644 --- a/test/asan/TestCases/invalid-pointer-pairs-subtract-errors.cc +++ b/test/asan/TestCases/invalid-pointer-pairs-subtract-errors.cc @@ -1,6 +1,6 @@  // RUN: %clangxx_asan -O0 %s -o %t -mllvm -asan-detect-invalid-pointer-pair -// RUN: %env_asan_opts=detect_invalid_pointer_pairs=1:halt_on_error=0 %run %t 2>&1 | FileCheck %s +// RUN: %env_asan_opts=detect_invalid_pointer_pairs=2:halt_on_error=0 %run %t 2>&1 | FileCheck %s  #include <assert.h>  #include <stdlib.h> diff --git a/test/asan/TestCases/invalid-pointer-pairs-subtract-success.cc b/test/asan/TestCases/invalid-pointer-pairs-subtract-success.cc index 4ce48424899d3..7ea120ed5c704 100644 --- a/test/asan/TestCases/invalid-pointer-pairs-subtract-success.cc +++ b/test/asan/TestCases/invalid-pointer-pairs-subtract-success.cc @@ -1,12 +1,12 @@  // RUN: %clangxx_asan -O0 %s -o %t -mllvm -asan-detect-invalid-pointer-pair -// RUN: %env_asan_opts=detect_invalid_pointer_pairs=1 %run %t +// RUN: %env_asan_opts=detect_invalid_pointer_pairs=2 %run %t  #include <assert.h>  #include <stdlib.h>  int bar(char *p, char *q) { -  return p <= q; +  return p - q;  }  char global[10000] = {}; diff --git a/test/asan/TestCases/malloc-no-intercept.c b/test/asan/TestCases/malloc-no-intercept.c index c1442e6cfa907..ca98febed0fb1 100644 --- a/test/asan/TestCases/malloc-no-intercept.c +++ b/test/asan/TestCases/malloc-no-intercept.c @@ -10,6 +10,11 @@  // Conflicts with BIONIC declarations.  // UNSUPPORTED: android +// Inhibit conflicting declaration of memalign on Solaris. +#if defined(__sun__) && defined(__svr4__) +#undef __EXTENSIONS__ +#endif +  #include <stdlib.h>  // For glibc, cause link failures by referencing a nonexistent function. diff --git a/test/asan/TestCases/malloc-size-too-big.cc b/test/asan/TestCases/malloc-size-too-big.cc new file mode 100644 index 0000000000000..f41b7ef75d71b --- /dev/null +++ b/test/asan/TestCases/malloc-size-too-big.cc @@ -0,0 +1,28 @@ +// RUN: %clangxx_asan -O0 %s -o %t +// RUN: %env_asan_opts=allocator_may_return_null=0 not %run %t 2>&1 | FileCheck %s +// RUN: %env_asan_opts=allocator_may_return_null=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-NULL + +// REQUIRES: stable-runtime + +#include <stdio.h> +#include <stdlib.h> + +static const size_t kMaxAllowedMallocSizePlusOne = +#if __LP64__ || defined(_WIN64) +    (1ULL << 40) + 1; +#else +    (3UL << 30) + 1; +#endif + +int main() { +  void *p = malloc(kMaxAllowedMallocSizePlusOne); +  // CHECK: {{ERROR: AddressSanitizer: requested allocation size .* \(.* after adjustments for alignment, red zones etc\.\) exceeds maximum supported size}} +  // CHECK: {{#0 0x.* in .*malloc}} +  // CHECK: {{#1 0x.* in main .*malloc-size-too-big.cc:}}[[@LINE-3]] +  // CHECK: SUMMARY: AddressSanitizer: allocation-size-too-big + +  printf("malloc returned: %zu\n", (size_t)p); +  // CHECK-NULL: malloc returned: 0 + +  return 0; +} diff --git a/test/asan/TestCases/non-executable-pc.cpp b/test/asan/TestCases/non-executable-pc.cpp index 6ef40540b0ace..60e900b87160f 100644 --- a/test/asan/TestCases/non-executable-pc.cpp +++ b/test/asan/TestCases/non-executable-pc.cpp @@ -3,7 +3,10 @@  // RUN: not %run %t n 2>&1 | FileCheck %s -check-prefix=CHECK -check-prefix=NON_EXEC  // Not every OS lists every memory region in MemoryMappingLayout. -// REQUIRES: linux || freebsd || netbsd +// This is limited to x86_64 because some architectures (e.g. the s390 before +// the z14) don't support NX mappings and others like PowerPC use function +// descriptors. +// REQUIRES: x86-target-arch && (linux || freebsd || netbsd)  #include <assert.h> @@ -20,12 +23,6 @@ int main(int argc, char **argv) {    }    func(); -  // x86 reports the SEGV with both address=X and pc=X. -  // On PowerPC64 ELFv1, the pointer is taken to be a function-descriptor -  // pointer out of which three 64-bit quantities are read. This will SEGV, but -  // the compiler is free to choose the order. As a result, the address is -  // either X, X+0x8 or X+0x10. The pc is still in main() because it has not -  // actually made the call when the faulting access occurs.    // CHECK: DEADLYSIGNAL    // CHECK: {{AddressSanitizer: (SEGV|access-violation).*(address|pc) }}    // NON_EXEC: PC is at a non-executable region. Maybe a wild jump? diff --git a/test/asan/TestCases/null_deref.cc b/test/asan/TestCases/null_deref.cc index 04576b40eb240..222c526fdc134 100644 --- a/test/asan/TestCases/null_deref.cc +++ b/test/asan/TestCases/null_deref.cc @@ -15,10 +15,10 @@ void NullDeref(int *ptr) {    ptr[10]++;  // BOOM    // atos on Mac cannot extract the symbol name correctly. Also, on FreeBSD 9.2    // the demangling function rejects local names with 'L' in front of them. -  // CHECK: {{    #0 0x.* in .*NullDeref.*null_deref.cc:}}[[@LINE-3]] +  // CHECK: {{    #0 0x.* in .*NullDeref.*null_deref.cc}}  }  int main() {    NullDeref((int*)0); -  // CHECK: {{    #1 0x.* in main.*null_deref.cc:}}[[@LINE-1]] +  // CHECK: {{    #1 0x.* in main.*null_deref.cc}}    // CHECK: AddressSanitizer can not provide additional info.  } diff --git a/test/asan/TestCases/printf-4.c b/test/asan/TestCases/printf-4.c index 5a883fe99efd7..70f4073cc496a 100644 --- a/test/asan/TestCases/printf-4.c +++ b/test/asan/TestCases/printf-4.c @@ -2,8 +2,9 @@  // RUN: %env_asan_opts=check_printf=1 not %run %t 2>&1 | FileCheck --check-prefix=CHECK-ON %s  // RUN: not %run %t 2>&1 | FileCheck --check-prefix=CHECK-ON %s -// FIXME: sprintf is not intercepted on Windows yet. -// XFAIL: win32 +// FIXME: sprintf is not intercepted on Windows yet. But this test can +// pass if sprintf calls memmove, which is intercepted, so we can't XFAIL it. +// UNSUPPORTED: win32  #include <stdio.h>  int main() { diff --git a/test/asan/TestCases/scariness_score_test.cc b/test/asan/TestCases/scariness_score_test.cc index 171bea9ee1917..fb174eb52b2b0 100644 --- a/test/asan/TestCases/scariness_score_test.cc +++ b/test/asan/TestCases/scariness_score_test.cc @@ -115,7 +115,7 @@ void DoubleFree() {  }  void StackOverflow(int Idx) { -  int some_stack[10000]; +  int some_stack[256];    static volatile int *x;    x = &some_stack[0];    if (Idx > 0) diff --git a/test/asan/TestCases/strcat-overlap.cc b/test/asan/TestCases/strcat-overlap.cc new file mode 100644 index 0000000000000..89991fbd78816 --- /dev/null +++ b/test/asan/TestCases/strcat-overlap.cc @@ -0,0 +1,54 @@ +// RUN: %clangxx_asan -O0 %s -o %t +// RUN: not %run %t 2>&1 | FileCheck %s +// RUN: echo "interceptor_via_fun:bad_function" > %t.supp +// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t +// RUN: echo "interceptor_name:strcat" > %t.supp +// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t +// +// RUN: %clangxx_asan -O1 %s -o %t +// RUN: not %run %t 2>&1 | FileCheck %s +// RUN: echo "interceptor_via_fun:bad_function" > %t.supp +// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t +// RUN: echo "interceptor_name:strcat" > %t.supp +// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t +// +// RUN: %clangxx_asan -O2 %s -o %t +// RUN: not %run %t 2>&1 | FileCheck %s +// RUN: echo "interceptor_via_fun:bad_function" > %t.supp +// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t +// RUN: echo "interceptor_name:strcat" > %t.supp +// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t +// +// RUN: %clangxx_asan -O3 %s -o %t +// RUN: not %run %t 2>&1 | FileCheck %s +// RUN: echo "interceptor_via_fun:bad_function" > %t.supp +// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t +// RUN: echo "interceptor_name:strcat" > %t.supp +// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t + +// This test when run with suppressions invokes undefined +// behavior which can cause all sorts of bad things to happen +// depending on how strcat() is implemented. For now only run +// on platforms where we know the test passes. +// REQUIRES: x86_64h-darwin || x86_64-darwin || i386-darwin || x86_64-linux || i386-linux +// UNSUPPORTED: win32 +// UNSUPPORTED: android + +#include <string.h> + + +// Don't inline function otherwise stacktrace changes. +__attribute__((noinline)) void bad_function() { +  char buffer[] = "hello\0XXX"; +  // CHECK: strcat-param-overlap: memory ranges +  // CHECK: [{{0x.*,[ ]*0x.*}}) and [{{0x.*,[ ]*0x.*}}) overlap +  // CHECK: {{#0 0x.* in .*strcat}} +  // CHECK: {{#1 0x.* in bad_function.*strcat-overlap.cc:}}[[@LINE+2]] +  // CHECK: {{#2 0x.* in main .*strcat-overlap.cc:}}[[@LINE+5]] +  strcat(buffer, buffer + 1); // BOOM +} + +int main(int argc, char **argv) { +  bad_function(); +  return 0; +} diff --git a/test/asan/TestCases/strcpy-overlap.cc b/test/asan/TestCases/strcpy-overlap.cc new file mode 100644 index 0000000000000..53b77e13d91ea --- /dev/null +++ b/test/asan/TestCases/strcpy-overlap.cc @@ -0,0 +1,48 @@ +// RUN: %clangxx_asan -O0 %s -o %t +// RUN: not %run %t 2>&1 | FileCheck %s +// RUN: echo "interceptor_via_fun:bad_function" > %t.supp +// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t +// RUN: echo "interceptor_name:strcpy" > %t.supp +// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t +// +// RUN: %clangxx_asan -O1 %s -o %t +// RUN: not %run %t 2>&1 | FileCheck %s +// RUN: echo "interceptor_via_fun:bad_function" > %t.supp +// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t +// RUN: echo "interceptor_name:strcpy" > %t.supp +// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t +// +// RUN: %clangxx_asan -O2 %s -o %t +// RUN: not %run %t 2>&1 | FileCheck %s +// RUN: echo "interceptor_via_fun:bad_function" > %t.supp +// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t +// RUN: echo "interceptor_name:strcpy" > %t.supp +// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t +// +// RUN: %clangxx_asan -O3 %s -o %t +// RUN: not %run %t 2>&1 | FileCheck %s +// RUN: echo "interceptor_via_fun:bad_function" > %t.supp +// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t +// RUN: echo "interceptor_name:strcpy" > %t.supp +// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t + +// UNSUPPORTED: android + +#include <string.h> + + +// Don't inline function otherwise stacktrace changes. +__attribute__((noinline)) void bad_function() { +  char buffer[] = "hello"; +  // CHECK: strcpy-param-overlap: memory ranges +  // CHECK: [{{0x.*,[ ]*0x.*}}) and [{{0x.*,[ ]*0x.*}}) overlap +  // CHECK: {{#0 0x.* in .*strcpy}} +  // CHECK: {{#1 0x.* in bad_function.*strcpy-overlap.cc:}}[[@LINE+2]] +  // CHECK: {{#2 0x.* in main .*strcpy-overlap.cc:}}[[@LINE+5]] +  strcpy(buffer, buffer + 1); // BOOM +} + +int main(int argc, char **argv) { +  bad_function(); +  return 0; +} diff --git a/test/asan/TestCases/strdup_oob_test.cc b/test/asan/TestCases/strdup_oob_test.cc index 60c5ef12a4735..e251dfcb43611 100644 --- a/test/asan/TestCases/strdup_oob_test.cc +++ b/test/asan/TestCases/strdup_oob_test.cc @@ -7,7 +7,7 @@  // RUN: %clangxx_asan -O3 -xc %s -o %t && not %run %t 2>&1 | FileCheck %s  // Unwind problem on arm: "main" is missing from the allocation stack trace. -// UNSUPPORTED: armv7l-unknown-linux-gnueabihf +// REQUIRES: (arm-target-arch || armhf-target-arch), fast-unwinder-works  // FIXME: We fail to intercept strdup with the dynamic WinASan RTL, so it's not  // in the stack trace. diff --git a/test/asan/TestCases/strncat-overlap.cc b/test/asan/TestCases/strncat-overlap.cc new file mode 100644 index 0000000000000..959b783d263f8 --- /dev/null +++ b/test/asan/TestCases/strncat-overlap.cc @@ -0,0 +1,48 @@ +// RUN: %clangxx_asan -O0 %s -o %t +// RUN: not %run %t 2>&1 | FileCheck %s +// RUN: echo "interceptor_via_fun:bad_function" > %t.supp +// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t +// RUN: echo "interceptor_name:strncat" > %t.supp +// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t +// +// RUN: %clangxx_asan -O1 %s -o %t +// RUN: not %run %t 2>&1 | FileCheck %s +// RUN: echo "interceptor_via_fun:bad_function" > %t.supp +// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t +// RUN: echo "interceptor_name:strncat" > %t.supp +// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t +// +// RUN: %clangxx_asan -O2 %s -o %t +// RUN: not %run %t 2>&1 | FileCheck %s +// RUN: echo "interceptor_via_fun:bad_function" > %t.supp +// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t +// RUN: echo "interceptor_name:strncat" > %t.supp +// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t +// +// RUN: %clangxx_asan -O3 %s -o %t +// RUN: not %run %t 2>&1 | FileCheck %s +// RUN: echo "interceptor_via_fun:bad_function" > %t.supp +// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t +// RUN: echo "interceptor_name:strncat" > %t.supp +// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t + +// UNSUPPORTED: android + +#include <string.h> + + +// Don't inline function otherwise stacktrace changes. +__attribute__((noinline)) void bad_function() { +  char buffer[] = "hello\0XXX"; +  // CHECK: strncat-param-overlap: memory ranges +  // CHECK: [{{0x.*,[ ]*0x.*}}) and [{{0x.*,[ ]*0x.*}}) overlap +  // CHECK: {{#0 0x.* in .*strncat}} +  // CHECK: {{#1 0x.* in bad_function.*strncat-overlap.cc:}}[[@LINE+2]] +  // CHECK: {{#2 0x.* in main .*strncat-overlap.cc:}}[[@LINE+5]] +  strncat(buffer, buffer + 1, 3); // BOOM +} + +int main(int argc, char **argv) { +  bad_function(); +  return 0; +} diff --git a/test/asan/TestCases/strncpy-overlap.cc b/test/asan/TestCases/strncpy-overlap.cc new file mode 100644 index 0000000000000..d7052cb49dc9a --- /dev/null +++ b/test/asan/TestCases/strncpy-overlap.cc @@ -0,0 +1,48 @@ +// RUN: %clangxx_asan -O0 %s -o %t +// RUN: not %run %t 2>&1 | FileCheck %s +// RUN: echo "interceptor_via_fun:bad_function" > %t.supp +// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t +// RUN: echo "interceptor_name:strncpy" > %t.supp +// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t +// +// RUN: %clangxx_asan -O1 %s -o %t +// RUN: not %run %t 2>&1 | FileCheck %s +// RUN: echo "interceptor_via_fun:bad_function" > %t.supp +// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t +// RUN: echo "interceptor_name:strncpy" > %t.supp +// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t +// +// RUN: %clangxx_asan -O2 %s -o %t +// RUN: not %run %t 2>&1 | FileCheck %s +// RUN: echo "interceptor_via_fun:bad_function" > %t.supp +// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t +// RUN: echo "interceptor_name:strncpy" > %t.supp +// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t +// +// RUN: %clangxx_asan -O3 %s -o %t +// RUN: not %run %t 2>&1 | FileCheck %s +// RUN: echo "interceptor_via_fun:bad_function" > %t.supp +// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t +// RUN: echo "interceptor_name:strncpy" > %t.supp +// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t + +// UNSUPPORTED: android + +#include <string.h> + + +// Don't inline function otherwise stacktrace changes. +__attribute__((noinline)) void bad_function() { +  char buffer[] = "hello"; +  // CHECK: strncpy-param-overlap: memory ranges +  // CHECK: [{{0x.*,[ ]*0x.*}}) and [{{0x.*,[ ]*0x.*}}) overlap +  // CHECK: {{#0 0x.* in .*strncpy}} +  // CHECK: {{#1 0x.* in bad_function.*strncpy-overlap.cc:}}[[@LINE+2]] +  // CHECK: {{#2 0x.* in main .*strncpy-overlap.cc:}}[[@LINE+5]] +  strncpy(buffer, buffer + 1, 5); // BOOM +} + +int main(int argc, char **argv) { +  bad_function(); +  return 0; +} diff --git a/test/asan/TestCases/suppressions-exec-relative-location.cc b/test/asan/TestCases/suppressions-exec-relative-location.cc index d4e214d35a0ed..d7497566a8c39 100644 --- a/test/asan/TestCases/suppressions-exec-relative-location.cc +++ b/test/asan/TestCases/suppressions-exec-relative-location.cc @@ -4,15 +4,15 @@  // If the executable is started from a different location, we should still  // find the suppression file located relative to the location of the executable. -// RUN: rm -rf %T/suppressions-exec-relative-location -// RUN: mkdir -p %T/suppressions-exec-relative-location -// RUN: %clangxx_asan -O0 %s -o %T/suppressions-exec-relative-location/exec +// RUN: rm -rf %t-dir +// RUN: mkdir -p %t-dir +// RUN: %clangxx_asan -O0 %s -o %t-dir/exec  // RUN: echo "interceptor_via_fun:crash_function" > \ -// RUN:   %T/suppressions-exec-relative-location/supp.txt +// RUN:   %t-dir/supp.txt  // RUN: %env_asan_opts=suppressions='"supp.txt"' \ -// RUN:   %run %T/suppressions-exec-relative-location/exec 2>&1 | \ +// RUN:   %run %t-dir/exec 2>&1 | \  // RUN:   FileCheck --check-prefix=CHECK-IGNORE %s -// RUN: rm -rf %T/suppressions-exec-relative-location +// RUN: rm -rf %t-dir  // If the wrong absolute path is given, we don't try to construct  // a relative path with it. diff --git a/test/asan/TestCases/suppressions-library.cc b/test/asan/TestCases/suppressions-library.cc index e95d339168ed8..39ede0840105d 100644 --- a/test/asan/TestCases/suppressions-library.cc +++ b/test/asan/TestCases/suppressions-library.cc @@ -7,7 +7,7 @@  // FIXME: Remove usage of backticks around basename below.  // REQUIRES: shell -// RUN: echo "interceptor_via_lib:"`basename %dynamiclib` > %t.supp +// RUN: echo "interceptor_via_lib:"%xdynamiclib_filename > %t.supp  // RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t 2>&1 | FileCheck --check-prefix=CHECK-IGNORE %s  // XFAIL: android diff --git a/test/asan/TestCases/throw_invoke_test.cc b/test/asan/TestCases/throw_invoke_test.cc index e6e91d1879cb4..bbfa1c7b95cae 100644 --- a/test/asan/TestCases/throw_invoke_test.cc +++ b/test/asan/TestCases/throw_invoke_test.cc @@ -1,5 +1,5 @@  // RUN: %clangxx_asan %s -o %t && %run %t -// RUN: %clangxx_asan %s -o %t -stdlib=libstdc++ -static-libstdc++ && %run %t +// RUN: %clangxx_asan %s -o %t %linux_static_libstdcplusplus && %run %t  #include <stdio.h>  static volatile int zero = 0; diff --git a/test/asan/TestCases/verbose-log-path_test.cc b/test/asan/TestCases/verbose-log-path_test.cc index 3c3db0883f616..8088ff9247611 100644 --- a/test/asan/TestCases/verbose-log-path_test.cc +++ b/test/asan/TestCases/verbose-log-path_test.cc @@ -1,12 +1,13 @@ -// RUN: %clangxx_asan %s -o %T/verbose-log-path_test-binary +// RUN: rm -rf %t-dir && mkdir -p %t-dir +// RUN: %clangxx_asan %s -o %t-dir/verbose-log-path_test-binary  // The glob below requires bash.  // REQUIRES: shell  // Good log_path. -// RUN: rm -f %T/asan.log.* -// RUN: %env_asan_opts=log_path=%T/asan.log:log_exe_name=1 not %run %T/verbose-log-path_test-binary 2> %t.out -// RUN: FileCheck %s --check-prefix=CHECK-ERROR < %T/asan.log.verbose-log-path_test-binary.* +// RUN: rm -f %t-dir/asan.log.* +// RUN: %env_asan_opts=log_path=%t-dir/asan.log:log_exe_name=1 not %run %t-dir/verbose-log-path_test-binary 2> %t.out +// RUN: FileCheck %s --check-prefix=CHECK-ERROR < %t-dir/asan.log.verbose-log-path_test-binary.*  // FIXME: only FreeBSD, NetBSD and Linux have verbose log paths now.  // XFAIL: win32,android diff --git a/test/asan/lit.cfg b/test/asan/lit.cfg index 4a08a7b475a2f..f8994d069ad87 100644 --- a/test/asan/lit.cfg +++ b/test/asan/lit.cfg @@ -48,8 +48,7 @@ config.substitutions.append(('%env_asan_opts=',  # Setup source root.  config.test_source_root = os.path.dirname(__file__) -# There is no libdl on FreeBSD. -if config.host_os != 'FreeBSD': +if config.host_os not in ['FreeBSD', 'NetBSD']:    libdl_flag = "-ldl"  else:    libdl_flag = "" @@ -102,7 +101,7 @@ config.substitutions.append( ("%clang ", build_invocation(target_cflags)) )  config.substitutions.append( ("%clangxx ", build_invocation(target_cxxflags)) )  config.substitutions.append( ("%clang_asan ", build_invocation(clang_asan_cflags)) )  config.substitutions.append( ("%clangxx_asan ", build_invocation(clang_asan_cxxflags)) ) -config.substitutions.append( ("%shared_libasan", "libclang_rt.asan-%s.so" % config.target_arch)) +config.substitutions.append( ("%shared_libasan", "libclang_rt.asan%s.so" % config.target_suffix))  if config.asan_dynamic:    config.substitutions.append( ("%clang_asan_static ", build_invocation(clang_asan_static_cflags)) )    config.substitutions.append( ("%clangxx_asan_static ", build_invocation(clang_asan_static_cxxflags)) ) @@ -125,7 +124,7 @@ if platform.system() == 'Windows':    clang_cl_asan_invocation = clang_cl_asan_invocation.replace("clang.exe","clang-cl.exe")    config.substitutions.append( ("%clang_cl_asan ", clang_cl_asan_invocation) ) -  base_lib = os.path.join(config.compiler_rt_libdir, "clang_rt.asan%%s-%s.lib" % config.target_arch) +  base_lib = os.path.join(config.compiler_rt_libdir, "clang_rt.asan%%s%s.lib" % config.target_suffix)    config.substitutions.append( ("%asan_lib", base_lib % "") )    config.substitutions.append( ("%asan_cxx_lib", base_lib % "_cxx") )    config.substitutions.append( ("%asan_dll_thunk", base_lib % "_dll_thunk") ) @@ -169,7 +168,7 @@ config.substitutions.append( ("%libdl", libdl_flag) )  config.available_features.add("asan-" + config.bits + "-bits")  # Fast unwinder doesn't work with Thumb -if re.search('mthumb', config.target_cflags) is not None: +if re.search('mthumb', config.target_cflags) is None:    config.available_features.add('fast-unwinder-works')  # Turn on leak detection on 64-bit Linux. @@ -209,8 +208,11 @@ else:    config.substitutions.append(('%pie', '-pie'))  # Only run the tests on supported OSs. -if config.host_os not in ['Linux', 'Darwin', 'FreeBSD', 'Windows']: +if config.host_os not in ['Linux', 'Darwin', 'FreeBSD', 'SunOS', 'Windows', 'NetBSD']:    config.unsupported = True -if config.host_os == 'Darwin' and config.target_arch in ["x86_64", "x86_64h"]: -  config.parallelism_group = "darwin-64bit-sanitizer" +if config.host_os == 'Darwin': +  if config.target_arch in ["x86_64", "x86_64h"]: +    config.parallelism_group = "darwin-64bit-sanitizer" +  elif config.apple_platform != "osx" and not config.apple_platform.endswith("sim"): +    config.parallelism_group = "darwin-ios-device-sanitizer" diff --git a/test/asan/lit.site.cfg.in b/test/asan/lit.site.cfg.in index 6c8f882bcc2c7..6282fd881e5d5 100644 --- a/test/asan/lit.site.cfg.in +++ b/test/asan/lit.site.cfg.in @@ -5,8 +5,7 @@ config.name_suffix = "@ASAN_TEST_CONFIG_SUFFIX@"  config.target_cflags = "@ASAN_TEST_TARGET_CFLAGS@"  config.clang = "@ASAN_TEST_TARGET_CC@"  config.bits = "@ASAN_TEST_BITS@" -config.ios = @ASAN_TEST_IOS_PYBOOL@ -config.iossim = @ASAN_TEST_IOSSIM_PYBOOL@ +config.apple_platform = "@ASAN_TEST_APPLE_PLATFORM@"  config.asan_dynamic = @ASAN_TEST_DYNAMIC@  config.target_arch = "@ASAN_TEST_TARGET_ARCH@" diff --git a/test/builtins/CMakeLists.txt b/test/builtins/CMakeLists.txt index cabf767223cce..a9199ebf10df9 100644 --- a/test/builtins/CMakeLists.txt +++ b/test/builtins/CMakeLists.txt @@ -26,6 +26,11 @@ foreach(arch ${BUILTIN_SUPPORTED_ARCH})      string(REPLACE ";" " " BUILTINS_TEST_TARGET_CFLAGS "${BUILTINS_TEST_TARGET_CFLAGS}")    endif() +  if (${arch} STREQUAL "riscv32") +    list(APPEND BUILTINS_TEST_TARGET_CFLAGS -fforce-enable-int128) +    string(REPLACE ";" " " BUILTINS_TEST_TARGET_CFLAGS "${BUILTINS_TEST_TARGET_CFLAGS}") +  endif() +    string(TOUPPER ${arch} ARCH_UPPER_CASE)    set(CONFIG_NAME ${ARCH_UPPER_CASE}${OS_NAME}Config)    configure_lit_site_cfg( diff --git a/test/builtins/TestCases/Darwin/os_version_check_test.c b/test/builtins/TestCases/Darwin/os_version_check_test.c index 2692cd37edce4..bae1f3255065c 100644 --- a/test/builtins/TestCases/Darwin/os_version_check_test.c +++ b/test/builtins/TestCases/Darwin/os_version_check_test.c @@ -1,4 +1,4 @@ -// RUN: %clang %s -o %t -mmacosx-version-min=10.5 -framework CoreFoundation -DMAJOR=%macos_version_major -DMINOR=%macos_version_minor -DSUBMINOR=%macos_version_subminor +// RUN: %clang %s -o %t -mmacosx-version-min=10.6 -framework CoreFoundation -DMAJOR=%macos_version_major -DMINOR=%macos_version_minor -DSUBMINOR=%macos_version_subminor  // RUN: %run %t  int __isOSVersionAtLeast(int Major, int Minor, int Subminor); diff --git a/test/builtins/TestCases/Darwin/os_version_check_test_no_core_foundation.c b/test/builtins/TestCases/Darwin/os_version_check_test_no_core_foundation.c index 4e0da35cd12db..90c798f6c55f3 100644 --- a/test/builtins/TestCases/Darwin/os_version_check_test_no_core_foundation.c +++ b/test/builtins/TestCases/Darwin/os_version_check_test_no_core_foundation.c @@ -1,4 +1,4 @@ -// RUN: %clang %s -o %t -mmacosx-version-min=10.5 +// RUN: %clang %s -o %t -mmacosx-version-min=10.6  // RUN: %run %t  int __isOSVersionAtLeast(int Major, int Minor, int Subminor); diff --git a/test/builtins/Unit/lit.cfg b/test/builtins/Unit/lit.cfg index 0e17e479e6b62..4b63948b5ef6e 100644 --- a/test/builtins/Unit/lit.cfg +++ b/test/builtins/Unit/lit.cfg @@ -26,12 +26,12 @@ config.test_source_root = os.path.dirname(__file__)  # Path to the static library  is_msvc = get_required_attr(config, "builtins_is_msvc")  if is_msvc: -  base_lib = os.path.join(config.compiler_rt_libdir, "clang_rt.builtins-%s.lib " -                          % config.target_arch) +  base_lib = os.path.join(config.compiler_rt_libdir, "clang_rt.builtins%s.lib " +                          % config.target_suffix)    config.substitutions.append( ("%librt ", base_lib) )  else: -  base_lib = os.path.join(config.compiler_rt_libdir, "libclang_rt.builtins-%s.a" -                          % config.target_arch) +  base_lib = os.path.join(config.compiler_rt_libdir, "libclang_rt.builtins%s.a" +                          % config.target_suffix)    config.substitutions.append( ("%librt ", base_lib + ' -lc -lm ') )  builtins_source_dir = os.path.join( diff --git a/test/builtins/Unit/riscv/mulsi3_test.c b/test/builtins/Unit/riscv/mulsi3_test.c new file mode 100644 index 0000000000000..9033004f11dd8 --- /dev/null +++ b/test/builtins/Unit/riscv/mulsi3_test.c @@ -0,0 +1,119 @@ +// REQUIRES-ANY: riscv32-target-arch +// RUN: %clang_builtins %s %librt -o %t && %run %t +//===-- mulsi3_test.c - Test __mulsi3 -------------------------------------===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file tests __mulsi3 for the compiler_rt library. +// +//===----------------------------------------------------------------------===// + +#include "int_lib.h" +#include <stdio.h> +#include <limits.h> + +#if !defined(__riscv_mul) && __riscv_xlen == 32 +// Based on mulsi3_test.c + +COMPILER_RT_ABI si_int __mulsi3(si_int a, si_int b); + +int test__mulsi3(si_int a, si_int b, si_int expected) +{ +    si_int x = __mulsi3(a, b); +    if (x != expected) +        printf("error in __mulsi3: %d * %d = %d, expected %d\n", +               a, b, __mulsi3(a, b), expected); +    return x != expected; +} +#endif + +int main() +{ +#if !defined(__riscv_mul) && __riscv_xlen == 32 +    if (test__mulsi3(0, 0, 0)) +        return 1; +    if (test__mulsi3(0, 1, 0)) +        return 1; +    if (test__mulsi3(1, 0, 0)) +        return 1; +    if (test__mulsi3(0, 10, 0)) +        return 1; +    if (test__mulsi3(10, 0, 0)) +        return 1; +    if (test__mulsi3(0, INT_MAX, 0)) +        return 1; +    if (test__mulsi3(INT_MAX, 0, 0)) +        return 1; + +    if (test__mulsi3(0, -1, 0)) +        return 1; +    if (test__mulsi3(-1, 0, 0)) +        return 1; +    if (test__mulsi3(0, -10, 0)) +        return 1; +    if (test__mulsi3(-10, 0, 0)) +        return 1; +    if (test__mulsi3(0, INT_MIN, 0)) +        return 1; +    if (test__mulsi3(INT_MIN, 0, 0)) +        return 1; + +    if (test__mulsi3(1, 1, 1)) +        return 1; +    if (test__mulsi3(1, 10, 10)) +        return 1; +    if (test__mulsi3(10, 1, 10)) +        return 1; +    if (test__mulsi3(1, INT_MAX, INT_MAX)) +        return 1; +    if (test__mulsi3(INT_MAX, 1, INT_MAX)) +        return 1; + +    if (test__mulsi3(1, -1, -1)) +        return 1; +    if (test__mulsi3(1, -10, -10)) +        return 1; +    if (test__mulsi3(-10, 1, -10)) +        return 1; +    if (test__mulsi3(1, INT_MIN, INT_MIN)) +        return 1; +    if (test__mulsi3(INT_MIN, 1, INT_MIN)) +        return 1; + +    if (test__mulsi3(46340, 46340, 2147395600)) +        return 1; +    if (test__mulsi3(-46340, 46340, -2147395600)) +        return 1; +    if (test__mulsi3(46340, -46340, -2147395600)) +        return 1; +    if (test__mulsi3(-46340, -46340, 2147395600)) +        return 1; + +    if (test__mulsi3(4194303, 8192, 34359730176)) +        return 1; +    if (test__mulsi3(-4194303, 8192, -34359730176)) +        return 1; +    if (test__mulsi3(4194303, -8192, -34359730176)) +        return 1; +    if (test__mulsi3(-4194303, -8192, 34359730176)) +        return 1; + +    if (test__mulsi3(8192, 4194303, 34359730176)) +        return 1; +    if (test__mulsi3(-8192, 4194303, -34359730176)) +        return 1; +    if (test__mulsi3(8192, -4194303, -34359730176)) +        return 1; +    if (test__mulsi3(-8192, -4194303, 34359730176)) +        return 1; +#else +    printf("skipped\n"); +#endif + +    return 0; +} diff --git a/test/cfi/CMakeLists.txt b/test/cfi/CMakeLists.txt index c7fadde530954..4dbbf1759fcca 100644 --- a/test/cfi/CMakeLists.txt +++ b/test/cfi/CMakeLists.txt @@ -1,6 +1,6 @@  set(CFI_TESTSUITES) -macro (add_cfi_test_suites lld thinlto) +macro (add_cfi_test_suites lld thinlto newpm)    set(suffix)    if (${lld})      set(suffix ${suffix}-lld) @@ -8,10 +8,14 @@ macro (add_cfi_test_suites lld thinlto)    if (${thinlto})      set(suffix ${suffix}-thinlto)    endif() +  if (${newpm}) +    set(suffix ${suffix}-newpm) +  endif()    set(suffix ${suffix}-${CFI_TEST_TARGET_ARCH})    set(CFI_TEST_USE_LLD ${lld})    set(CFI_TEST_USE_THINLTO ${thinlto}) +  set(CFI_TEST_USE_NEWPM ${newpm})    set(CFI_LIT_TEST_MODE Standalone)    set(CFI_TEST_CONFIG_SUFFIX -standalone${suffix}) @@ -40,16 +44,18 @@ foreach(arch ${CFI_TEST_ARCH})    get_test_cc_for_arch(${arch} CFI_TEST_TARGET_CC CFI_TEST_TARGET_CFLAGS)    if (APPLE)      # FIXME: enable ThinLTO tests after fixing http://llvm.org/pr32741 -    add_cfi_test_suites(False False) +    add_cfi_test_suites(False False False)    elseif(WIN32) -    add_cfi_test_suites(True False) -    add_cfi_test_suites(True True) +    add_cfi_test_suites(True False False) +    add_cfi_test_suites(True True False)    else() -    add_cfi_test_suites(False False) -    add_cfi_test_suites(False True) +    add_cfi_test_suites(False False False) +    add_cfi_test_suites(False True False) +    add_cfi_test_suites(False False True) +    add_cfi_test_suites(False True True)      if (COMPILER_RT_HAS_LLD AND NOT arch STREQUAL "i386") -      add_cfi_test_suites(True False) -      add_cfi_test_suites(True True) +	    add_cfi_test_suites(True False False) +	    add_cfi_test_suites(True True False)      endif()    endif()  endforeach() diff --git a/test/cfi/create-derivers.test b/test/cfi/create-derivers.test index 8b569d001d89f..b651d9be6bd97 100644 --- a/test/cfi/create-derivers.test +++ b/test/cfi/create-derivers.test @@ -7,15 +7,15 @@ B0: {{1B|B@@}}: {{.*}} size 1  RUN: %clangxx_cfi -DB32 -flto -c -o %t2.o %S/simple-fail.cpp  RUN: opt -lowertypetests -debug-only=lowertypetests -o /dev/null %t2.o 2>&1 | FileCheck --check-prefix=B32 %s -B32: {{1B|B@@}}: {{.*}} size 24 +B32: {{1B|B@@}}: {{.*}} size 2{{3|4}}  B32-NOT: all-ones  RUN: %clangxx_cfi -DB64 -flto -c -o %t3.o %S/simple-fail.cpp  RUN: opt -lowertypetests -debug-only=lowertypetests -o /dev/null %t3.o 2>&1 | FileCheck --check-prefix=B64 %s -B64: {{1B|B@@}}: {{.*}} size 54 +B64: {{1B|B@@}}: {{.*}} size 5{{3|4}}  B64-NOT: all-ones  RUN: %clangxx_cfi -DBM -flto -c -o %t4.o %S/simple-fail.cpp  RUN: opt -lowertypetests -debug-only=lowertypetests -o /dev/null %t4.o 2>&1 | FileCheck --check-prefix=BM %s -BM: {{1B|B@@}}: {{.*}} size 84 +BM: {{1B|B@@}}: {{.*}} size 8{{3|4}}  BM-NOT: all-ones diff --git a/test/cfi/cross-dso-diagnostic.cpp b/test/cfi/cross-dso-diagnostic.cpp new file mode 100644 index 0000000000000..f3782dae02725 --- /dev/null +++ b/test/cfi/cross-dso-diagnostic.cpp @@ -0,0 +1,47 @@ +// Check that cross-DSO diagnostics print the names of both modules + +// RUN: %clangxx_cfi_diag -g -DSHARED_LIB -fPIC -shared -o %dynamiclib %s %ld_flags_rpath_so +// RUN: %clangxx_cfi_diag -g -o %t_exe_suffix %s %ld_flags_rpath_exe +// RUN: %t_exe_suffix 2>&1 | FileCheck -DDSONAME=%xdynamiclib_namespec %s + +// UNSUPPORTED: win32 +// REQUIRES: cxxabi + +#include <dlfcn.h> +#include <stdio.h> + +struct S1 { +  virtual void f1(); +}; + +#ifdef SHARED_LIB + +void S1::f1() {} + +__attribute__((visibility("default"))) extern "C" +void* dso_symbol() { return new S1(); } + +#else + +int main() { +  void* (*fp)(void) = +      reinterpret_cast<void*(*)(void)>(dlsym(RTLD_DEFAULT, "dso_symbol")); +  if (!fp) { +    perror("failed to resolve dso_symbol"); +    return 1; +  } + +  // CHECK: runtime error: control flow integrity check for type 'void *()' failed during indirect function call +  // CHECK: dso_symbol defined here +  // CHECK: check failed in {{.*}}_exe_suffix, destination function located in {{.*}}[[DSONAME]] +  void *S = fp(); // trigger cfi-icall failure + +  // CHECK: runtime error: control flow integrity check for type 'S1' failed during cast to unrelated type +  // CHECK: invalid vtable +  // CHECK: check failed in {{.*}}_exe_suffix, vtable located in {{.*}}[[DSONAME]] +  S1 *Scast = reinterpret_cast<S1*>(S); // trigger cfi-unrelated-cast failure + +  return 0; +} + +#endif // SHARED_LIB diff --git a/test/cfi/cross-dso/icall/dlopen.cpp b/test/cfi/cross-dso/icall/dlopen.cpp index d238a7acec890..c9674c3fb412a 100644 --- a/test/cfi/cross-dso/icall/dlopen.cpp +++ b/test/cfi/cross-dso/icall/dlopen.cpp @@ -83,10 +83,12 @@ static void save_code(char *p) {  }  static void restore_code() { -  char *code = (char *)mmap(real_start, kCodeSize, PROT_WRITE | PROT_EXEC, -                            MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, 0, 0); +  char *code = +      (char *)mmap(real_start, kCodeSize, PROT_READ | PROT_WRITE | PROT_EXEC, +                   MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, 0, 0);    assert(code == real_start);    memcpy(code, saved_code, kCodeSize); +  __builtin___clear_cache(code, code + kCodeSize);  }  int main(int argc, char *argv[]) { diff --git a/test/cfi/lit.site.cfg.in b/test/cfi/lit.site.cfg.in index eb9b44137fdf2..a735e8812acd4 100644 --- a/test/cfi/lit.site.cfg.in +++ b/test/cfi/lit.site.cfg.in @@ -7,6 +7,7 @@ config.target_cflags = "@CFI_TEST_TARGET_CFLAGS@"  config.use_lld = @CFI_TEST_USE_LLD@  config.use_lto = True # CFI *requires* LTO.  config.use_thinlto = @CFI_TEST_USE_THINLTO@ +config.use_newpm = @CFI_TEST_USE_NEWPM@  lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/test/lit.common.configured")  lit_config.load_config(config, "@CMAKE_CURRENT_SOURCE_DIR@/lit.cfg") diff --git a/test/cfi/mfcall.cpp b/test/cfi/mfcall.cpp new file mode 100644 index 0000000000000..6e22e3f3d711e --- /dev/null +++ b/test/cfi/mfcall.cpp @@ -0,0 +1,96 @@ +// UNSUPPORTED: win32 + +// RUN: %clangxx_cfi -o %t %s +// RUN: %expect_crash %run %t a +// RUN: %expect_crash %run %t b +// RUN: %expect_crash %run %t c +// RUN: %expect_crash %run %t d +// RUN: %expect_crash %run %t e +// RUN: %run %t f +// RUN: %run %t g + +// RUN: %clangxx_cfi_diag -o %t2 %s +// RUN: %run %t2 a 2>&1 | FileCheck --check-prefix=A %s +// RUN: %run %t2 b 2>&1 | FileCheck --check-prefix=B %s +// RUN: %run %t2 c 2>&1 | FileCheck --check-prefix=C %s +// RUN: %run %t2 d 2>&1 | FileCheck --check-prefix=D %s +// RUN: %run %t2 e 2>&1 | FileCheck --check-prefix=E %s + +#include <assert.h> +#include <string.h> + +struct SBase1 { +  void b1() {} +}; + +struct SBase2 { +  void b2() {} +}; + +struct S : SBase1, SBase2 { +  void f1() {} +  int f2() { return 1; } +  virtual void g1() {} +  virtual int g2() { return 1; } +  virtual int g3() { return 1; } +}; + +struct T { +  void f1() {} +  int f2() { return 2; } +  virtual void g1() {} +  virtual int g2() { return 2; } +  virtual void g3() {} +}; + +typedef void (S::*S_void)(); + +typedef int (S::*S_int)(); +typedef int (T::*T_int)(); + +template <typename To, typename From> +To bitcast(From f) { +  assert(sizeof(To) == sizeof(From)); +  To t; +  memcpy(&t, &f, sizeof(f)); +  return t; +} + +int main(int argc, char **argv) { +  S s; +  T t; + +  switch (argv[1][0]) { +    case 'a': +      // A: runtime error: control flow integrity check for type 'int (S::*)()' failed during non-virtual pointer to member function call +      // A: note: S::f1() defined here +      (s.*bitcast<S_int>(&S::f1))(); +      break; +    case 'b': +      // B: runtime error: control flow integrity check for type 'int (T::*)()' failed during non-virtual pointer to member function call +      // B: note: S::f2() defined here +      (t.*bitcast<T_int>(&S::f2))(); +      break; +    case 'c': +      // C: runtime error: control flow integrity check for type 'int (S::*)()' failed during virtual pointer to member function call +      // C: note: vtable is of type 'S' +      (s.*bitcast<S_int>(&S::g1))(); +      break; +    case 'd': +      // D: runtime error: control flow integrity check for type 'int (S::*)()' failed during virtual pointer to member function call +      // D: note: vtable is of type 'T' +      (reinterpret_cast<S &>(t).*&S::g2)(); +      break; +    case 'e': +      // E: runtime error: control flow integrity check for type 'void (S::*)()' failed during virtual pointer to member function call +      // E: note: vtable is of type 'S' +      (s.*bitcast<S_void>(&T::g3))(); +      break; +    case 'f': +      (s.*&SBase1::b1)(); +      break; +    case 'g': +      (s.*&SBase2::b2)(); +      break; +  } +} diff --git a/test/cfi/simple-pass.cpp b/test/cfi/simple-pass.cpp index aba09be2d8169..de791fc1073ff 100644 --- a/test/cfi/simple-pass.cpp +++ b/test/cfi/simple-pass.cpp @@ -1,5 +1,10 @@ +// -mretpoline does not work yet on Darwin. +// XFAIL: darwin +  // RUN: %clangxx_cfi -o %t %s  // RUN: %run %t +// RUN: %clangxx_cfi -mretpoline -o %t2 %s +// RUN: %run %t2  // Tests that the CFI mechanism does not crash the program when making various  // kinds of valid calls involving classes with various different linkages and diff --git a/test/cfi/target_uninstrumented.cpp b/test/cfi/target_uninstrumented.cpp index 5df0738c078b6..6379b7e12f44f 100644 --- a/test/cfi/target_uninstrumented.cpp +++ b/test/cfi/target_uninstrumented.cpp @@ -32,12 +32,14 @@ void A::f() {}  int main(int argc, char *argv[]) {    void *p = create_B();    // CHECK: runtime error: control flow integrity check for type 'A' failed during cast to unrelated type -  // CHECK: invalid vtable in module {{.*}}libtarget_uninstrumented.cpp.dynamic.so +  // CHECK: invalid vtable +  // CHECK: check failed in {{.*}}, vtable located in {{.*}}libtarget_uninstrumented.cpp.dynamic.so    A *a = (A *)p;    memset(p, 0, sizeof(A)); +    // CHECK: runtime error: control flow integrity check for type 'A' failed during cast to unrelated type -  // CHECK-NOT: invalid vtable in module    // CHECK: invalid vtable +  // CHECK: check failed in {{.*}}, vtable located in (unknown)    a = (A *)p;    // CHECK: done    fprintf(stderr, "done %p\n", a); diff --git a/test/dfsan/custom.cc b/test/dfsan/custom.cc index b36db01bc48cf..71422f7ce834f 100644 --- a/test/dfsan/custom.cc +++ b/test/dfsan/custom.cc @@ -3,8 +3,6 @@  // RUN: %clang_dfsan -DSTRICT_DATA_DEPENDENCIES %s -o %t && %run %t  // RUN: %clang_dfsan -DSTRICT_DATA_DEPENDENCIES -mllvm -dfsan-args-abi %s -o %t && %run %t -// XFAIL: target-is-mips64,target-is-mips64el -  // Tests custom implementations of various glibc functions.  #include <sanitizer/dfsan_interface.h> diff --git a/test/dfsan/trace-cmp.c b/test/dfsan/trace-cmp.c new file mode 100644 index 0000000000000..0645363b26055 --- /dev/null +++ b/test/dfsan/trace-cmp.c @@ -0,0 +1,50 @@ +// Checks that dfsan works with trace-cmp instrumentation, even if some hooks +// are not defined (relies on week hooks implemented in dfsan). +// +// RUN: %clang_dfsan -fsanitize-coverage=trace-pc-guard,pc-table,func,trace-cmp %s -o %t +// RUN: %run %t 2>&1 | FileCheck %s + +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> + +#include <sanitizer/dfsan_interface.h> + +uint32_t a4, b4; +uint64_t a8, b8; + +// Define just two hooks, and leave others undefined. +void __dfsw___sanitizer_cov_trace_const_cmp4(uint8_t a, uint8_t b, +                                             dfsan_label l1, dfsan_label l2) { +  printf("const_cmp4 %d %d\n", a, b); +} +void __dfsw___sanitizer_cov_trace_cmp8(uint8_t a, uint8_t b, dfsan_label l1, +                                       dfsan_label l2) { +  printf("cmp8 %d %d\n", a, b); +} + +int main(int argc, char **argv) { +  printf("MAIN\n"); +  // CHECK: MAIN + +  if (a4 != b4) abort(); +  if (a4 == 42) abort(); +  // CHECK: const_cmp4 42 0 +  if (a8 != b8) abort(); +  // CHECK: cmp8 0 0 +  if (a8 == 66) abort(); + +  switch (10 / (a4 + 2)) { +    case 1: abort(); +    case 2: exit(1); +    case 5: +            printf("SWITCH OK\n"); +            break; +  } +  // CHECK: SWITCH OK + + +  printf("DONE\n"); +  // CHECK: DONE +  return 0; +} diff --git a/test/fuzzer/AbsNegAndConstant64Test.cpp b/test/fuzzer/AbsNegAndConstant64Test.cpp index abeb784e9a116..0ba80b61d0332 100644 --- a/test/fuzzer/AbsNegAndConstant64Test.cpp +++ b/test/fuzzer/AbsNegAndConstant64Test.cpp @@ -14,7 +14,8 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {    uint64_t y;    memcpy(&x, Data, sizeof(x));    memcpy(&y, Data + sizeof(x), sizeof(y)); -  if (llabs(x) < 0 && y == 0xbaddcafedeadbeefULL) { +  volatile int64_t abs_x = llabs(x); +  if (abs_x < 0 && y == 0xbaddcafedeadbeefULL) {      printf("BINGO; Found the target, exiting; x = 0x%lx y 0x%lx\n", x, y);      fflush(stdout);      exit(1); diff --git a/test/fuzzer/AbsNegAndConstantTest.cpp b/test/fuzzer/AbsNegAndConstantTest.cpp index 049db0a60c3d5..a3f5349800104 100644 --- a/test/fuzzer/AbsNegAndConstantTest.cpp +++ b/test/fuzzer/AbsNegAndConstantTest.cpp @@ -14,7 +14,8 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {    unsigned y;    memcpy(&x, Data, sizeof(x));    memcpy(&y, Data + sizeof(x), sizeof(y)); -  if (abs(x) < 0 && y == 0xbaddcafe) { +  volatile int abs_x = abs(x); +  if (abs_x < 0 && y == 0xbaddcafe) {      printf("BINGO; Found the target, exiting; x = 0x%x y 0x%x\n", x, y);      fflush(stdout);      exit(1); diff --git a/test/fuzzer/AcquireCrashStateTest.cpp b/test/fuzzer/AcquireCrashStateTest.cpp new file mode 100644 index 0000000000000..0fe71fd46bf4c --- /dev/null +++ b/test/fuzzer/AcquireCrashStateTest.cpp @@ -0,0 +1,18 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// Ensures that error reports are suppressed after +// __sanitizer_acquire_crash_state() has been called the first time. +#include "sanitizer/common_interface_defs.h" + +#include <cassert> +#include <cstdint> +#include <cstdlib> + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { +  assert(Data); +  if (Size == 0) return 0; +  __sanitizer_acquire_crash_state(); +  exit(0);  // No report should be generated here. +} + diff --git a/test/fuzzer/Bingo.h b/test/fuzzer/Bingo.h new file mode 100644 index 0000000000000..09fc61e2a0cb6 --- /dev/null +++ b/test/fuzzer/Bingo.h @@ -0,0 +1 @@ +#define BINGO aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa diff --git a/test/fuzzer/CMakeLists.txt b/test/fuzzer/CMakeLists.txt index bd511123255b2..ef46ec4a90616 100644 --- a/test/fuzzer/CMakeLists.txt +++ b/test/fuzzer/CMakeLists.txt @@ -1,43 +1,109 @@  set(LIBFUZZER_TEST_DEPS ${SANITIZER_COMMON_LIT_TEST_DEPS}) -list(REMOVE_ITEM LIBFUZZER_TEST_DEPS SanitizerLintCheck)  if (NOT COMPILER_RT_STANDALONE_BUILD)    list(APPEND LIBFUZZER_TEST_DEPS fuzzer asan ubsan) +  if (COMPILER_RT_HAS_MSAN) +    list(APPEND LIBFUZZER_TEST_DEPS msan) +  endif() +  if (COMPILER_RT_HAS_DFSAN) +    list(APPEND LIBFUZZER_TEST_DEPS dfsan) +  endif() +  if(NOT APPLE AND COMPILER_RT_HAS_LLD) +    list(APPEND LIBFUZZER_TEST_DEPS lld) +  endif() +endif() + +if (APPLE) +  darwin_filter_host_archs(FUZZER_SUPPORTED_ARCH FUZZER_SUPPORTED_ARCH)  endif()  if(COMPILER_RT_INCLUDE_TESTS)    list(APPEND LIBFUZZER_TEST_DEPS FuzzerUnitTests)  endif() -set(LIBFUZZER_TESTSUITES) - +add_custom_target(check-fuzzer)  if(COMPILER_RT_INCLUDE_TESTS)    # libFuzzer unit tests.    configure_lit_site_cfg(      ${CMAKE_CURRENT_SOURCE_DIR}/unit/lit.site.cfg.in      ${CMAKE_CURRENT_BINARY_DIR}/unit/lit.site.cfg) -  list(APPEND LIBFUZZER_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/unit) +  add_lit_testsuite(check-fuzzer-unit "Running Fuzzer unit tests" +    ${CMAKE_CURRENT_BINARY_DIR}/unit +    DEPENDS ${LIBFUZZER_TEST_DEPS}) +  set_target_properties(check-fuzzer-unit PROPERTIES FOLDER "Compiler-RT Tests") +  add_dependencies(check-fuzzer check-fuzzer-unit)  endif() -foreach(arch ${FUZZER_SUPPORTED_ARCH}) -  set(LIBFUZZER_TEST_COMPILER ${COMPILER_RT_TEST_COMPILER}) -  get_test_cc_for_arch(${arch} LIBFUZZER_TEST_COMPILER LIBFUZZER_TEST_FLAGS) +macro(test_fuzzer stdlib) +  cmake_parse_arguments(TEST "" "" "DEPS" ${ARGN}) +  string(REPLACE "+" "x" stdlib_name ${stdlib}) +  string(REPLACE "-" ";" stdlib_list ${stdlib_name}) +  set(STDLIB_CAPITALIZED "") +  foreach(part IN LISTS stdlib_list) +    string(SUBSTRING ${part} 0 1 first_letter) +    string(TOUPPER ${first_letter} first_letter) +    string(REGEX REPLACE "^.(.*)" "${first_letter}\\1" part "${part}") +    set(STDLIB_CAPITALIZED "${STDLIB_CAPITALIZED}${part}") +  endforeach() +  foreach(arch ${FUZZER_SUPPORTED_ARCH}) +    set(LIBFUZZER_TEST_COMPILER ${COMPILER_RT_TEST_COMPILER}) +    get_test_cc_for_arch(${arch} LIBFUZZER_TEST_COMPILER LIBFUZZER_TEST_FLAGS) -  string(TOUPPER ${arch} ARCH_UPPER_CASE) -  set(CONFIG_NAME ${ARCH_UPPER_CASE}${OS_NAME}Config) +    set(LIBFUZZER_TEST_APPLE_PLATFORM "osx") -  # LIT-based libFuzzer tests. -  configure_lit_site_cfg( -    ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in -    ${CMAKE_CURRENT_BINARY_DIR}/${CONFIG_NAME}/lit.site.cfg -    ) -  list(APPEND LIBFUZZER_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/${CONFIG_NAME}) +    set(LIBFUZZER_TEST_STDLIB ${stdlib}) + +    string(TOUPPER ${arch} ARCH_UPPER_CASE) +    set(CONFIG_NAME ${ARCH_UPPER_CASE}${STDLIB_CAPITALIZED}${OS_NAME}Config) -endforeach() +    # LIT-based libFuzzer tests. +    configure_lit_site_cfg( +      ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in +      ${CMAKE_CURRENT_BINARY_DIR}/${CONFIG_NAME}/lit.site.cfg +      ) -set(EXCLUDE_FROM_ALL ON) +    add_lit_testsuite(check-fuzzer-${stdlib_name}-${arch} +      "Running libFuzzer ${stdlib} tests for arch ${arch}" +      ${CMAKE_CURRENT_BINARY_DIR}/${CONFIG_NAME}/ +      DEPENDS ${LIBFUZZER_TEST_DEPS}) +    if(TEST_DEPS) +      add_dependencies(check-fuzzer-${stdlib_name}-${arch} ${TEST_DEPS}) +    endif() +    set_target_properties(check-fuzzer-${stdlib_name}-${arch} +        PROPERTIES FOLDER "Compiler-RT Tests") +    add_dependencies(check-fuzzer check-fuzzer-${stdlib_name}-${arch}) +  endforeach() +endmacro() -add_lit_testsuite(check-fuzzer "Running Fuzzer tests" -  ${LIBFUZZER_TESTSUITES} -  DEPENDS ${LIBFUZZER_TEST_DEPS}) -set_target_properties(check-fuzzer PROPERTIES FOLDER "Compiler-RT Tests") +test_fuzzer("default") +if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") +  if(TARGET cxx_shared) +    test_fuzzer("libc++" DEPS cxx_shared) +  endif() +  if(TARGET cxx_static) +    test_fuzzer("static-libc++" DEPS cxx_static) +  endif() +endif() + +if (APPLE) +  set(EXCLUDE_FROM_ALL ON) + +  foreach(arch ${DARWIN_ios_ARCHS}) +    set(LIBFUZZER_TEST_APPLE_PLATFORM "ios") +    set(LIBFUZZER_TEST_TARGET_ARCH ${arch}) +    set(LIBFUZZER_TEST_FLAGS "-arch ${arch} -isysroot ${DARWIN_ios_SYSROOT} ${COMPILER_RT_TEST_COMPILER_CFLAGS}") +    set(LIBFUZZER_TEST_CONFIG_SUFFIX "-${arch}-${LIBFUZZER_TEST_APPLE_PLATFORM}") +    string(TOUPPER ${arch} ARCH_UPPER_CASE) +    set(CONFIG_NAME "IOS${ARCH_UPPER_CASE}Config") +    configure_lit_site_cfg( +      ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in +      ${CMAKE_CURRENT_BINARY_DIR}/${CONFIG_NAME}/lit.site.cfg +      ) +    add_lit_testsuite(check-fuzzer-ios-${arch} "libFuzzer iOS ${arch} tests" +      ${CMAKE_CURRENT_BINARY_DIR}/${CONFIG_NAME}/ +      DEPENDS ${LIBFUZZER_TEST_DEPS}) + +  endforeach() + +  set(EXCLUDE_FROM_ALL OFF) +endif() diff --git a/test/fuzzer/CleanseTest.cpp b/test/fuzzer/CleanseTest.cpp index ee18457012693..d4efa12bb207e 100644 --- a/test/fuzzer/CleanseTest.cpp +++ b/test/fuzzer/CleanseTest.cpp @@ -1,7 +1,7 @@  // This file is distributed under the University of Illinois Open Source  // License. See LICENSE.TXT for details. -// Test the the fuzzer is able to 'cleanse' the reproducer +// Test the fuzzer is able to 'cleanse' the reproducer  // by replacing all irrelevant bytes with garbage.  #include <cstddef>  #include <cstdint> diff --git a/test/fuzzer/ExplodeDFSanLabelsTest.cpp b/test/fuzzer/ExplodeDFSanLabelsTest.cpp new file mode 100644 index 0000000000000..0decff8ff0862 --- /dev/null +++ b/test/fuzzer/ExplodeDFSanLabelsTest.cpp @@ -0,0 +1,23 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// When tracing data flow, explode the number of DFSan labels. +#include <cstddef> +#include <cstdint> + +static volatile int sink; + +__attribute__((noinline)) +void f(uint8_t a, uint8_t b, uint8_t c, uint8_t d) { +  if (a == b + 1 && c == d + 2) +    sink++; +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { +  for (size_t a = 0; a < Size; a++) +    for (size_t b = 0; b < Size; b++) +      for (size_t c = 0; c < Size; c++) +        for (size_t d = 0; d < Size; d++) +          f(Data[a], Data[b], Data[c], Data[d]); +  return 0; +} diff --git a/test/fuzzer/LeakTest.cpp b/test/fuzzer/LeakTest.cpp index ea89e39010573..f259e9d359f4c 100644 --- a/test/fuzzer/LeakTest.cpp +++ b/test/fuzzer/LeakTest.cpp @@ -5,7 +5,7 @@  #include <cstddef>  #include <cstdint> -static volatile void *Sink; +static void * volatile Sink;  extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {    if (Size > 0 && *Data == 'H') { diff --git a/test/fuzzer/MultipleConstraintsOnSmallInputTest.cpp b/test/fuzzer/MultipleConstraintsOnSmallInputTest.cpp new file mode 100644 index 0000000000000..8e24acbcf2d95 --- /dev/null +++ b/test/fuzzer/MultipleConstraintsOnSmallInputTest.cpp @@ -0,0 +1,4129 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +// echo -en 'Im_so_cute&pretty_:)' > crash +// +#include <stddef.h> +#include <stdint.h> +#include <stdlib.h> +#include <stdio.h> + +// Force noinline, as this test might be interesting for experimenting with +// data flow tracing approach started in https://reviews.llvm.org/D46666. +__attribute__((noinline)) +int func1(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v <= 15 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func2(uint8_t a1, uint8_t a2) { +  char v = (a1 & a2); +  if ( v > 80 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func3(uint8_t a1, uint8_t a2) { +  char v = (a1 & a2); +  if ( v > 48 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func4(uint8_t a1, uint8_t a2, uint8_t a3) { +  char v = ((a1 & a2)) ^ a3; +  if ( v > 44 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func5(uint8_t a1, uint8_t a2) { +  char v = (a1 & a2); +  if ( v <= 72 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func6(uint8_t a1, uint8_t a2) { +  char v = (a1 & a2); +  if ( v <= 72 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func7(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v <= 43 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func8(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v <= 66 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func9(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v > 16 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func10(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v > 83 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func11(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v <= 117 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func12(uint8_t a1, uint8_t a2) { +  char v = a1 | a2; +  if ( v <= 16 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func13(uint8_t a1, uint8_t a2) { +  char v = (a1 & a2); +  if ( v <= 80 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func14(uint8_t a1) { +  char v = ~a1; +  if ( v > 1 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func15(uint8_t a1, uint8_t a2) { +  char v = a1 | a2; +  if ( v <= 116 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func16(uint8_t a1) { +  char v = a1 >> 5; +  if ( v <= 0 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func17(uint8_t a1) { +  char v = ~a1; +  if ( v > 1 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func18(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v <= 28 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func19(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v > 18 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func20(uint8_t a1, uint8_t a2) { +  char v = (a1 & a2); +  if ( v <= 47 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func21(uint8_t a1, uint8_t a2, uint8_t a3) { +  char v = (((a1 ^ a2))) & a3; +  if ( v > 108 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func22(uint8_t a1) { +  char v = ~a1; +  if ( v > 1 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func23(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v <= 7 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func24(uint8_t a1) { +  char v = (char)a1 >> 1; +  if ( v <= 25 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func25(uint8_t a1) { +  char v = ~a1; +  if ( v > 1 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func26(uint8_t a1, uint8_t a2) { +  char v = (a1 & a2); +  if ( v <= 41 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func27(uint8_t a1) { +  char v = (char)a1 >> 1; +  if ( v <= 14 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func28(uint8_t a1) { +  char v = ~a1; +  if ( v > 1 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func29(uint8_t a1) { +  char v = a1 >> 5; +  if ( v > 48 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func30(uint8_t a1) { +  char v = ~a1; +  if ( v > 1 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func31(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v > 45 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func32(uint8_t a1, uint8_t a2) { +  char v = (a1 & a2); +  if ( v <= 0 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func33(uint8_t a1) { +  char v = ~a1; +  if ( v > 1 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func34(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v <= 95 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func35(uint8_t a1) { +  char v = a1 >> 5; +  if ( v > 12 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func36(uint8_t a1, uint8_t a2) { +  char v = a1 | a2; +  if ( v <= 121 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func37(uint8_t a1) { +  char v = ~a1; +  if ( v > 1 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func38(uint8_t a1, uint8_t a2) { +  char v = (a1 & a2); +  if ( v <= 61 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func39(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v > 94 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func40(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v > 125 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func41(uint8_t a1, uint8_t a2) { +  char v = (a1 & a2); +  if ( v <= 0 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func42(uint8_t a1, uint8_t a2, uint8_t a3) { +  char v = (((a1 ^ a2))) & a3; +  if ( v > 66 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func43(uint8_t a1) { +  char v = ~a1; +  if ( v > 1 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func44(uint8_t a1) { +  char v = a1 >> 5; +  if ( v <= 0 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func45(uint8_t a1) { +  char v = ~a1; +  if ( v > 1 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func46(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v > 106 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func47(uint8_t a1, uint8_t a2) { +  char v = (a1 & a2); +  if ( v <= 33 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func48(uint8_t a1, uint8_t a2) { +  char v = a1 | a2; +  if ( v <= 118 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func49(uint8_t a1, uint8_t a2) { +  char v = (a1 & a2); +  if ( v > 58 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func50(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v <= 42 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func51(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v <= 46 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func52(uint8_t a1, uint8_t a2) { +  char v = (a1 & a2); +  if ( v <= 94 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func53(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v <= 66 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func54(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v <= 23 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func55(uint8_t a1, uint8_t a2) { +  char v = (a1 & a2); +  if ( v <= 17 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func56(uint8_t a1, uint8_t a2) { +  char v = (a1 & a2); +  if ( v > 90 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func57(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v > 63 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func58(uint8_t a1, uint8_t a2) { +  char v = (a1 & a2); +  if ( v > 102 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func59(uint8_t a1, uint8_t a2) { +  char v = (a1 & a2); +  if ( v <= 49 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func60(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v > 26 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func61(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v > 55 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func62(uint8_t a1, uint8_t a2) { +  char v = (a1 & a2); +  if ( v > 103 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func63(uint8_t a1, uint8_t a2) { +  char v = (a1 & a2); +  if ( v <= 0 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func64(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v <= 34 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func65(uint8_t a1, uint8_t a2) { +  char v = (a1 & a2); +  if ( v > 90 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func66(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v > 4 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func67(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v > 50 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func68(uint8_t a1, uint8_t a2) { +  char v = (a1 & a2); +  if ( v <= 37 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func69(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v > 48 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func70(uint8_t a1) { +  char v = a1 << 6; +  if ( v > 1 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func71(uint8_t a1, uint8_t a2) { +  char v = a1 | a2; +  if ( v <= 85 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func72(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v <= 66 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func73(uint8_t a1, uint8_t a2) { +  char v = (a1 & a2); +  if ( v <= 30 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func74(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v > 118 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func75(uint8_t a1, uint8_t a2, uint8_t a3) { +  char v = ((a1 & a2)) | a3; +  if ( v <= 59 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func76(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v <= 94 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func77(uint8_t a1, uint8_t a2) { +  char v = (a1 & a2); +  if ( v <= 30 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func78(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v > 32 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func79(uint8_t a1) { +  char v = 16 * a1; +  if ( v > 1 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func80(uint8_t a1, uint8_t a2, uint8_t a3) { +  char v = ((a1 ^ a2)) | a3; +  if ( v <= 94 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func81(uint8_t a1, uint8_t a2) { +  char v = a1 | a2; +  if ( v > 120 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func82(uint8_t a1, uint8_t a2) { +  char v = (a1 & a2); +  if ( v > 81 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func83(uint8_t a1, uint8_t a2) { +  char v = a1 | a2; +  if ( v > 119 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func84(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v <= 16 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func85(uint8_t a1) { +  char v = 2 * a1; +  if ( v > 1 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func86(uint8_t a1, uint8_t a2) { +  char v = a1 | a2; +  if ( v <= 66 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func87(uint8_t a1, uint8_t a2) { +  char v = (a1 & a2); +  if ( v <= 84 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func88(uint8_t a1, uint8_t a2) { +  char v = (a1 & a2); +  if ( v > 118 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func89(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v > 47 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func90(uint8_t a1, uint8_t a2) { +  char v = a1 | a2; +  if ( v <= 60 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func91(uint8_t a1, uint8_t a2) { +  char v = (a1 & a2); +  if ( v <= 13 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func92(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v <= 38 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func93(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v > 67 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func94(uint8_t a1) { +  char v = 16 * a1; +  if ( v > 1 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func95(uint8_t a1, uint8_t a2) { +  char v = a1 | a2; +  if ( v <= 94 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func96(uint8_t a1, uint8_t a2) { +  char v = (a1 & a2); +  if ( v > 67 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func97(uint8_t a1, uint8_t a2) { +  char v = (a1 & a2); +  if ( v > 48 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func98(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v > 102 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func99(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v > 96 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func100(uint8_t a1, uint8_t a2, uint8_t a3) { +  char v = ((a1 ^ a2)) | a3; +  if ( v != 127 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func101(uint8_t a1) { +  char v = 4 * a1; +  if ( v > 1 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func102(uint8_t a1, uint8_t a2) { +  char v = a1 | a2; +  if ( v <= 43 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func103(uint8_t a1, uint8_t a2) { +  char v = (a1 & a2); +  if ( v > 95 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func104(uint8_t a1, uint8_t a2, uint8_t a3) { +  char v = (((a1 ^ a2))) & a3; +  if ( v <= 2 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func105(uint8_t a1, uint8_t a2) { +  char v = (a1 & a2); +  if ( v > 65 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func106(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v <= 24 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func107(uint8_t a1) { +  char v = ~a1; +  if ( v > 1 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func108(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v > 67 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func109(uint8_t a1) { +  char v = 2 * a1; +  if ( v > 1 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func110(uint8_t a1, uint8_t a2) { +  char v = (a1 & a2); +  if ( v > 101 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func111(uint8_t a1, uint8_t a2, uint8_t a3) { +  char v = ((a1 & a2)) | a3; +  if ( v <= 121 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func112(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v <= 40 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func113(uint8_t a1, uint8_t a2) { +  char v = (a1 & a2); +  if ( v > 50 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func114(uint8_t a1) { +  char v = a1 << 6; +  if ( v > 1 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func115(uint8_t a1, uint8_t a2) { +  char v = a1 | a2; +  if ( v <= 12 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func116(uint8_t a1) { +  char v = ~a1; +  if ( v > 1 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func117(uint8_t a1) { +  char v = a1 >> 5; +  if ( v > 79 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func118(uint8_t a1) { +  char v = ~a1; +  if ( v > 1 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func119(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v > 44 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func120(uint8_t a1, uint8_t a2, uint8_t a3) { +  char v = ((a1 & a2)) | a3; +  if ( v <= 28 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func121(uint8_t a1, uint8_t a2) { +  char v = a1 | a2; +  if ( v <= 93 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func122(uint8_t a1, uint8_t a2) { +  char v = a1 | a2; +  if ( v <= 40 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func123(uint8_t a1) { +  char v = ~a1; +  if ( v > 1 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func124(uint8_t a1) { +  char v = a1 >> 5; +  if ( v <= 0 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func125(uint8_t a1) { +  char v = ~a1; +  if ( v > 1 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func126(uint8_t a1) { +  char v = ~a1; +  if ( v > 1 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func127(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v > 8 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func128(uint8_t a1) { +  char v = ~a1; +  if ( v > 1 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func129(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v <= 3 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func130(uint8_t a1, uint8_t a2) { +  char v = a1 | a2; +  if ( v <= 102 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func131(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v > 68 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func132(uint8_t a1, uint8_t a2) { +  char v = (a1 & a2); +  if ( v > 73 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func133(uint8_t a1, uint8_t a2) { +  char v = (a1 & a2); +  if ( v <= 68 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func134(uint8_t a1) { +  char v = 16 * a1; +  if ( v > 125 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func135(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v > 79 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func136(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v > 6 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func137(uint8_t a1, uint8_t a2) { +  char v = (a1 & a2); +  if ( v <= 16 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func138(uint8_t a1) { +  char v = ~a1; +  if ( v > 1 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func139(uint8_t a1) { +  char v = ~a1; +  if ( v > 1 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func140(uint8_t a1) { +  char v = a1 >> 5; +  if ( v > 74 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func141(uint8_t a1) { +  char v = ~a1; +  if ( v > 1 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func142(uint8_t a1, uint8_t a2) { +  char v = a1 | a2; +  if ( v <= 89 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func143(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v > 46 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func144(uint8_t a1) { +  char v = 16 * a1; +  if ( v <= 29 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func145(uint8_t a1, uint8_t a2) { +  char v = a1 | a2; +  if ( v <= 77 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func146(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v > 12 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func147(uint8_t a1) { +  char v = ~a1; +  if ( v > 1 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func148(uint8_t a1) { +  char v = a1 >> 5; +  if ( v > 27 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func149(uint8_t a1) { +  char v = ~a1; +  if ( v > 1 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func150(uint8_t a1, uint8_t a2) { +  char v = a1 | a2; +  if ( v > 122 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func151(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v <= 3 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func152(uint8_t a1, uint8_t a2) { +  char v = (a1 & a2); +  if ( v <= 56 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func153(uint8_t a1) { +  char v = 16 * a1; +  if ( v <= 3 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func154(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v > 43 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func155(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v <= 16 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func156(uint8_t a1) { +  char v = ~a1; +  if ( v > 1 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func157(uint8_t a1) { +  char v = ~a1; +  if ( v > 1 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func158(uint8_t a1) { +  char v = ~a1; +  if ( v > 1 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func159(uint8_t a1) { +  char v = a1 >> 5; +  if ( v > 88 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func160(uint8_t a1) { +  char v = ~a1; +  if ( v > 33 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func161(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v > 46 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func162(uint8_t a1) { +  char v = ~a1; +  if ( v > 1 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func163(uint8_t a1, uint8_t a2, uint8_t a3) { +  char v = ((a1 & a2)) | a3; +  if ( v <= 9 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func164(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v > 96 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func165(uint8_t a1) { +  char v = ~a1; +  if ( v > 1 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func166(uint8_t a1) { +  char v = ~a1; +  if ( v > 1 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func167(uint8_t a1) { +  char v = a1 >> 5; +  if ( v > 91 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func168(uint8_t a1) { +  char v = ~a1; +  if ( v > 1 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func169(uint8_t a1, uint8_t a2) { +  char v = a1 | a2; +  if ( v <= 32 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func170(uint8_t a1, uint8_t a2) { +  char v = (a1 & a2); +  if ( v <= 32 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func171(uint8_t a1) { +  char v = ~a1; +  if ( v > 1 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func172(uint8_t a1) { +  char v = ~a1; +  if ( v > 1 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func173(uint8_t a1) { +  char v = ~a1; +  if ( v > 1 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func174(uint8_t a1, uint8_t a2) { +  char v = a1 | a2; +  if ( v <= 90 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func175(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v > 32 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func176(uint8_t a1) { +  char v = 16 * a1; +  if ( v <= 61 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func177(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v <= 33 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func178(uint8_t a1) { +  char v = a1 >> 5; +  if ( v > 16 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func179(uint8_t a1) { +  char v = ~a1; +  if ( v > 64 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func180(uint8_t a1, uint8_t a2) { +  char v = a1 | a2; +  if ( v <= 95 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func181(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v > 48 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func182(uint8_t a1, uint8_t a2) { +  char v = (a1 & a2); +  if ( v > 113 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func183(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v <= 41 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func184(uint8_t a1) { +  char v = 16 * a1; +  if ( v <= 63 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func185(uint8_t a1) { +  char v = ~a1; +  if ( v > 1 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func186(uint8_t a1, uint8_t a2) { +  char v = (a1 & a2); +  if ( v <= 94 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func187(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v > 43 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func188(uint8_t a1) { +  char v = (char)a1 >> 1; +  if ( v <= 57 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func189(uint8_t a1) { +  char v = ~a1; +  if ( v > 1 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func190(uint8_t a1, uint8_t a2) { +  char v = (a1 & a2); +  if ( v > 103 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func191(uint8_t a1) { +  char v = (char)a1 >> 1; +  if ( v > 92 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func192(uint8_t a1) { +  char v = ~a1; +  if ( v > 1 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func193(uint8_t a1, uint8_t a2, uint8_t a3) { +  char v = ((a1 & a2)) | a3; +  if ( v <= 16 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func194(uint8_t a1, uint8_t a2) { +  char v = a1 | a2; +  if ( v <= 20 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func195(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v > 82 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func196(uint8_t a1, uint8_t a2) { +  char v = a1 | a2; +  if ( v > 117 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func197(uint8_t a1, uint8_t a2) { +  char v = (a1 & a2); +  if ( v <= 50 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func198(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v > 118 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func199(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v == 127 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func200(uint8_t a1) { +  char v = ~a1; +  if ( v > 1 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func201(uint8_t a1, uint8_t a2) { +  char v = (a1 & a2); +  if ( v <= 67 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func202(uint8_t a1, uint8_t a2) { +  char v = (a1 & a2); +  if ( v <= 56 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func203(uint8_t a1) { +  char v = (char)a1 >> 1; +  if ( v > 95 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func204(uint8_t a1) { +  char v = ~a1; +  if ( v > 1 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func205(uint8_t a1, uint8_t a2, uint8_t a3) { +  char v = ((a1 ^ a2)) | a3; +  if ( v > 95 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func206(uint8_t a1, uint8_t a2) { +  char v = (a1 & a2); +  if ( v <= 78 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func207(uint8_t a1) { +  char v = (char)a1 >> 1; +  if ( v <= 7 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func208(uint8_t a1) { +  char v = a1 >> 5; +  if ( v > 123 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func209(uint8_t a1) { +  char v = ~a1; +  if ( v > 1 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func210(uint8_t a1, uint8_t a2) { +  char v = a1 | a2; +  if ( v <= 101 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func211(uint8_t a1, uint8_t a2) { +  char v = (a1 & a2); +  if ( v <= 61 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func212(uint8_t a1) { +  char v = 16 * a1; +  if ( v <= 73 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func213(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v <= 34 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func214(uint8_t a1) { +  char v = ~a1; +  if ( v > 1 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func215(uint8_t a1, uint8_t a2) { +  char v = (a1 & a2); +  if ( v <= 5 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func216(uint8_t a1) { +  char v = ~a1; +  if ( v > 85 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func217(uint8_t a1, uint8_t a2) { +  char v = (a1 & a2); +  if ( v > 113 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func218(uint8_t a1) { +  char v = (char)a1 >> 1; +  if ( v > 61 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func219(uint8_t a1) { +  char v = (char)a1 >> 1; +  if ( v > 90 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func220(uint8_t a1) { +  char v = a1 >> 5; +  if ( v > 106 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func221(uint8_t a1) { +  char v = ~a1; +  if ( v > 1 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func222(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v > 84 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func223(uint8_t a1, uint8_t a2) { +  char v = (a1 & a2); +  if ( v > 81 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func224(uint8_t a1) { +  char v = ~a1; +  if ( v > 1 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func225(uint8_t a1) { +  char v = a1 >> 5; +  if ( v > 49 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func226(uint8_t a1) { +  char v = ~a1; +  if ( v > 1 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func227(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v > 66 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func228(uint8_t a1, uint8_t a2) { +  char v = (a1 & a2); +  if ( v > 81 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func229(uint8_t a1, uint8_t a2) { +  char v = (a1 & a2); +  if ( v > 41 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func230(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v > 82 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func231(uint8_t a1, uint8_t a2) { +  char v = (a1 & a2); +  if ( v > 84 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func232(uint8_t a1, uint8_t a2) { +  char v = (a1 & a2); +  if ( v <= 34 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func233(uint8_t a1, uint8_t a2) { +  char v = (a1 & a2); +  if ( v > 66 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func234(uint8_t a1, uint8_t a2) { +  char v = (a1 & a2); +  if ( v > 90 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func235(uint8_t a1, uint8_t a2) { +  char v = (a1 & a2); +  if ( v > 73 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func236(uint8_t a1, uint8_t a2) { +  char v = (a1 & a2); +  if ( v <= 12 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func237(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v <= 9 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func238(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v <= 42 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func239(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v > 44 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func240(uint8_t a1, uint8_t a2) { +  char v = (a1 & a2); +  if ( v <= 14 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func241(uint8_t a1, uint8_t a2) { +  char v = (a1 & a2); +  if ( v <= 16 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func242(uint8_t a1, uint8_t a2) { +  char v = (a1 & a2); +  if ( v > 74 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func243(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v > 102 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func244(uint8_t a1) { +  char v = 4 * a1; +  if ( v <= 16 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func245(uint8_t a1, uint8_t a2) { +  char v = a1 | a2; +  if ( v <= 87 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func246(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v > 29 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func247(uint8_t a1, uint8_t a2) { +  char v = (a1 & a2); +  if ( v > 51 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func248(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v > 74 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func249(uint8_t a1) { +  char v = 4 * a1; +  if ( v <= 103 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func250(uint8_t a1, uint8_t a2) { +  char v = a1 | a2; +  if ( v <= 56 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func251(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v <= 11 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func252(uint8_t a1, uint8_t a2) { +  char v = (a1 & a2); +  if ( v <= 16 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func253(uint8_t a1, uint8_t a2) { +  char v = (a1 & a2); +  if ( v <= 22 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func254(uint8_t a1, uint8_t a2, uint8_t a3) { +  char v = ((a1 & a2)) | a3; +  if ( v > 122 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func255(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v > 74 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func256(uint8_t a1) { +  char v = 4 * a1; +  if ( v <= 16 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func257(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v > 67 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func258(uint8_t a1, uint8_t a2) { +  char v = (a1 & a2); +  if ( v > 102 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func259(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v > 74 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func260(uint8_t a1, uint8_t a2) { +  char v = a1 | a2; +  if ( v <= 27 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func261(uint8_t a1) { +  char v = 4 * a1; +  if ( v <= 58 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func262(uint8_t a1) { +  char v = 4 * a1; +  if ( v <= 77 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func263(uint8_t a1, uint8_t a2) { +  char v = a1 | a2; +  if ( v <= 3 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func264(uint8_t a1, uint8_t a2) { +  char v = (a1 & a2); +  if ( v <= 13 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func265(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v > 47 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func266(uint8_t a1, uint8_t a2) { +  char v = (a1 & a2); +  if ( v <= 39 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func267(uint8_t a1, uint8_t a2) { +  char v = a1 | a2; +  if ( v == 127 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func268(uint8_t a1, uint8_t a2) { +  char v = a1 | a2; +  if ( v <= 66 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func269(uint8_t a1, uint8_t a2) { +  char v = (a1 & a2); +  if ( v <= 47 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func270(uint8_t a1, uint8_t a2) { +  char v = (a1 & a2); +  if ( v > 63 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func271(uint8_t a1, uint8_t a2) { +  char v = (a1 & a2); +  if ( v > 122 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func272(uint8_t a1) { +  char v = 4 * a1; +  if ( v <= 65 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func273(uint8_t a1, uint8_t a2) { +  char v = (a1 & a2); +  if ( v > 120 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func274(uint8_t a1) { +  char v = 4 * a1; +  if ( v <= 83 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func275(uint8_t a1, uint8_t a2) { +  char v = a1 | a2; +  if ( v <= 99 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func276(uint8_t a1) { +  char v = ~a1; +  if ( v > 1 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func277(uint8_t a1) { +  char v = a1 >> 5; +  if ( v > 42 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func278(uint8_t a1) { +  char v = ~a1; +  if ( v > 1 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func279(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v > 110 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func280(uint8_t a1) { +  char v = 4 * a1; +  if ( v <= 92 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func281(uint8_t a1, uint8_t a2) { +  char v = a1 | a2; +  if ( v <= 59 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func282(uint8_t a1, uint8_t a2) { +  char v = a1 | a2; +  if ( v <= 1 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func283(uint8_t a1) { +  char v = ~a1; +  if ( v > 1 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func284(uint8_t a1) { +  char v = ~a1; +  if ( v > 1 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func285(uint8_t a1) { +  char v = ~a1; +  if ( v > 17 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func286(uint8_t a1) { +  char v = ~a1; +  if ( v > 1 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func287(uint8_t a1, uint8_t a2) { +  char v = a1 | a2; +  if ( v <= 78 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func288(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v > 47 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func289(uint8_t a1, uint8_t a2) { +  char v = (a1 & a2); +  if ( v <= 90 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func290(uint8_t a1) { +  char v = 16 * a1; +  if ( v <= 78 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func291(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v <= 30 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func292(uint8_t a1) { +  char v = ~a1; +  if ( v > 1 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func293(uint8_t a1) { +  char v = ~a1; +  if ( v > 1 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func294(uint8_t a1) { +  char v = ~a1; +  if ( v > 1 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func295(uint8_t a1, uint8_t a2) { +  char v = a1 | a2; +  if ( v <= 17 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func296(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v > 86 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func297(uint8_t a1, uint8_t a2) { +  char v = (a1 & a2); +  if ( v > 120 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func298(uint8_t a1) { +  char v = 16 * a1; +  if ( v <= 46 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func299(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v > 63 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func300(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v <= 5 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func301(uint8_t a1) { +  char v = ~a1; +  if ( v > 17 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func302(uint8_t a1) { +  char v = ~a1; +  if ( v > 113 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func303(uint8_t a1) { +  char v = ~a1; +  if ( v > 1 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func304(uint8_t a1, uint8_t a2) { +  char v = a1 | a2; +  if ( v <= 73 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func305(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v > 60 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func306(uint8_t a1, uint8_t a2) { +  char v = (a1 & a2); +  if ( v > 119 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func307(uint8_t a1) { +  char v = ~a1; +  if ( v > 21 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func308(uint8_t a1) { +  char v = ~a1; +  if ( v > 107 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func309(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v > 44 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func310(uint8_t a1, uint8_t a2) { +  char v = (a1 & a2); +  if ( v <= 57 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func311(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v > 59 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func312(uint8_t a1) { +  char v = ~a1; +  if ( v > 1 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func313(uint8_t a1) { +  char v = ~a1; +  if ( v > 1 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func314(uint8_t a1) { +  char v = a1 >> 5; +  if ( v > 58 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func315(uint8_t a1) { +  char v = ~a1; +  if ( v > 1 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func316(uint8_t a1, uint8_t a2) { +  char v = a1 | a2; +  if ( v <= 101 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func317(uint8_t a1, uint8_t a2) { +  char v = (a1 & a2); +  if ( v <= 99 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func318(uint8_t a1) { +  char v = 16 * a1; +  if ( v <= 78 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func319(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v > 16 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func320(uint8_t a1) { +  char v = ~a1; +  if ( v > 10 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func321(uint8_t a1) { +  char v = ~a1; +  if ( v > 1 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func322(uint8_t a1) { +  char v = a1 >> 5; +  if ( v > 3 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func323(uint8_t a1) { +  char v = ~a1; +  if ( v > 1 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func324(uint8_t a1, uint8_t a2) { +  char v = a1 | a2; +  if ( v > 118 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func325(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v <= 1 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func326(uint8_t a1) { +  char v = 16 * a1; +  if ( v <= 0 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func327(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v > 101 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func328(uint8_t a1) { +  char v = a1 >> 5; +  if ( v > 18 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func329(uint8_t a1) { +  char v = ~a1; +  if ( v > 1 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func330(uint8_t a1, uint8_t a2) { +  char v = a1 | a2; +  if ( v <= 0 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func331(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v > 67 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func332(uint8_t a1, uint8_t a2) { +  char v = (a1 & a2); +  if ( v > 103 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func333(uint8_t a1) { +  char v = 16 * a1; +  if ( v > 1 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func334(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v <= 38 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func335(uint8_t a1) { +  char v = ~a1; +  if ( v > 1 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func336(uint8_t a1, uint8_t a2) { +  char v = (a1 & a2); +  if ( v <= 94 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func337(uint8_t a1) { +  char v = (char)a1 >> 1; +  if ( v > 63 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func338(uint8_t a1) { +  char v = ~a1; +  if ( v > 1 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func339(uint8_t a1) { +  char v = (char)a1 >> 1; +  if ( v <= 47 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func340(uint8_t a1) { +  char v = a1 >> 5; +  if ( v <= 0 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func341(uint8_t a1) { +  char v = ~a1; +  if ( v > 1 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func342(uint8_t a1, uint8_t a2) { +  char v = a1 | a2; +  if ( v > 118 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func343(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v > 58 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func344(uint8_t a1, uint8_t a2) { +  char v = (a1 & a2); +  if ( v <= 91 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func345(uint8_t a1) { +  char v = 16 * a1; +  if ( v <= 72 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func346(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v > 63 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func347(uint8_t a1) { +  char v = ~a1; +  if ( v > 1 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func348(uint8_t a1, uint8_t a2) { +  char v = (a1 & a2); +  if ( v <= 94 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func349(uint8_t a1) { +  char v = (char)a1 >> 1; +  if ( v <= 57 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func350(uint8_t a1) { +  char v = ~a1; +  if ( v > 1 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func351(uint8_t a1, uint8_t a2) { +  char v = (a1 & a2); +  if ( v > 99 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func352(uint8_t a1) { +  char v = (char)a1 >> 1; +  if ( v > 63 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func353(uint8_t a1) { +  char v = a1 >> 5; +  if ( v > 81 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func354(uint8_t a1) { +  char v = ~a1; +  if ( v > 1 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func355(uint8_t a1, uint8_t a2) { +  char v = a1 | a2; +  if ( v > 118 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func356(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v > 1 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func357(uint8_t a1, uint8_t a2) { +  char v = (a1 & a2); +  if ( v <= 72 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func358(uint8_t a1) { +  char v = 16 * a1; +  if ( v > 1 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func359(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v > 110 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func360(uint8_t a1) { +  char v = ~a1; +  if ( v > 1 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func361(uint8_t a1, uint8_t a2) { +  char v = (a1 & a2); +  if ( v <= 68 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func362(uint8_t a1) { +  char v = (char)a1 >> 1; +  if ( v > 91 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func363(uint8_t a1) { +  char v = ~a1; +  if ( v > 1 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func364(uint8_t a1, uint8_t a2) { +  char v = (a1 & a2); +  if ( v > 99 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func365(uint8_t a1) { +  char v = (char)a1 >> 1; +  if ( v <= 40 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func366(uint8_t a1) { +  char v = (char)a1 >> 1; +  if ( v <= 31 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func367(uint8_t a1) { +  char v = ~a1; +  if ( v > 1 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func368(uint8_t a1) { +  char v = a1 >> 5; +  if ( v > 96 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func369(uint8_t a1) { +  char v = ~a1; +  if ( v > 1 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func370(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v > 42 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func371(uint8_t a1, uint8_t a2) { +  char v = (a1 & a2); +  if ( v > 118 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func372(uint8_t a1) { +  char v = (char)a1 >> 1; +  if ( v > 94 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func373(uint8_t a1) { +  char v = ~a1; +  if ( v > 1 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func374(uint8_t a1) { +  char v = ~a1; +  if ( v > 1 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func375(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v > 64 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func376(uint8_t a1, uint8_t a2) { +  char v = (a1 & a2); +  if ( v > 110 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func377(uint8_t a1) { +  char v = 4 * a1; +  if ( v <= 104 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func378(uint8_t a1, uint8_t a2) { +  char v = a1 | a2; +  if ( v > 112 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func379(uint8_t a1, uint8_t a2) { +  char v = (a1 & a2); +  if ( v <= 62 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func380(uint8_t a1, uint8_t a2) { +  char v = (a1 & a2); +  if ( v > 48 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func381(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v > 58 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func382(uint8_t a1) { +  char v = 4 * a1; +  if ( v <= 104 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func383(uint8_t a1, uint8_t a2) { +  char v = a1 | a2; +  if ( v <= 50 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func384(uint8_t a1, uint8_t a2) { +  char v = (a1 & a2); +  if ( v <= 38 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func385(uint8_t a1, uint8_t a2) { +  char v = (a1 & a2); +  if ( v > 85 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func386(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v <= 18 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func387(uint8_t a1) { +  char v = 4 * a1; +  if ( v <= 97 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func388(uint8_t a1, uint8_t a2) { +  char v = a1 | a2; +  if ( v <= 94 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func389(uint8_t a1, uint8_t a2) { +  char v = (a1 & a2); +  if ( v <= 26 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func390(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v > 67 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func391(uint8_t a1) { +  char v = 4 * a1; +  if ( v <= 103 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func392(uint8_t a1, uint8_t a2) { +  char v = (a1 & a2); +  if ( v > 50 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func393(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v <= 22 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func394(uint8_t a1) { +  char v = 4 * a1; +  if ( v <= 103 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func395(uint8_t a1, uint8_t a2) { +  char v = a1 | a2; +  if ( v <= 38 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func396(uint8_t a1, uint8_t a2) { +  char v = (a1 & a2); +  if ( v <= 52 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func397(uint8_t a1, uint8_t a2) { +  char v = (a1 & a2); +  if ( v <= 17 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func398(uint8_t a1) { +  char v = 4 * a1; +  if ( v > 1 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func399(uint8_t a1, uint8_t a2) { +  char v = a1 | a2; +  if ( v <= 92 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func400(uint8_t a1, uint8_t a2) { +  char v = (a1 & a2); +  if ( v <= 55 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func401(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v > 81 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func402(uint8_t a1) { +  char v = 4 * a1; +  if ( v > 1 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func403(uint8_t a1, uint8_t a2) { +  char v = a1 | a2; +  if ( v <= 94 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func404(uint8_t a1) { +  char v = ~a1; +  if ( v > 1 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func405(uint8_t a1) { +  char v = ~a1; +  if ( v > 1 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func406(uint8_t a1, uint8_t a2) { +  char v = (a1 ^ a2); +  if ( v > 101 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func407(uint8_t a1) { +  char v = 4 * a1; +  if ( v > 1 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func408(uint8_t a1, uint8_t a2) { +  char v = a1 | a2; +  if ( v <= 44 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func409(uint8_t a1) { +  char v = ~a1; +  if ( v > 1 ) +    return 0; +  return 1; +} + +__attribute__((noinline)) +int func410(uint8_t a1) { +  char v = ~a1; +  if ( v > 1 ) +    return 0; +  return 1; +} + +int api(const uint8_t *data, size_t size) { +  if (size != 20) return 0; + +  if (func1(data[0], data[1]) == 0) +    return 0; +  if (func2(data[0], data[1]) == 0) +    return 0; +  if (func3(data[18], data[1]) == 0) +    return 0; +  if (func4(data[7], data[4], data[0]) == 0) +    return 0; +  if (func5(data[0], data[2]) == 0) +    return 0; +  if (func6(data[11], data[17]) == 0) +    return 0; +  if (func7(data[0], data[13]) == 0) +    return 0; +  if (func8(data[13], data[10]) == 0) +    return 0; +  if (func9(data[11], data[16]) == 0) +    return 0; +  if (func10(data[10], data[8]) == 0) +    return 0; +  if (func11(data[19], data[5]) == 0) +    return 0; +  if (func12(data[0], data[1]) == 0) +    return 0; +  if (func13(data[17], data[3]) == 0) +    return 0; +  if (func14(data[14]) == 0) +    return 0; +  if (func15(data[13], data[15]) == 0) +    return 0; +  if (func16(data[0]) == 0) +    return 0; +  if (func17(data[19]) == 0) +    return 0; +  if (func18(data[1], data[11]) == 0) +    return 0; +  if (func19(data[12], data[15]) == 0) +    return 0; +  if (func20(data[13], data[1]) == 0) +    return 0; +  if (func21(data[10], data[19], data[12]) == 0) +    return 0; +  if (func22(data[6]) == 0) +    return 0; +  if (func23(data[1], data[9]) == 0) +    return 0; +  if (func24(data[16]) == 0) +    return 0; +  if (func25(data[6]) == 0) +    return 0; +  if (func26(data[4], data[12]) == 0) +    return 0; +  if (func27(data[16]) == 0) +    return 0; +  if (func28(data[14]) == 0) +    return 0; +  if (func29(data[0]) == 0) +    return 0; +  if (func30(data[19]) == 0) +    return 0; +  if (func31(data[0], data[1]) == 0) +    return 0; +  if (func32(data[0], data[1]) == 0) +    return 0; +  if (func33(data[14]) == 0) +    return 0; +  if (func34(data[0], data[19]) == 0) +    return 0; +  if (func35(data[0]) == 0) +    return 0; +  if (func36(data[16], data[7]) == 0) +    return 0; +  if (func37(data[19]) == 0) +    return 0; +  if (func38(data[15], data[3]) == 0) +    return 0; +  if (func39(data[19], data[15]) == 0) +    return 0; +  if (func40(data[0], data[1]) == 0) +    return 0; +  if (func41(data[18], data[1]) == 0) +    return 0; +  if (func42(data[16], data[5], data[1]) == 0) +    return 0; +  if (func43(data[14]) == 0) +    return 0; +  if (func44(data[0]) == 0) +    return 0; +  if (func45(data[19]) == 0) +    return 0; +  if (func46(data[4], data[19]) == 0) +    return 0; +  if (func47(data[8], data[7]) == 0) +    return 0; +  if (func48(data[6], data[7]) == 0) +    return 0; +  if (func49(data[18], data[1]) == 0) +    return 0; +  if (func50(data[2], data[8]) == 0) +    return 0; +  if (func51(data[2], data[13]) == 0) +    return 0; +  if (func52(data[3], data[8]) == 0) +    return 0; +  if (func53(data[16], data[18]) == 0) +    return 0; +  if (func54(data[10], data[9]) == 0) +    return 0; +  if (func55(data[18], data[1]) == 0) +    return 0; +  if (func56(data[0], data[1]) == 0) +    return 0; +  if (func57(data[16], data[1]) == 0) +    return 0; +  if (func58(data[18], data[1]) == 0) +    return 0; +  if (func59(data[18], data[3]) == 0) +    return 0; +  if (func60(data[9], data[1]) == 0) +    return 0; +  if (func61(data[0], data[1]) == 0) +    return 0; +  if (func62(data[13], data[1]) == 0) +    return 0; +  if (func63(data[18], data[1]) == 0) +    return 0; +  if (func64(data[0], data[1]) == 0) +    return 0; +  if (func65(data[0], data[1]) == 0) +    return 0; +  if (func66(data[11], data[14]) == 0) +    return 0; +  if (func67(data[5], data[11]) == 0) +    return 0; +  if (func68(data[18], data[1]) == 0) +    return 0; +  if (func69(data[0], data[6]) == 0) +    return 0; +  if (func70(data[2]) == 0) +    return 0; +  if (func71(data[0], data[1]) == 0) +    return 0; +  if (func72(data[9], data[10]) == 0) +    return 0; +  if (func73(data[10], data[8]) == 0) +    return 0; +  if (func74(data[19], data[17]) == 0) +    return 0; +  if (func75(data[0], data[17], data[8]) == 0) +    return 0; +  if (func76(data[17], data[18]) == 0) +    return 0; +  if (func77(data[18], data[9]) == 0) +    return 0; +  if (func78(data[3], data[6]) == 0) +    return 0; +  if (func79(data[16]) == 0) +    return 0; +  if (func80(data[7], data[3], data[17]) == 0) +    return 0; +  if (func81(data[0], data[1]) == 0) +    return 0; +  if (func82(data[10], data[18]) == 0) +    return 0; +  if (func83(data[6], data[7]) == 0) +    return 0; +  if (func84(data[0], data[6]) == 0) +    return 0; +  if (func85(data[12]) == 0) +    return 0; +  if (func86(data[0], data[1]) == 0) +    return 0; +  if (func87(data[6], data[1]) == 0) +    return 0; +  if (func88(data[18], data[1]) == 0) +    return 0; +  if (func89(data[0], data[6]) == 0) +    return 0; +  if (func90(data[0], data[1]) == 0) +    return 0; +  if (func91(data[18], data[1]) == 0) +    return 0; +  if (func92(data[0], data[6]) == 0) +    return 0; +  if (func93(data[13], data[10]) == 0) +    return 0; +  if (func94(data[2]) == 0) +    return 0; +  if (func95(data[0], data[1]) == 0) +    return 0; +  if (func96(data[0], data[11]) == 0) +    return 0; +  if (func97(data[18], data[1]) == 0) +    return 0; +  if (func98(data[0], data[6]) == 0) +    return 0; +  if (func99(data[0], data[19]) == 0) +    return 0; +  if (func100(data[14], data[18], data[3]) == 0) +    return 0; +  if (func101(data[14]) == 0) +    return 0; +  if (func102(data[6], data[1]) == 0) +    return 0; +  if (func103(data[5], data[1]) == 0) +    return 0; +  if (func104(data[14], data[3], data[10]) == 0) +    return 0; +  if (func105(data[18], data[1]) == 0) +    return 0; +  if (func106(data[0], data[6]) == 0) +    return 0; +  if (func107(data[6]) == 0) +    return 0; +  if (func108(data[9], data[10]) == 0) +    return 0; +  if (func109(data[7]) == 0) +    return 0; +  if (func110(data[9], data[17]) == 0) +    return 0; +  if (func111(data[16], data[15], data[18]) == 0) +    return 0; +  if (func112(data[0], data[16]) == 0) +    return 0; +  if (func113(data[18], data[3]) == 0) +    return 0; +  if (func114(data[3]) == 0) +    return 0; +  if (func115(data[0], data[1]) == 0) +    return 0; +  if (func116(data[14]) == 0) +    return 0; +  if (func117(data[0]) == 0) +    return 0; +  if (func118(data[19]) == 0) +    return 0; +  if (func119(data[0], data[6]) == 0) +    return 0; +  if (func120(data[9], data[5], data[0]) == 0) +    return 0; +  if (func121(data[0], data[1]) == 0) +    return 0; +  if (func122(data[12], data[4]) == 0) +    return 0; +  if (func123(data[14]) == 0) +    return 0; +  if (func124(data[0]) == 0) +    return 0; +  if (func125(data[19]) == 0) +    return 0; +  if (func126(data[14]) == 0) +    return 0; +  if (func127(data[1], data[9]) == 0) +    return 0; +  if (func128(data[19]) == 0) +    return 0; +  if (func129(data[11], data[14]) == 0) +    return 0; +  if (func130(data[11], data[9]) == 0) +    return 0; +  if (func131(data[12], data[15]) == 0) +    return 0; +  if (func132(data[0], data[2]) == 0) +    return 0; +  if (func133(data[13], data[1]) == 0) +    return 0; +  if (func134(data[7]) == 0) +    return 0; +  if (func135(data[13], data[5]) == 0) +    return 0; +  if (func136(data[12], data[14]) == 0) +    return 0; +  if (func137(data[9], data[4]) == 0) +    return 0; +  if (func138(data[6]) == 0) +    return 0; +  if (func139(data[14]) == 0) +    return 0; +  if (func140(data[0]) == 0) +    return 0; +  if (func141(data[19]) == 0) +    return 0; +  if (func142(data[11], data[9]) == 0) +    return 0; +  if (func143(data[12], data[15]) == 0) +    return 0; +  if (func144(data[7]) == 0) +    return 0; +  if (func145(data[19], data[7]) == 0) +    return 0; +  if (func146(data[4], data[6]) == 0) +    return 0; +  if (func147(data[6]) == 0) +    return 0; +  if (func148(data[0]) == 0) +    return 0; +  if (func149(data[19]) == 0) +    return 0; +  if (func150(data[11], data[9]) == 0) +    return 0; +  if (func151(data[12], data[15]) == 0) +    return 0; +  if (func152(data[13], data[1]) == 0) +    return 0; +  if (func153(data[7]) == 0) +    return 0; +  if (func154(data[2], data[8]) == 0) +    return 0; +  if (func155(data[13], data[5]) == 0) +    return 0; +  if (func156(data[6]) == 0) +    return 0; +  if (func157(data[6]) == 0) +    return 0; +  if (func158(data[14]) == 0) +    return 0; +  if (func159(data[0]) == 0) +    return 0; +  if (func160(data[19]) == 0) +    return 0; +  if (func161(data[12], data[15]) == 0) +    return 0; +  if (func162(data[5]) == 0) +    return 0; +  if (func163(data[6], data[7], data[3]) == 0) +    return 0; +  if (func164(data[13], data[5]) == 0) +    return 0; +  if (func165(data[6]) == 0) +    return 0; +  if (func166(data[14]) == 0) +    return 0; +  if (func167(data[0]) == 0) +    return 0; +  if (func168(data[19]) == 0) +    return 0; +  if (func169(data[11], data[9]) == 0) +    return 0; +  if (func170(data[9], data[11]) == 0) +    return 0; +  if (func171(data[6]) == 0) +    return 0; +  if (func172(data[14]) == 0) +    return 0; +  if (func173(data[19]) == 0) +    return 0; +  if (func174(data[11], data[9]) == 0) +    return 0; +  if (func175(data[12], data[15]) == 0) +    return 0; +  if (func176(data[7]) == 0) +    return 0; +  if (func177(data[13], data[5]) == 0) +    return 0; +  if (func178(data[0]) == 0) +    return 0; +  if (func179(data[19]) == 0) +    return 0; +  if (func180(data[11], data[9]) == 0) +    return 0; +  if (func181(data[12], data[15]) == 0) +    return 0; +  if (func182(data[13], data[1]) == 0) +    return 0; +  if (func183(data[7], data[17]) == 0) +    return 0; +  if (func184(data[7]) == 0) +    return 0; +  if (func185(data[6]) == 0) +    return 0; +  if (func186(data[4], data[12]) == 0) +    return 0; +  if (func187(data[2], data[8]) == 0) +    return 0; +  if (func188(data[16]) == 0) +    return 0; +  if (func189(data[6]) == 0) +    return 0; +  if (func190(data[4], data[12]) == 0) +    return 0; +  if (func191(data[16]) == 0) +    return 0; +  if (func192(data[19]) == 0) +    return 0; +  if (func193(data[19], data[4], data[2]) == 0) +    return 0; +  if (func194(data[11], data[9]) == 0) +    return 0; +  if (func195(data[12], data[15]) == 0) +    return 0; +  if (func196(data[13], data[15]) == 0) +    return 0; +  if (func197(data[13], data[1]) == 0) +    return 0; +  if (func198(data[19], data[5]) == 0) +    return 0; +  if (func199(data[13], data[5]) == 0) +    return 0; +  if (func200(data[6]) == 0) +    return 0; +  if (func201(data[4], data[12]) == 0) +    return 0; +  if (func202(data[5], data[17]) == 0) +    return 0; +  if (func203(data[16]) == 0) +    return 0; +  if (func204(data[6]) == 0) +    return 0; +  if (func205(data[7], data[3], data[17]) == 0) +    return 0; +  if (func206(data[4], data[12]) == 0) +    return 0; +  if (func207(data[16]) == 0) +    return 0; +  if (func208(data[0]) == 0) +    return 0; +  if (func209(data[19]) == 0) +    return 0; +  if (func210(data[11], data[9]) == 0) +    return 0; +  if (func211(data[13], data[1]) == 0) +    return 0; +  if (func212(data[7]) == 0) +    return 0; +  if (func213(data[13], data[5]) == 0) +    return 0; +  if (func214(data[6]) == 0) +    return 0; +  if (func215(data[4], data[12]) == 0) +    return 0; +  if (func216(data[6]) == 0) +    return 0; +  if (func217(data[4], data[12]) == 0) +    return 0; +  if (func218(data[16]) == 0) +    return 0; +  if (func219(data[16]) == 0) +    return 0; +  if (func220(data[0]) == 0) +    return 0; +  if (func221(data[19]) == 0) +    return 0; +  if (func222(data[0], data[1]) == 0) +    return 0; +  if (func223(data[0], data[1]) == 0) +    return 0; +  if (func224(data[14]) == 0) +    return 0; +  if (func225(data[0]) == 0) +    return 0; +  if (func226(data[19]) == 0) +    return 0; +  if (func227(data[0], data[1]) == 0) +    return 0; +  if (func228(data[0], data[1]) == 0) +    return 0; +  if (func229(data[18], data[1]) == 0) +    return 0; +  if (func230(data[0], data[1]) == 0) +    return 0; +  if (func231(data[17], data[3]) == 0) +    return 0; +  if (func232(data[0], data[1]) == 0) +    return 0; +  if (func233(data[18], data[1]) == 0) +    return 0; +  if (func234(data[0], data[1]) == 0) +    return 0; +  if (func235(data[18], data[4]) == 0) +    return 0; +  if (func236(data[18], data[1]) == 0) +    return 0; +  if (func237(data[0], data[1]) == 0) +    return 0; +  if (func238(data[2], data[8]) == 0) +    return 0; +  if (func239(data[13], data[0]) == 0) +    return 0; +  if (func240(data[0], data[1]) == 0) +    return 0; +  if (func241(data[0], data[1]) == 0) +    return 0; +  if (func242(data[18], data[1]) == 0) +    return 0; +  if (func243(data[0], data[6]) == 0) +    return 0; +  if (func244(data[2]) == 0) +    return 0; +  if (func245(data[0], data[1]) == 0) +    return 0; +  if (func246(data[1], data[11]) == 0) +    return 0; +  if (func247(data[18], data[1]) == 0) +    return 0; +  if (func248(data[0], data[6]) == 0) +    return 0; +  if (func249(data[2]) == 0) +    return 0; +  if (func250(data[0], data[1]) == 0) +    return 0; +  if (func251(data[4], data[6]) == 0) +    return 0; +  if (func252(data[0], data[1]) == 0) +    return 0; +  if (func253(data[18], data[1]) == 0) +    return 0; +  if (func254(data[16], data[15], data[18]) == 0) +    return 0; +  if (func255(data[0], data[6]) == 0) +    return 0; +  if (func256(data[2]) == 0) +    return 0; +  if (func257(data[16], data[18]) == 0) +    return 0; +  if (func258(data[0], data[1]) == 0) +    return 0; +  if (func259(data[0], data[6]) == 0) +    return 0; +  if (func260(data[9], data[13]) == 0) +    return 0; +  if (func261(data[2]) == 0) +    return 0; +  if (func262(data[2]) == 0) +    return 0; +  if (func263(data[0], data[1]) == 0) +    return 0; +  if (func264(data[0], data[1]) == 0) +    return 0; +  if (func265(data[0], data[6]) == 0) +    return 0; +  if (func266(data[7], data[4]) == 0) +    return 0; +  if (func267(data[16], data[7]) == 0) +    return 0; +  if (func268(data[0], data[1]) == 0) +    return 0; +  if (func269(data[0], data[1]) == 0) +    return 0; +  if (func270(data[18], data[1]) == 0) +    return 0; +  if (func271(data[13], data[3]) == 0) +    return 0; +  if (func272(data[2]) == 0) +    return 0; +  if (func273(data[0], data[1]) == 0) +    return 0; +  if (func274(data[2]) == 0) +    return 0; +  if (func275(data[0], data[1]) == 0) +    return 0; +  if (func276(data[14]) == 0) +    return 0; +  if (func277(data[0]) == 0) +    return 0; +  if (func278(data[19]) == 0) +    return 0; +  if (func279(data[0], data[6]) == 0) +    return 0; +  if (func280(data[2]) == 0) +    return 0; +  if (func281(data[0], data[1]) == 0) +    return 0; +  if (func282(data[8], data[0]) == 0) +    return 0; +  if (func283(data[14]) == 0) +    return 0; +  if (func284(data[19]) == 0) +    return 0; +  if (func285(data[14]) == 0) +    return 0; +  if (func286(data[19]) == 0) +    return 0; +  if (func287(data[11], data[9]) == 0) +    return 0; +  if (func288(data[12], data[15]) == 0) +    return 0; +  if (func289(data[13], data[1]) == 0) +    return 0; +  if (func290(data[7]) == 0) +    return 0; +  if (func291(data[13], data[5]) == 0) +    return 0; +  if (func292(data[6]) == 0) +    return 0; +  if (func293(data[14]) == 0) +    return 0; +  if (func294(data[19]) == 0) +    return 0; +  if (func295(data[11], data[9]) == 0) +    return 0; +  if (func296(data[12], data[15]) == 0) +    return 0; +  if (func297(data[12], data[4]) == 0) +    return 0; +  if (func298(data[7]) == 0) +    return 0; +  if (func299(data[13], data[5]) == 0) +    return 0; +  if (func300(data[12], data[14]) == 0) +    return 0; +  if (func301(data[6]) == 0) +    return 0; +  if (func302(data[14]) == 0) +    return 0; +  if (func303(data[19]) == 0) +    return 0; +  if (func304(data[11], data[9]) == 0) +    return 0; +  if (func305(data[12], data[15]) == 0) +    return 0; +  if (func306(data[13], data[1]) == 0) +    return 0; +  if (func307(data[6]) == 0) +    return 0; +  if (func308(data[19]) == 0) +    return 0; +  if (func309(data[12], data[15]) == 0) +    return 0; +  if (func310(data[13], data[1]) == 0) +    return 0; +  if (func311(data[13], data[5]) == 0) +    return 0; +  if (func312(data[6]) == 0) +    return 0; +  if (func313(data[14]) == 0) +    return 0; +  if (func314(data[0]) == 0) +    return 0; +  if (func315(data[9]) == 0) +    return 0; +  if (func316(data[11], data[9]) == 0) +    return 0; +  if (func317(data[13], data[1]) == 0) +    return 0; +  if (func318(data[7]) == 0) +    return 0; +  if (func319(data[13], data[4]) == 0) +    return 0; +  if (func320(data[16]) == 0) +    return 0; +  if (func321(data[4]) == 0) +    return 0; +  if (func322(data[0]) == 0) +    return 0; +  if (func323(data[19]) == 0) +    return 0; +  if (func324(data[11], data[9]) == 0) +    return 0; +  if (func325(data[12], data[15]) == 0) +    return 0; +  if (func326(data[7]) == 0) +    return 0; +  if (func327(data[13], data[5]) == 0) +    return 0; +  if (func328(data[0]) == 0) +    return 0; +  if (func329(data[19]) == 0) +    return 0; +  if (func330(data[11], data[9]) == 0) +    return 0; +  if (func331(data[12], data[15]) == 0) +    return 0; +  if (func332(data[13], data[1]) == 0) +    return 0; +  if (func333(data[4]) == 0) +    return 0; +  if (func334(data[13], data[5]) == 0) +    return 0; +  if (func335(data[6]) == 0) +    return 0; +  if (func336(data[4], data[12]) == 0) +    return 0; +  if (func337(data[16]) == 0) +    return 0; +  if (func338(data[6]) == 0) +    return 0; +  if (func339(data[16]) == 0) +    return 0; +  if (func340(data[0]) == 0) +    return 0; +  if (func341(data[19]) == 0) +    return 0; +  if (func342(data[11], data[9]) == 0) +    return 0; +  if (func343(data[12], data[15]) == 0) +    return 0; +  if (func344(data[13], data[1]) == 0) +    return 0; +  if (func345(data[7]) == 0) +    return 0; +  if (func346(data[13], data[5]) == 0) +    return 0; +  if (func347(data[6]) == 0) +    return 0; +  if (func348(data[4], data[12]) == 0) +    return 0; +  if (func349(data[16]) == 0) +    return 0; +  if (func350(data[6]) == 0) +    return 0; +  if (func351(data[4], data[12]) == 0) +    return 0; +  if (func352(data[16]) == 0) +    return 0; +  if (func353(data[0]) == 0) +    return 0; +  if (func354(data[19]) == 0) +    return 0; +  if (func355(data[11], data[9]) == 0) +    return 0; +  if (func356(data[8], data[15]) == 0) +    return 0; +  if (func357(data[7], data[1]) == 0) +    return 0; +  if (func358(data[17]) == 0) +    return 0; +  if (func359(data[3], data[5]) == 0) +    return 0; +  if (func360(data[6]) == 0) +    return 0; +  if (func361(data[4], data[12]) == 0) +    return 0; +  if (func362(data[16]) == 0) +    return 0; +  if (func363(data[6]) == 0) +    return 0; +  if (func364(data[4], data[12]) == 0) +    return 0; +  if (func365(data[16]) == 0) +    return 0; +  if (func366(data[16]) == 0) +    return 0; +  if (func367(data[14]) == 0) +    return 0; +  if (func368(data[0]) == 0) +    return 0; +  if (func369(data[19]) == 0) +    return 0; +  if (func370(data[3], data[1]) == 0) +    return 0; +  if (func371(data[4], data[1]) == 0) +    return 0; +  if (func372(data[16]) == 0) +    return 0; +  if (func373(data[14]) == 0) +    return 0; +  if (func374(data[19]) == 0) +    return 0; +  if (func375(data[0], data[1]) == 0) +    return 0; +  if (func376(data[0], data[1]) == 0) +    return 0; +  if (func377(data[2]) == 0) +    return 0; +  if (func378(data[0], data[1]) == 0) +    return 0; +  if (func379(data[0], data[1]) == 0) +    return 0; +  if (func380(data[18], data[1]) == 0) +    return 0; +  if (func381(data[0], data[6]) == 0) +    return 0; +  if (func382(data[2]) == 0) +    return 0; +  if (func383(data[8], data[1]) == 0) +    return 0; +  if (func384(data[5], data[1]) == 0) +    return 0; +  if (func385(data[18], data[1]) == 0) +    return 0; +  if (func386(data[0], data[6]) == 0) +    return 0; +  if (func387(data[2]) == 0) +    return 0; +  if (func388(data[0], data[1]) == 0) +    return 0; +  if (func389(data[18], data[1]) == 0) +    return 0; +  if (func390(data[0], data[6]) == 0) +    return 0; +  if (func391(data[2]) == 0) +    return 0; +  if (func392(data[18], data[1]) == 0) +    return 0; +  if (func393(data[0], data[6]) == 0) +    return 0; +  if (func394(data[2]) == 0) +    return 0; +  if (func395(data[0], data[1]) == 0) +    return 0; +  if (func396(data[0], data[1]) == 0) +    return 0; +  if (func397(data[18], data[1]) == 0) +    return 0; +  if (func398(data[9]) == 0) +    return 0; +  if (func399(data[0], data[1]) == 0) +    return 0; +  if (func400(data[0], data[1]) == 0) +    return 0; +  if (func401(data[8], data[6]) == 0) +    return 0; +  if (func402(data[12]) == 0) +    return 0; +  if (func403(data[0], data[1]) == 0) +    return 0; +  if (func404(data[12]) == 0) +    return 0; +  if (func405(data[1]) == 0) +    return 0; +  if (func406(data[0], data[6]) == 0) +    return 0; +  if (func407(data[4]) == 0) +    return 0; +  if (func408(data[0], data[1]) == 0) +    return 0; +  if (func409(data[14]) == 0) +    return 0; +  if (func410(data[14]) == 0) +    return 0; + +  fprintf(stderr, "BINGO\n"); +  abort(); +  return 1; +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { +  if (api(Data, Size)) { +    // Should've crashed before getting here. +    return 0; +  } +  return 0; +} + diff --git a/test/fuzzer/NullDerefTest.cpp b/test/fuzzer/NullDerefTest.cpp index 1b44b682ace68..48df0f54cfe0a 100644 --- a/test/fuzzer/NullDerefTest.cpp +++ b/test/fuzzer/NullDerefTest.cpp @@ -5,7 +5,7 @@  #include <cstddef>  #include <cstdint>  #include <cstdlib> -#include <iostream> +#include <cstdio>  static volatile int Sink;  static volatile int *Null = 0; @@ -16,7 +16,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {      if (Size > 1 && Data[1] == 'i') {        Sink = 2;        if (Size > 2 && Data[2] == '!') { -        std::cout << "Found the target, dereferencing NULL\n"; +        printf("Found the target, dereferencing NULL\n");          *Null = 1;        }      } diff --git a/test/fuzzer/OnlySomeBytesTest.cpp b/test/fuzzer/OnlySomeBytesTest.cpp new file mode 100644 index 0000000000000..076cda0634598 --- /dev/null +++ b/test/fuzzer/OnlySomeBytesTest.cpp @@ -0,0 +1,40 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// Find ABCxxFxUxZxxx... (2048+ bytes, 'x' is any byte) +#include <assert.h> +#include <cstddef> +#include <cstdint> +#include <cstdlib> +#include <cstring> +#include <cstdio> + +const size_t N = 2048; +typedef const uint8_t *IN; + +static volatile int one = 1; + +extern "C" { +__attribute__((noinline)) void bad() { +  fprintf(stderr, "BINGO\n"); +  if (one) +    abort(); +} + +__attribute__((noinline)) void f0(IN in) { +  uint32_t x = in[5] + 251 * in[7] + 251 * 251 * in[9]; +  if (x == 'F' + 251 * 'U' + 251 * 251 * 'Z') +    bad(); +} + +__attribute__((noinline)) void fC(IN in) { if (in[2] == 'C') f0(in); } +__attribute__((noinline)) void fB(IN in) { if (in[1] == 'B') fC(in); } +__attribute__((noinline)) void fA(IN in) { if (in[0] == 'A') fB(in); } + +} // extern "C" + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { +  if (Size < N) return 0; +  fA((IN)Data); +  return 0; +} diff --git a/test/fuzzer/PrintUnstableStatsTest.cpp b/test/fuzzer/PrintUnstableStatsTest.cpp new file mode 100644 index 0000000000000..078eb4c3d9713 --- /dev/null +++ b/test/fuzzer/PrintUnstableStatsTest.cpp @@ -0,0 +1,69 @@ +#include <assert.h> +#include <cstdint> +#include <cstdio> +#include <cstdlib> + +int x = 0; +bool skip0 = false; +bool skip1 = false; +bool skip2 = false; + +__attribute__((noinline)) void det0() { x++; } +__attribute__((noinline)) void det1() { x++; } +__attribute__((noinline)) void det2() { x++; } +__attribute__((noinline)) void det3() { x++; } +__attribute__((noinline)) void det4() { x++; } + +__attribute__((noinline)) void ini0() { x++; } +__attribute__((noinline)) void ini1() { x++; } +__attribute__((noinline)) void ini2() { x++; } + +__attribute__((noinline)) void t0() { x++; } +__attribute__((noinline)) void t1() { x++; } +__attribute__((noinline)) void t2() { x++; } +__attribute__((noinline)) void t3() { x++; } +__attribute__((noinline)) void t4() { x++; } + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { +  if (Size == 1 && Data[0] == 'A' && !skip0) { +    skip0 = true; +    ini0(); +  } +  if (Size == 1 && Data[0] == 'B' && !skip1) { +    skip1 = true; +    ini1(); +  } +  if (Size == 1 && Data[0] == 'C' && !skip2) { +    skip2 = true; +    ini2(); +  } + +  det0(); +  det1(); +  int a = rand(); +  det2(); + +  switch (a % 5) { +  case 0: +    t0(); +    break; +  case 1: +    t1(); +    break; +  case 2: +    t2(); +    break; +  case 3: +    t3(); +    break; +  case 4: +    t4(); +    break; +  default: +    assert(false); +  } + +  det3(); +  det4(); +  return 0; +} diff --git a/test/fuzzer/ShrinkValueProfileTest.cpp b/test/fuzzer/ShrinkValueProfileTest.cpp index 86e4e3cb0d9ae..dddf493da6977 100644 --- a/test/fuzzer/ShrinkValueProfileTest.cpp +++ b/test/fuzzer/ShrinkValueProfileTest.cpp @@ -1,7 +1,7 @@  // This file is distributed under the University of Illinois Open Source  // License. See LICENSE.TXT for details. -// Test that we can find the minimal item in the corpus (3 bytes: "FUZ"). +// Test that we can find the minimal item in the corpus (4 bytes: "FUZZ").  #include <cstddef>  #include <cstdint>  #include <cstdio> diff --git a/test/fuzzer/SimpleCmpTest.cpp b/test/fuzzer/SimpleCmpTest.cpp index 8acad4ac77e8f..3bb28c17318b2 100644 --- a/test/fuzzer/SimpleCmpTest.cpp +++ b/test/fuzzer/SimpleCmpTest.cpp @@ -17,15 +17,15 @@ bool PrintOnce(int Line) {  }  extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { -  if (Size != 22) return 0; +  if (Size != 24) return 0;    uint64_t x = 0;    int64_t  y = 0;    int32_t z = 0; -  uint16_t a = 0; +  uint32_t a = 0;    memcpy(&x, Data, 8);  // 8    memcpy(&y, Data + 8, 8);  // 16    memcpy(&z, Data + 16, sizeof(z));  // 20 -  memcpy(&a, Data + 20, sizeof(a));  // 22 +  memcpy(&a, Data + 20, sizeof(a));  // 24    const bool k32bit = sizeof(void*) == 4;    if ((k32bit || x > 1234567890) && PrintOnce(__LINE__) && diff --git a/test/fuzzer/SimpleTestStdio.cpp b/test/fuzzer/SimpleTestStdio.cpp new file mode 100644 index 0000000000000..ed7fe1cb3f679 --- /dev/null +++ b/test/fuzzer/SimpleTestStdio.cpp @@ -0,0 +1,26 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// Simple test for a fuzzer. The fuzzer must find the string "Hi!". +#include <assert.h> +#include <cstdint> +#include <cstdio> +#include <cstdlib> + +static volatile int Sink; + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { +  assert(Data); +  if (Size > 0 && Data[0] == 'H') { +    Sink = 1; +    if (Size > 1 && Data[1] == 'i') { +      Sink = 2; +      if (Size > 2 && Data[2] == '!') { +        fprintf(stderr, "BINGO; Found the target, exiting\n"); +        exit(0); +      } +    } +  } +  return 0; +} + diff --git a/test/fuzzer/SwapCmpTest.cpp b/test/fuzzer/SwapCmpTest.cpp index bbfbefe6ab710..5aa47beb22bbd 100644 --- a/test/fuzzer/SwapCmpTest.cpp +++ b/test/fuzzer/SwapCmpTest.cpp @@ -11,14 +11,14 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {    if (Size < 14) return 0;    uint64_t x = 0;    uint32_t y = 0; -  uint16_t z = 0; +  uint32_t z = 0;    memcpy(&x, Data, sizeof(x));    memcpy(&y, Data + Size / 2, sizeof(y));    memcpy(&z, Data + Size - sizeof(z), sizeof(z));    x = __builtin_bswap64(x);    y = __builtin_bswap32(y); -  z = __builtin_bswap16(z); +  z = __builtin_bswap32(z);    const bool k32bit = sizeof(void*) == 4;    if ((k32bit || x == 0x46555A5A5A5A5546ULL) && @@ -26,7 +26,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {        y == 0x66757A7A &&        true        ) { -    if (Data[Size - 3] == 'z') { +    if (Data[Size - 5] == 'z') {        fprintf(stderr, "BINGO; Found the target\n");        exit(1);      } diff --git a/test/fuzzer/SymbolizeDeadlock.cpp b/test/fuzzer/SymbolizeDeadlock.cpp new file mode 100644 index 0000000000000..5be1be804bcec --- /dev/null +++ b/test/fuzzer/SymbolizeDeadlock.cpp @@ -0,0 +1,35 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// Tests that deadlocks do not occur when an OOM occurs during symbolization. + +#include <cassert> +#include <cstdint> +#include <cstdio> +#include <cstdlib> +#include <cstring> +#include <unistd.h> + +#include "Bingo.h" + +volatile unsigned Sink = 0; + +// Do not inline this function.  We want to trigger NEW_FUNC symbolization when +// libFuzzer finds this function.  We use a macro to make the name as long +// possible, hoping to increase the time spent in symbolization and increase the +// chances of triggering a deadlock. +__attribute__((noinline)) void BINGO() { +  // Busy work.  Inserts a delay here so the deadlock is more likely to trigger. +  for (unsigned i = 0; i < 330000000; i++) Sink += i; +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { +  assert(Data); +  if (Size < 3) return 0; +  if (Data[0] == 'F' && +      Data[1] == 'U' && +      Data[2] == 'Z') +    BINGO(); +  return 0; +} + diff --git a/test/fuzzer/ThreadedLeakTest.cpp b/test/fuzzer/ThreadedLeakTest.cpp index 538d3b434808e..59f3671fe9db2 100644 --- a/test/fuzzer/ThreadedLeakTest.cpp +++ b/test/fuzzer/ThreadedLeakTest.cpp @@ -6,7 +6,7 @@  #include <cstdint>  #include <thread> -static volatile int *Sink; +static int * volatile Sink;  extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {    if (Size == 0) return 0; diff --git a/test/fuzzer/ThreeBytes.cpp b/test/fuzzer/ThreeBytes.cpp new file mode 100644 index 0000000000000..754a5b0b56a1e --- /dev/null +++ b/test/fuzzer/ThreeBytes.cpp @@ -0,0 +1,14 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// Find FUZ +#include <cstddef> +#include <cstdint> +#include <cstdlib> + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { +  if (Size < 3) return 0; +  uint32_t x = Data[0] + 251 * Data[1] + 251 * 251 * Data[2]; +  if (x == 'F' + 251 * 'U' + 251 * 251 * 'Z')     abort(); +  return 0; +} diff --git a/test/fuzzer/ThreeFunctionsTest.cpp b/test/fuzzer/ThreeFunctionsTest.cpp new file mode 100644 index 0000000000000..1278cb05633da --- /dev/null +++ b/test/fuzzer/ThreeFunctionsTest.cpp @@ -0,0 +1,36 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// Find "FUZZME", the target has 3 different functions. +#include <assert.h> +#include <cstddef> +#include <cstdint> +#include <cstdlib> +#include <cstdio> + +extern "C" +__attribute__((noinline)) +bool Func1(const uint8_t *Data, size_t Size) { +  // assumes Size >= 5, doesn't check it. +  return Data[4] == 'M'; +} + +extern "C" +__attribute__((noinline)) +bool Func2(const uint8_t *Data, size_t Size) { +  return Size >= 6 && Data[5] == 'E'; +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { +  if (Size >= 5 +      && Data[0] == 'F' +      && Data[1] == 'U' +      && Data[2] == 'Z' +      && Data[3] == 'Z' +      && Func1(Data, Size) +      && Func2(Data, Size)) { +        fprintf(stderr, "BINGO\n"); +        abort(); +  } +  return 0; +} diff --git a/test/fuzzer/TraceMallocThreadedTest.cpp b/test/fuzzer/TraceMallocThreadedTest.cpp index 5603af344cb7b..0183d939af51b 100644 --- a/test/fuzzer/TraceMallocThreadedTest.cpp +++ b/test/fuzzer/TraceMallocThreadedTest.cpp @@ -7,11 +7,12 @@  #include <cstddef>  #include <cstdint>  #include <cstring> +#include <cstdlib>  #include <thread>  extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {    auto C = [&] { -    volatile void *a = malloc(5639); +    void * volatile a = malloc(5639);      free((void *)a);    };    std::thread T[] = {std::thread(C), std::thread(C), std::thread(C), diff --git a/test/fuzzer/UninitializedStrlen.cpp b/test/fuzzer/UninitializedStrlen.cpp new file mode 100644 index 0000000000000..5a4e778df94bf --- /dev/null +++ b/test/fuzzer/UninitializedStrlen.cpp @@ -0,0 +1,14 @@ +#include <cstdint> +#include <cstring> + +volatile size_t Sink; + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { +  if (Size < 4) return 0; +  if (Data[0] == 'F' && Data[1] == 'U' && Data[2] == 'Z' && Data[3] == 'Z') { +    char uninit[7]; +    Sink = strlen(uninit); +  } +  return 0; +} + diff --git a/test/fuzzer/UseAfterDtor.cpp b/test/fuzzer/UseAfterDtor.cpp new file mode 100644 index 0000000000000..dcefca5cc7d58 --- /dev/null +++ b/test/fuzzer/UseAfterDtor.cpp @@ -0,0 +1,27 @@ +#include <cstdint> +#include <cstdio> + +struct Simple { +  int x_; +  Simple() { +    x_ = 5; +  } +  ~Simple() { +    x_ += 1; +  } +}; + +Simple *volatile SimpleSink; + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { +  if (Size < 4) return 0; +  if (Data[0] == 'F' && Data[1] == 'U' && Data[2] == 'Z' && Data[3] == 'Z') { +    { +      Simple S; +      SimpleSink = &S; +    } +    if (SimpleSink->x_) fprintf(stderr, "Failed to catch use-after-dtor\n"); +  } +  return 0; +} + diff --git a/test/fuzzer/acquire-crash-state.test b/test/fuzzer/acquire-crash-state.test new file mode 100644 index 0000000000000..952ec735be6f0 --- /dev/null +++ b/test/fuzzer/acquire-crash-state.test @@ -0,0 +1,3 @@ +RUN: %cpp_compiler %S/AcquireCrashStateTest.cpp -o %t +RUN: %run %t 2>&1 | FileCheck %s +CHECK-NOT: fuzz target exited diff --git a/test/fuzzer/afl-driver-extra-stats.test b/test/fuzzer/afl-driver-extra-stats.test index a6de53302002f..cddb683e6dec5 100644 --- a/test/fuzzer/afl-driver-extra-stats.test +++ b/test/fuzzer/afl-driver-extra-stats.test @@ -1,8 +1,9 @@ -RUN: %no_fuzzer_cpp_compiler -fno-sanitize-coverage=edge,trace-cmp,indirect-calls,8bit-counters,trace-pc-guard %S/AFLDriverTest.cpp %libfuzzer_src/afl/afl_driver.cpp -o %t-AFLDriverTest +XFAIL: ios +RUN: %no_fuzzer_cpp_compiler %S/AFLDriverTest.cpp %libfuzzer_src/afl/afl_driver.cpp -o %t-AFLDriverTest  ; Test that not specifying an extra stats file isn't broken.  RUN: unset AFL_DRIVER_EXTRA_STATS_FILENAME -RUN: %t-AFLDriverTest +RUN: %run %t-AFLDriverTest  ; Test that specifying an invalid extra stats file causes a crash.  RUN: ASAN_OPTIONS= AFL_DRIVER_EXTRA_STATS_FILENAME=%T not --crash %t-AFLDriverTest diff --git a/test/fuzzer/afl-driver-stderr.test b/test/fuzzer/afl-driver-stderr.test index be0efaa8f03ea..d3d739d3b977e 100644 --- a/test/fuzzer/afl-driver-stderr.test +++ b/test/fuzzer/afl-driver-stderr.test @@ -1,12 +1,14 @@ -RUN: %no_fuzzer_cpp_compiler -fno-sanitize-coverage=edge,trace-cmp,indirect-calls,8bit-counters,trace-pc-guard %S/AFLDriverTest.cpp %libfuzzer_src/afl/afl_driver.cpp -o %t-AFLDriverTest +XFAIL: ios +UNSUPPORTED: freebsd +RUN: %no_fuzzer_cpp_compiler %S/AFLDriverTest.cpp %libfuzzer_src/afl/afl_driver.cpp -o %t-AFLDriverTest  ; Test that not specifying a stderr file isn't broken.  RUN: unset AFL_DRIVER_STDERR_DUPLICATE_FILENAME -RUN: %t-AFLDriverTest +RUN: %run %t-AFLDriverTest  ; Test that specifying an invalid file causes a crash. -RUN: ASAN_OPTIONS= AFL_DRIVER_STDERR_DUPLICATE_FILENAME="%T" not --crash %t-AFLDriverTest +RUN: ASAN_OPTIONS= AFL_DRIVER_STDERR_DUPLICATE_FILENAME="%T" not --crash %run %t-AFLDriverTest  ; Test that a file is created when specified as the duplicate stderr. -RUN: AFL_DRIVER_STDERR_DUPLICATE_FILENAME=%t %t-AFLDriverTest +RUN: AFL_DRIVER_STDERR_DUPLICATE_FILENAME=%t %run %t-AFLDriverTest  RUN: stat %t diff --git a/test/fuzzer/afl-driver.test b/test/fuzzer/afl-driver.test index 32e7d03b43c0c..552bafb0bf346 100644 --- a/test/fuzzer/afl-driver.test +++ b/test/fuzzer/afl-driver.test @@ -1,29 +1,29 @@  REQUIRES: linux -RUN: %no_fuzzer_cpp_compiler -fno-sanitize-coverage=edge,trace-cmp,indirect-calls,8bit-counters,trace-pc-guard %S/AFLDriverTest.cpp %libfuzzer_src/afl/afl_driver.cpp -o %t-AFLDriverTest +RUN: %no_fuzzer_cpp_compiler %S/AFLDriverTest.cpp %libfuzzer_src/afl/afl_driver.cpp -o %t-AFLDriverTest  RUN: echo -n "abc" > %t.file3  RUN: echo -n "abcd" > %t.file4 -RUN: %t-AFLDriverTest < %t.file3 2>&1 | FileCheck %s --check-prefix=CHECK1 +RUN: %run %t-AFLDriverTest < %t.file3 2>&1 | FileCheck %s --check-prefix=CHECK1  CHECK1: __afl_persistent_loop calle, Count = 1000  CHECK1: LLVMFuzzerTestOneInput called; Size = 3 -RUN: %t-AFLDriverTest < %t.file3 -42 2>&1 | FileCheck %s --check-prefix=CHECK2 +RUN: %run %t-AFLDriverTest < %t.file3 -42 2>&1 | FileCheck %s --check-prefix=CHECK2  CHECK2: __afl_persistent_loop calle, Count = 42  CHECK2: LLVMFuzzerTestOneInput called; Size = 3 -RUN: %t-AFLDriverTest < %t.file3 666 2>&1 | FileCheck %s --check-prefix=CHECK3 +RUN: %run %t-AFLDriverTest < %t.file3 666 2>&1 | FileCheck %s --check-prefix=CHECK3  CHECK3: WARNING: using the deprecated call style  CHECK3: __afl_persistent_loop calle, Count = 666  CHECK3: LLVMFuzzerTestOneInput called; Size = 3 -RUN: %t-AFLDriverTest %t.file3 2>&1 | FileCheck %s --check-prefix=CHECK4 +RUN: %run %t-AFLDriverTest %t.file3 2>&1 | FileCheck %s --check-prefix=CHECK4  CHECK4: LLVMFuzzerTestOneInput called; Size = 3 -RUN: %t-AFLDriverTest %t.file3 %t.file4  2>&1 | FileCheck %s --check-prefix=CHECK5 +RUN: %run %t-AFLDriverTest %t.file3 %t.file4  2>&1 | FileCheck %s --check-prefix=CHECK5  CHECK5: LLVMFuzzerTestOneInput called; Size = 3  CHECK5: LLVMFuzzerTestOneInput called; Size = 4 diff --git a/test/fuzzer/bad-strcmp.test b/test/fuzzer/bad-strcmp.test index fd1621a4e1eb2..7fb2a6f073536 100644 --- a/test/fuzzer/bad-strcmp.test +++ b/test/fuzzer/bad-strcmp.test @@ -1,2 +1,2 @@  RUN: %cpp_compiler %S/BadStrcmpTest.cpp -o %t-BadStrcmpTest -RUN: %t-BadStrcmpTest -runs=100000 +RUN: %run %t-BadStrcmpTest -runs=100000 diff --git a/test/fuzzer/bogus-initialize.test b/test/fuzzer/bogus-initialize.test new file mode 100644 index 0000000000000..2dff2d5a26395 --- /dev/null +++ b/test/fuzzer/bogus-initialize.test @@ -0,0 +1,4 @@ +RUN: %cpp_compiler %S/BogusInitializeTest.cpp -o %t-BogusInitializeTest + +RUN: not %run %t-BogusInitializeTest 2>&1 | FileCheck %s --check-prefix=BOGUS_INITIALIZE +BOGUS_INITIALIZE: argv[0] has been modified in LLVMFuzzerInitialize diff --git a/test/fuzzer/buffer-overflow-on-input.test b/test/fuzzer/buffer-overflow-on-input.test new file mode 100644 index 0000000000000..6e40b75d70bcd --- /dev/null +++ b/test/fuzzer/buffer-overflow-on-input.test @@ -0,0 +1,5 @@ +RUN: %cpp_compiler %S/BufferOverflowOnInput.cpp -o %t-BufferOverflowOnInput + +RUN: not %run %t-BufferOverflowOnInput 2>&1 | FileCheck %s --check-prefix=OOB +OOB: AddressSanitizer: heap-buffer-overflow +OOB: is located 0 bytes to the right of 3-byte region diff --git a/test/fuzzer/caller-callee.test b/test/fuzzer/caller-callee.test index e4eccdc307adc..679e4a6f65a41 100644 --- a/test/fuzzer/caller-callee.test +++ b/test/fuzzer/caller-callee.test @@ -1,3 +1,4 @@ +UNSUPPORTED: freebsd  RUN: %cpp_compiler %S/CallerCalleeTest.cpp -o %t-CallerCalleeTest  CHECK: BINGO -RUN: not %t-CallerCalleeTest          -use_value_profile=1 -cross_over=0 -seed=1 -runs=10000000 2>&1 | FileCheck %s +RUN: not %run %t-CallerCalleeTest          -use_value_profile=1 -cross_over=0 -seed=1 -runs=10000000 2>&1 | FileCheck %s diff --git a/test/fuzzer/cleanse.test b/test/fuzzer/cleanse.test index 8e45dc77d9ea4..3447fcf0ff261 100644 --- a/test/fuzzer/cleanse.test +++ b/test/fuzzer/cleanse.test @@ -1,4 +1,4 @@  RUN: %cpp_compiler %S/CleanseTest.cpp -o %t-CleanseTest  RUN: echo -n 0123456789ABCDEFGHIZ > %t-in -RUN: %t-CleanseTest -cleanse_crash=1 %t-in -exact_artifact_path=%t-out +RUN: %run %t-CleanseTest -cleanse_crash=1 %t-in -exact_artifact_path=%t-out  RUN: echo -n ' 1   5    A        Z' | diff - %t-out diff --git a/test/fuzzer/counters.test b/test/fuzzer/counters.test new file mode 100644 index 0000000000000..f75d3a03783f8 --- /dev/null +++ b/test/fuzzer/counters.test @@ -0,0 +1,9 @@ +XFAIL: ios +UNSUPPORTED: aarch64 +RUN: %cpp_compiler %S/CounterTest.cpp -o %t-CounterTest +RUN: not %run %t-CounterTest  -max_len=6 -seed=1 -timeout=15 2>&1 | FileCheck %s --check-prefix=COUNTERS + +COUNTERS: INITED {{.*}} {{bits:|ft:}} +COUNTERS: NEW {{.*}} {{bits:|ft:}} {{[1-9]*}} +COUNTERS: NEW {{.*}} {{bits:|ft:}} {{[1-9]*}} +COUNTERS: BINGO diff --git a/test/fuzzer/coverage.test b/test/fuzzer/coverage.test index 9a2179d91add6..3b2341f21f695 100644 --- a/test/fuzzer/coverage.test +++ b/test/fuzzer/coverage.test @@ -1,21 +1,18 @@ +UNSUPPORTED: aarch64  RUN: %cpp_compiler -mllvm -use-unknown-locations=Disable  %S/NullDerefTest.cpp -o %t-NullDerefTest -RUN: %cpp_compiler -mllvm -use-unknown-locations=Disable %S/DSO1.cpp -fPIC -shared -o %t-DSO1.so -RUN: %cpp_compiler -mllvm -use-unknown-locations=Disable %S/DSO2.cpp -fPIC -shared -o %t-DSO2.so -RUN: %cpp_compiler -mllvm -use-unknown-locations=Disable %S/DSOTestMain.cpp %S/DSOTestExtra.cpp -L. %t-DSO1.so %t-DSO2.so -o %t-DSOTest +RUN: %cpp_compiler -mllvm -use-unknown-locations=Disable %S/DSO1.cpp -fPIC %ld_flags_rpath_so1 -shared -o %dynamiclib1 +RUN: %cpp_compiler -mllvm -use-unknown-locations=Disable %S/DSO2.cpp -fPIC %ld_flags_rpath_so2 -shared -o %dynamiclib2 +RUN: %cpp_compiler -mllvm -use-unknown-locations=Disable %S/DSOTestMain.cpp %S/DSOTestExtra.cpp %ld_flags_rpath_exe1 %ld_flags_rpath_exe2 -o %t-DSOTest  CHECK: COVERAGE: -CHECK-DAG: COVERED: {{.*}}in LLVMFuzzerTestOneInput {{.*}}NullDerefTest.cpp:13 -CHECK-DAG: COVERED: {{.*}}in LLVMFuzzerTestOneInput {{.*}}NullDerefTest.cpp:14 -CHECK-DAG: COVERED: {{.*}}in LLVMFuzzerTestOneInput {{.*}}NullDerefTest.cpp:16 -RUN: not %t-NullDerefTest -print_coverage=1 2>&1 | FileCheck %s +CHECK: COVERED_FUNC: {{.*}}LLVMFuzzerTestOneInput {{.*}}NullDerefTest.cpp:13 +RUN: not %run %t-NullDerefTest -print_coverage=1 2>&1 | FileCheck %s -RUN: %t-DSOTest -print_coverage=1 -runs=0 2>&1 | FileCheck %s --check-prefix=DSO +RUN: %run %t-DSOTest -print_coverage=1 -runs=0 2>&1 | FileCheck %s --check-prefix=DSO  DSO: COVERAGE: -DSO-DAG: COVERED:{{.*}}DSO1{{.*}}DSO1.cpp -DSO-DAG: COVERED:{{.*}}DSO2{{.*}}DSO2.cpp -DSO-DAG: COVERED:{{.*}}LLVMFuzzerTestOneInput{{.*}}DSOTestMain -DSO-DAG: UNCOVERED_LINE:{{.*}}DSO1{{.*}}DSO1.cpp -DSO-DAG: UNCOVERED_LINE:{{.*}}DSO2{{.*}}DSO2.cpp -DSO-DAG: UNCOVERED_FUNC: in Uncovered1 -DSO-DAG: UNCOVERED_FUNC: in Uncovered2 -DSO-DAG: UNCOVERED_LINE: in LLVMFuzzerTestOneInput +DSO-DAG: COVERED_FUNC:{{.*}}1{{.*}} +DSO-DAG: COVERED_FUNC:{{.*}}2{{.*}} +DSO-DAG: COVERED_FUNC:{{.*}}LLVMFuzzerTestOneInput{{.*}}DSOTestMain +DSO-DAG: UNCOVERED_PC:{{.*}}1 +DSO-DAG: UNCOVERED_PC:{{.*}}2 +DSO-DAG: UNCOVERED_PC:{{.*}}DSOTestMain diff --git a/test/fuzzer/cxxstring.test b/test/fuzzer/cxxstring.test index 7bb341ba22b48..65edeec1964a8 100644 --- a/test/fuzzer/cxxstring.test +++ b/test/fuzzer/cxxstring.test @@ -1,6 +1,6 @@ -UNSUPPORTED: windows +UNSUPPORTED: windows,freebsd  RUN: %cpp_compiler %S/CxxStringEqTest.cpp -o %t-CxxStringEqTest -RUN: not %t-CxxStringEqTest -seed=1 -runs=1000000 2>&1 | FileCheck %s +RUN: not %run %t-CxxStringEqTest -seed=1 -runs=1000000 2>&1 | FileCheck %s  CHECK: BINGO diff --git a/test/fuzzer/dataflow.test b/test/fuzzer/dataflow.test new file mode 100644 index 0000000000000..64f083735cb9e --- /dev/null +++ b/test/fuzzer/dataflow.test @@ -0,0 +1,84 @@ +# Tests the data flow tracer. +REQUIRES: linux +UNSUPPORTED: aarch64 + +# Build the tracer and the test. +RUN: %no_fuzzer_cpp_compiler -c -fno-sanitize=all -fsanitize=dataflow  %S/../../lib/fuzzer/dataflow/DataFlow.cpp -o  %t-DataFlow.o +RUN: %no_fuzzer_cpp_compiler    -fno-sanitize=all -fsanitize=dataflow -fsanitize-coverage=trace-pc-guard,pc-table,func,trace-cmp   %S/ThreeFunctionsTest.cpp     %t-DataFlow.o -o %t-ThreeFunctionsTestDF +RUN: %no_fuzzer_cpp_compiler    -fno-sanitize=all -fsanitize=dataflow -fsanitize-coverage=trace-pc-guard,pc-table,func,trace-cmp   %S/ExplodeDFSanLabelsTest.cpp %t-DataFlow.o -o %t-ExplodeDFSanLabelsTestDF +RUN: %cpp_compiler %S/ThreeFunctionsTest.cpp -o %t-ThreeFunctionsTest + +# Dump the function list. +RUN:  %t-ThreeFunctionsTestDF 2>&1 | FileCheck %s --check-prefix=FUNC_LIST +FUNC_LIST-DAG: LLVMFuzzerTestOneInput +FUNC_LIST-DAG: Func1 +FUNC_LIST-DAG: Func2 + +# Prepare the inputs. +RUN: rm -rf %t/IN +RUN: mkdir -p %t/IN +RUN: echo -n ABC    > %t/IN/ABC +RUN: echo -n FUABC  > %t/IN/FUABC +RUN: echo -n FUZZR  > %t/IN/FUZZR +RUN: echo -n FUZZM  > %t/IN/FUZZM +RUN: echo -n FUZZMU > %t/IN/FUZZMU +RUN: echo -n 1234567890123456 > %t/IN/1234567890123456 + +# ABC: No data is used, the only used label is 4 (corresponds to the size) +RUN:%t-ThreeFunctionsTestDF 0 3 %t/IN/ABC    | FileCheck %s --check-prefix=IN_ABC +IN_ABC: F{{[012]}} 0001 +IN_ABC-NOT: F + +# FUABC: First 3 bytes are checked, Func1/Func2 are not called. +RUN:%t-ThreeFunctionsTestDF 0 5 %t/IN/FUABC  | FileCheck %s --check-prefix=IN_FUABC +IN_FUABC: F{{[012]}} 111001 +IN_FUABC-NOT: F + +# FUZZR: 5 bytes are used (4 in one function, 5-th in the other), Func2 is not called. +RUN:%t-ThreeFunctionsTestDF 0 5 %t/IN/FUZZR  | FileCheck %s --check-prefix=IN_FUZZR +IN_FUZZR-DAG: F{{[012]}} 111101 +IN_FUZZR-DAG: F{{[012]}} 000010 +IN_FUZZR-NOT: F + +# FUZZM: 5 bytes are used, both Func1 and Func2 are called, Func2 depends only on size (label 6). +RUN:%t-ThreeFunctionsTestDF 0 5 %t/IN/FUZZM  | FileCheck %s --check-prefix=IN_FUZZM +IN_FUZZM-DAG: F{{[012]}} 000010 +IN_FUZZM-DAG: F{{[012]}} 111101 +IN_FUZZM-DAG: F{{[012]}} 000001 + +# FUZZMU: 6 bytes are used, both Func1 and Func2 are called, Func2 depends on byte 6 and size (label 7) +RUN:%t-ThreeFunctionsTestDF 0 6 %t/IN/FUZZMU  | FileCheck %s --check-prefix=IN_FUZZMU + +# Test merge_data_flow +RUN:rm -f %t-merge-* +RUN:%t-ThreeFunctionsTestDF 0 2 %t/IN/FUZZMU > %t-merge-1 +RUN:%t-ThreeFunctionsTestDF 2 4 %t/IN/FUZZMU > %t-merge-2 +RUN:%t-ThreeFunctionsTestDF 4 6 %t/IN/FUZZMU > %t-merge-3 +RUN:%libfuzzer_src/scripts/merge_data_flow.py  %t-merge-* | FileCheck %s --check-prefix=IN_FUZZMU + +# Test collect_data_flow +RUN: %libfuzzer_src/scripts/collect_data_flow.py %t-ThreeFunctionsTestDF %t/IN/FUZZMU | FileCheck %s --check-prefix=IN_FUZZMU + +IN_FUZZMU-DAG: F{{[012]}} 0000100 +IN_FUZZMU-DAG: F{{[012]}} 1111001 +IN_FUZZMU-DAG: F{{[012]}} 0000011 + +# A very simple test will cause DFSan to die with "out of labels" +RUN: not %t-ExplodeDFSanLabelsTestDF 0 16 %t/IN/1234567890123456 2>&1 | FileCheck %s --check-prefix=OUT_OF_LABELS +OUT_OF_LABELS: ==FATAL: DataFlowSanitizer: out of labels +# However we can run the same test piece by piece. +RUN: %t-ExplodeDFSanLabelsTestDF 0 2  %t/IN/1234567890123456 +RUN: %t-ExplodeDFSanLabelsTestDF 2 4  %t/IN/1234567890123456 +RUN: %t-ExplodeDFSanLabelsTestDF 4 6  %t/IN/1234567890123456 +# Or we can use collect_data_flow +RUN: %libfuzzer_src/scripts/collect_data_flow.py %t-ExplodeDFSanLabelsTestDF %t/IN/1234567890123456 + +# Test that we can run collect_data_flow on the entire corpus dir +RUN: rm -rf %t/OUT +RUN: %libfuzzer_src/scripts/collect_data_flow.py %t-ThreeFunctionsTestDF %t/IN %t/OUT +RUN: %t-ThreeFunctionsTest -data_flow_trace=%t/OUT -runs=0 -focus_function=Func2 2>&1 | FileCheck %s --check-prefix=USE_DATA_FLOW_TRACE +USE_DATA_FLOW_TRACE: INFO: Focus function is set to 'Func2' +USE_DATA_FLOW_TRACE: INFO: DataFlowTrace: reading from {{.*}}/OUT +USE_DATA_FLOW_TRACE-DAG: a8eefe2fd5d6b32028f355fafa3e739a6bf5edc => |000001| +USE_DATA_FLOW_TRACE-DGA: d28cb407e8e1a702c72d25473f0553d3ec172262 => |0000011| +USE_DATA_FLOW_TRACE: INFO: DataFlowTrace: 6 trace files, 3 functions, 2 traces with focus function diff --git a/test/fuzzer/deep-recursion.test b/test/fuzzer/deep-recursion.test index 22475f91263a5..f65104004bf93 100644 --- a/test/fuzzer/deep-recursion.test +++ b/test/fuzzer/deep-recursion.test @@ -1,5 +1,5 @@  # Test that we can find a stack overflow  REQUIRES: linux  RUN: %cpp_compiler %S/DeepRecursionTest.cpp -o %t -RUN: not %t -seed=1 -runs=100000000 2>&1 | FileCheck %s +RUN: not %run %t -seed=1 -runs=100000000 2>&1 | FileCheck %s  CHECK: ERROR: libFuzzer: deadly signal diff --git a/test/fuzzer/disable-leaks.test b/test/fuzzer/disable-leaks.test index bc120d98b38a9..1c65884e32130 100644 --- a/test/fuzzer/disable-leaks.test +++ b/test/fuzzer/disable-leaks.test @@ -1,5 +1,6 @@  REQUIRES: lsan +UNSUPPORTED: aarch64  RUN: %cpp_compiler %S/AccumulateAllocationsTest.cpp -o %t-AccumulateAllocationsTest -RUN: %t-AccumulateAllocationsTest -detect_leaks=1 -runs=100000 2>&1 | FileCheck %s --check-prefix=ACCUMULATE_ALLOCS +RUN: %run %t-AccumulateAllocationsTest -detect_leaks=1 -runs=100000 2>&1 | FileCheck %s --check-prefix=ACCUMULATE_ALLOCS  ACCUMULATE_ALLOCS: INFO: libFuzzer disabled leak detection after every mutation diff --git a/test/fuzzer/dso.test b/test/fuzzer/dso.test new file mode 100644 index 0000000000000..fc1fe23818f04 --- /dev/null +++ b/test/fuzzer/dso.test @@ -0,0 +1,7 @@ +RUN: %cpp_compiler %S/DSO1.cpp -fPIC %ld_flags_rpath_so1 -shared -o %dynamiclib1 +RUN: %cpp_compiler %S/DSO2.cpp -fPIC %ld_flags_rpath_so2 -shared -o %dynamiclib2 +RUN: %cpp_compiler %S/DSOTestMain.cpp %S/DSOTestExtra.cpp %ld_flags_rpath_exe1 %ld_flags_rpath_exe2 -o %t-DSOTest + +RUN: not %run %t-DSOTest 2>&1 | FileCheck %s --check-prefix=DSO +DSO: INFO: Loaded 3 modules +DSO: BINGO diff --git a/test/fuzzer/dump_coverage.test b/test/fuzzer/dump_coverage.test index b240089ce2395..41e193824de6a 100644 --- a/test/fuzzer/dump_coverage.test +++ b/test/fuzzer/dump_coverage.test @@ -1,20 +1,21 @@ -RUN: %cpp_compiler -fsanitize-coverage=0 -fsanitize-coverage=trace-pc-guard %S/DSO1.cpp -fPIC -shared -o %t-DSO1.so -RUN: %cpp_compiler -fsanitize-coverage=0 -fsanitize-coverage=trace-pc-guard %S/DSO2.cpp -fPIC -shared -o %t-DSO2.so -RUN: %cpp_compiler -fsanitize-coverage=0 -fsanitize-coverage=trace-pc-guard %S/DSOTestMain.cpp %S/DSOTestExtra.cpp -L. %t-DSO1.so %t-DSO2.so -o %t-DSOTest +UNSUPPORTED: freebsd +RUN: %cpp_compiler -fsanitize-coverage=0 -fsanitize-coverage=trace-pc-guard %S/DSO1.cpp -fPIC -shared -o %dynamiclib1 %ld_flags_rpath_so1 +RUN: %cpp_compiler -fsanitize-coverage=0 -fsanitize-coverage=trace-pc-guard %S/DSO2.cpp -fPIC -shared -o %dynamiclib2 %ld_flags_rpath_so2 +RUN: %cpp_compiler -fsanitize-coverage=0 -fsanitize-coverage=trace-pc-guard %S/DSOTestMain.cpp %S/DSOTestExtra.cpp %ld_flags_rpath_exe1 %ld_flags_rpath_exe2 -o %t-DSOTest  RUN: %cpp_compiler -fsanitize-coverage=0 -fsanitize-coverage=trace-pc-guard %S/NullDerefTest.cpp -o %t-NullDerefTest  RUN: rm -rf %t_workdir && mkdir -p %t_workdir -RUN: env ASAN_OPTIONS=coverage_dir='"%t_workdir"' not %t-NullDerefTest -dump_coverage=1 2>&1 | FileCheck %s +RUN: env ASAN_OPTIONS=coverage_dir='"%t_workdir"' not %run %t-NullDerefTest -dump_coverage=1 2>&1 | FileCheck %s  RUN: sancov -covered-functions %t-NullDerefTest* %t_workdir/*.sancov | FileCheck %s --check-prefix=SANCOV -RUN: env ASAN_OPTIONS=coverage_dir='"%t_workdir"' %t-DSOTest -dump_coverage=1 -runs=0 2>&1 | FileCheck %s --check-prefix=DSO -RUN: env ASAN_OPTIONS=coverage_dir='"%t_workdir"' not %t-NullDerefTest -dump_coverage=0 2>&1 | FileCheck %s --check-prefix=NOCOV +RUN: env ASAN_OPTIONS=coverage_dir='"%t_workdir"' %run %t-DSOTest -dump_coverage=1 -runs=0 2>&1 | FileCheck -allow-deprecated-dag-overlap %s --check-prefix=DSO +RUN: env ASAN_OPTIONS=coverage_dir='"%t_workdir"' not %run %t-NullDerefTest -dump_coverage=0 2>&1 | FileCheck %s --check-prefix=NOCOV  CHECK: SanitizerCoverage: {{.*}}NullDerefTest.{{.*}}.sancov: {{.*}} PCs written  SANCOV: LLVMFuzzerTestOneInput  DSO: SanitizerCoverage: {{.*}}DSOTest.{{.*}}.sancov: {{.*}} PCs written -DSO-DAG: SanitizerCoverage: {{.*}}DSO1.{{.*}}.sancov: {{.*}} PCs written -DSO-DAG: SanitizerCoverage: {{.*}}DSO2.{{.*}}.sancov: {{.*}} PCs written +DSO-DAG: SanitizerCoverage: {{.*}}.{{.*}}.sancov: {{.*}} PCs written +DSO-DAG: SanitizerCoverage: {{.*}}2.{{.*}}.sancov: {{.*}} PCs written  NOCOV-NOT: SanitizerCoverage: {{.*}} PCs written diff --git a/test/fuzzer/equivalence-signals.test b/test/fuzzer/equivalence-signals.test index 7951636e85f86..1da66f1474f17 100644 --- a/test/fuzzer/equivalence-signals.test +++ b/test/fuzzer/equivalence-signals.test @@ -1,9 +1,14 @@ +REQUIRES: this-test-is-deprecated  # Run EquivalenceATest against itself with a small timeout  # to stress the signal handling and ensure that shmem doesn't mind  # the signals. +UNSUPPORTED: freebsd + +# The test is not supported on Darwin +UNSUPPORTED: darwin  RUN: %cpp_compiler %S/EquivalenceATest.cpp -o %t-EquivalenceATest -RUN: %t-EquivalenceATest -timeout=1 -run_equivalence_server=EQUIV_SIG_TEST & export APID=$! +RUN: %run %t-EquivalenceATest -timeout=1 -run_equivalence_server=EQ_SIG_TEST & export APID=$!  RUN: sleep 3 -RUN: %t-EquivalenceATest -timeout=1 -use_equivalence_server=EQUIV_SIG_TEST -runs=500000 2>&1 +RUN: %run %t-EquivalenceATest -timeout=1 -use_equivalence_server=EQ_SIG_TEST -runs=500000 2>&1  RUN: kill -9 $APID diff --git a/test/fuzzer/equivalence.test b/test/fuzzer/equivalence.test index 12964f478a455..2438811f28098 100644 --- a/test/fuzzer/equivalence.test +++ b/test/fuzzer/equivalence.test @@ -1,9 +1,11 @@ +REQUIRES: this-test-is-deprecated +UNSUPPORTED: freebsd  RUN: %cpp_compiler %S/EquivalenceATest.cpp -o %t-EquivalenceATest  RUN: %cpp_compiler %S/EquivalenceBTest.cpp -o %t-EquivalenceBTest -RUN: %t-EquivalenceATest -run_equivalence_server=EQUIV_TEST & export APID=$! +RUN: %run %t-EquivalenceATest -run_equivalence_server=EQUIV_TEST & export APID=$!  RUN: sleep 3 -RUN: not %t-EquivalenceBTest -use_equivalence_server=EQUIV_TEST -max_len=4096 2>&1 | FileCheck %s +RUN: not %run %t-EquivalenceBTest -use_equivalence_server=EQUIV_TEST -max_len=4096 2>&1 | FileCheck %s  CHECK: ERROR: libFuzzer: equivalence-mismatch. Sizes: {{.*}}; offset 2  CHECK: SUMMARY: libFuzzer: equivalence-mismatch  RUN: kill -9 $APID diff --git a/test/fuzzer/exit-report.test b/test/fuzzer/exit-report.test index f754c1376c437..65d91c5cd88a8 100644 --- a/test/fuzzer/exit-report.test +++ b/test/fuzzer/exit-report.test @@ -1,5 +1,5 @@  RUN: %cpp_compiler %S/SimpleTest.cpp -o %t-SimpleTest -RUN: not %t-SimpleTest 2>&1 | FileCheck %s +RUN: not %run %t-SimpleTest 2>&1 | FileCheck %s  CHECK: ERROR: libFuzzer: fuzz target exited  CHECK: SUMMARY: libFuzzer: fuzz target exited diff --git a/test/fuzzer/exit_on_src_pos.test b/test/fuzzer/exit_on_src_pos.test index 6a42c7ae95392..ad0fa0a7ce4e3 100644 --- a/test/fuzzer/exit_on_src_pos.test +++ b/test/fuzzer/exit_on_src_pos.test @@ -1,8 +1,9 @@  # Temporary use -mllvm -use-unknown-locations=Disable so that  # all instructions have debug info (file line numbers) attached. -RUN: %cpp_compiler %S/SimpleTest.cpp -o %t-SimpleTest -mllvm -use-unknown-locations=Disable -RUN: %cpp_compiler %S/ShrinkControlFlowTest.cpp -o %t-ShrinkControlFlowTest +# TODO: Find out why test fails on Darwin with -O2. +RUN: %cpp_compiler -O0 %S/SimpleTest.cpp -o %t-SimpleTest -mllvm -use-unknown-locations=Disable +RUN: %cpp_compiler -O0 %S/ShrinkControlFlowTest.cpp -o %t-ShrinkControlFlowTest -RUN: %t-SimpleTest  -exit_on_src_pos=SimpleTest.cpp:18                 2>&1 | FileCheck %s --check-prefix=EXIT_ON_SRC_POS -RUN: %t-ShrinkControlFlowTest  -exit_on_src_pos=Foo 2>&1 | FileCheck %s --check-prefix=EXIT_ON_SRC_POS +RUN: %run %t-SimpleTest  -exit_on_src_pos=SimpleTest.cpp:18                 2>&1 | FileCheck %s --check-prefix=EXIT_ON_SRC_POS +RUN: %run %t-ShrinkControlFlowTest  -exit_on_src_pos=Foo 2>&1 | FileCheck %s --check-prefix=EXIT_ON_SRC_POS  EXIT_ON_SRC_POS: INFO: found line matching '{{.*}}', exiting. diff --git a/test/fuzzer/extra-counters.test b/test/fuzzer/extra-counters.test index 230f74a1b0bb5..a93f775dcfc5f 100644 --- a/test/fuzzer/extra-counters.test +++ b/test/fuzzer/extra-counters.test @@ -1,7 +1,7 @@  REQUIRES: linux  RUN: %cpp_compiler %S/TableLookupTest.cpp -o %t-TableLookupTest -RUN: not %t-TableLookupTest -print_final_stats=1 2>&1 | FileCheck %s -CHECK: BINGO +RUN: not %run %t-TableLookupTest -print_final_stats=1 2>&1 | FileCheck %s +CHECK: INFO: {{[0-9]+}} Extra Counters  // Expecting >= 4096 new_units_added  CHECK: stat::new_units_added:{{.*[4][0-9][0-9][0-9]}} diff --git a/test/fuzzer/fprofile-instr-generate.test b/test/fuzzer/fprofile-instr-generate.test deleted file mode 100644 index 2a3ec96f10f77..0000000000000 --- a/test/fuzzer/fprofile-instr-generate.test +++ /dev/null @@ -1,7 +0,0 @@ -# Test libFuzzer + -fprofile-instr-generate -REQUIRES: linux -RUN: %cpp_compiler %S/SimpleTest.cpp -fsanitize-coverage=0 -fprofile-instr-generate -o %t-SimpleTest-fprofile-instr-generate -CHECK-NOT: INFO: Loaded 1 modules -CHECK: INFO: {{.*}} Clang Coverage Counters -CHECK: BINGO -RUN: not %t-SimpleTest-fprofile-instr-generate -runs=1000000 -seed=1 -use_clang_coverage=1 2>&1 | FileCheck %s diff --git a/test/fuzzer/full-coverage-set.test b/test/fuzzer/full-coverage-set.test new file mode 100644 index 0000000000000..629873d4eb39e --- /dev/null +++ b/test/fuzzer/full-coverage-set.test @@ -0,0 +1,3 @@ +CHECK: BINGO +RUN: %cpp_compiler %S/FullCoverageSetTest.cpp -o %t-FullCoverageSetTest +#not %run %t-FullCoverageSetTest -timeout=15 -seed=1 -mutate_depth=2 -use_full_coverage_set=1 2>&1 | FileCheck %s diff --git a/test/fuzzer/fuzzer-customcrossover.test b/test/fuzzer/fuzzer-customcrossover.test index 5a78307c7a3bf..0835081f289a1 100644 --- a/test/fuzzer/fuzzer-customcrossover.test +++ b/test/fuzzer/fuzzer-customcrossover.test @@ -1,8 +1,8 @@  RUN: %cpp_compiler %S/CustomCrossOverTest.cpp -o %t-CustomCrossOverTest -RUN: not %t-CustomCrossOverTest -seed=1 -runs=1000000                2>&1 | FileCheck %s --check-prefix=CHECK_CO +RUN: not %run %t-CustomCrossOverTest -seed=1 -runs=1000000                2>&1 | FileCheck %s --check-prefix=CHECK_CO  Disable cross_over, verify that we can't find the target w/o it. -RUN:     %t-CustomCrossOverTest -seed=1 -runs=1000000 -cross_over=0 2>&1 | FileCheck %s --check-prefix=CHECK_NO_CO +RUN:     %run %t-CustomCrossOverTest -seed=1 -runs=1000000 -cross_over=0 2>&1 | FileCheck %s --check-prefix=CHECK_NO_CO  CHECK_CO: In LLVMFuzzerCustomCrossover  CHECK_CO: BINGO diff --git a/test/fuzzer/fuzzer-customcrossoverandmutate.test b/test/fuzzer/fuzzer-customcrossoverandmutate.test index 4a7dfba2ab8be..e538d866ff2d3 100644 --- a/test/fuzzer/fuzzer-customcrossoverandmutate.test +++ b/test/fuzzer/fuzzer-customcrossoverandmutate.test @@ -1,2 +1,2 @@  RUN: %cpp_compiler %S/CustomCrossOverAndMutateTest.cpp -o %t-CustomCrossOverAndMutateTest -RUN: %t-CustomCrossOverAndMutateTest -seed=1 -runs=100000 +RUN: %run %t-CustomCrossOverAndMutateTest -seed=1 -runs=100000 diff --git a/test/fuzzer/fuzzer-custommutator.test b/test/fuzzer/fuzzer-custommutator.test index 7a693cd473249..51aef2373cca0 100644 --- a/test/fuzzer/fuzzer-custommutator.test +++ b/test/fuzzer/fuzzer-custommutator.test @@ -1,5 +1,5 @@  RUN: %cpp_compiler %S/CustomMutatorTest.cpp -o %t-CustomMutatorTest -RUN: not %t-CustomMutatorTest 2>&1 | FileCheck %s --check-prefix=LLVMFuzzerCustomMutator +RUN: not %run %t-CustomMutatorTest 2>&1 | FileCheck %s --check-prefix=LLVMFuzzerCustomMutator  LLVMFuzzerCustomMutator: In LLVMFuzzerCustomMutator  LLVMFuzzerCustomMutator: BINGO diff --git a/test/fuzzer/fuzzer-dict.test b/test/fuzzer/fuzzer-dict.test index 48c91dc1d6fe8..d396f6950a13b 100644 --- a/test/fuzzer/fuzzer-dict.test +++ b/test/fuzzer/fuzzer-dict.test @@ -3,6 +3,6 @@ RUN: %cpp_compiler %S/SimpleDictionaryTest.cpp -o %t-SimpleDictionaryTest  CHECK: BINGO  Done1000000: Done 1000000 runs in -RUN: not %t-SimpleDictionaryTest -dict=%S/dict1.txt -seed=1 -runs=1000003  2>&1 | FileCheck %s -RUN:     %t-SimpleDictionaryTest                    -seed=1 -runs=1000000  2>&1 | FileCheck %s --check-prefix=Done1000000 +RUN: not %run %t-SimpleDictionaryTest -dict=%S/dict1.txt -seed=1 -runs=1000003  2>&1 | FileCheck %s +RUN:     %run %t-SimpleDictionaryTest                    -seed=1 -runs=1000000  2>&1 | FileCheck %s --check-prefix=Done1000000 diff --git a/test/fuzzer/fuzzer-dirs.test b/test/fuzzer/fuzzer-dirs.test index 9b6e4d1eedda6..3c742b52da4c5 100644 --- a/test/fuzzer/fuzzer-dirs.test +++ b/test/fuzzer/fuzzer-dirs.test @@ -5,17 +5,17 @@ RUN: mkdir -p %t/SUB1/SUB2/SUB3  RUN: echo a > %t/SUB1/a  RUN: echo b > %t/SUB1/SUB2/b  RUN: echo c > %t/SUB1/SUB2/SUB3/c -RUN: %t-SimpleTest %t/SUB1 -runs=0 2>&1 | FileCheck %s --check-prefix=SUBDIRS +RUN: %run %t-SimpleTest %t/SUB1 -runs=0 2>&1 | FileCheck %s --check-prefix=SUBDIRS  SUBDIRS: INFO: seed corpus: files: 3 min: 2b max: 2b total: 6b  RUN: echo -n zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz > %t/SUB1/f64  RUN: cat %t/SUB1/f64 %t/SUB1/f64 %t/SUB1/f64 %t/SUB1/f64 > %t/SUB1/f256  RUN: cat %t/SUB1/f256 %t/SUB1/f256 %t/SUB1/f256 %t/SUB1/f256 > %t/SUB1/f1024  RUN: cat %t/SUB1/f1024 %t/SUB1/f1024 %t/SUB1/f1024 %t/SUB1/f1024 > %t/SUB1/f4096  RUN: cat %t/SUB1/f4096 %t/SUB1/f4096 > %t/SUB1/f8192 -RUN: %t-SimpleTest %t/SUB1 -runs=0 2>&1 | FileCheck %s --check-prefix=LONG +RUN: %run %t-SimpleTest %t/SUB1 -runs=0 2>&1 | FileCheck %s --check-prefix=LONG  LONG: INFO: -max_len is not provided; libFuzzer will not generate inputs larger than 8192 bytes  RUN: rm -rf %t/SUB1 -RUN: not %t-SimpleTest NONEXISTENT_DIR 2>&1 | FileCheck %s --check-prefix=NONEXISTENT_DIR -NONEXISTENT_DIR: No such directory: NONEXISTENT_DIR; exiting +RUN: not %run %t-SimpleTest NONEXISTENT_DIR 2>&1 | FileCheck %s --check-prefix=NONEXISTENT_DIR +NONEXISTENT_DIR: No such file or directory: NONEXISTENT_DIR; exiting diff --git a/test/fuzzer/fuzzer-fdmask.test b/test/fuzzer/fuzzer-fdmask.test index 3f04993b5d7ed..09f29782b8a8a 100644 --- a/test/fuzzer/fuzzer-fdmask.test +++ b/test/fuzzer/fuzzer-fdmask.test @@ -1,28 +1,28 @@  RUN: %cpp_compiler %S/SpamyTest.cpp -o %t-SpamyTest -RUN: %t-SpamyTest -runs=1                  2>&1 | FileCheck %s --check-prefix=FD_MASK_0 -RUN: %t-SpamyTest -runs=1 -close_fd_mask=0 2>&1 | FileCheck %s --check-prefix=FD_MASK_0 -RUN: %t-SpamyTest -runs=1 -close_fd_mask=1 2>&1 | FileCheck %s --check-prefix=FD_MASK_1 -RUN: %t-SpamyTest -runs=1 -close_fd_mask=2 2>&1 | FileCheck %s --check-prefix=FD_MASK_2 -RUN: %t-SpamyTest -runs=1 -close_fd_mask=3 2>&1 | FileCheck %s --check-prefix=FD_MASK_3 +RUN: %run %t-SpamyTest -runs=1                  2>&1 | FileCheck %s --check-prefix=FD_MASK_0 +RUN: %run %t-SpamyTest -runs=1 -close_fd_mask=0 2>&1 | FileCheck %s --check-prefix=FD_MASK_0 +RUN: %run %t-SpamyTest -runs=1 -close_fd_mask=1 2>&1 | FileCheck %s --check-prefix=FD_MASK_1 +RUN: %run %t-SpamyTest -runs=1 -close_fd_mask=2 2>&1 | FileCheck %s --check-prefix=FD_MASK_2 +RUN: %run %t-SpamyTest -runs=1 -close_fd_mask=3 2>&1 | FileCheck %s --check-prefix=FD_MASK_3 -FD_MASK_0: PRINTF_STDOUT -FD_MASK_0: PRINTF_STDERR -FD_MASK_0: STREAM_COUT -FD_MASK_0: STREAM_CERR -FD_MASK_0: INITED +FD_MASK_0-DAG: PRINTF_STDOUT +FD_MASK_0-DAG: PRINTF_STDERR +FD_MASK_0-DAG: STREAM_COUT +FD_MASK_0-DAG: STREAM_CERR +FD_MASK_0-DAG: INITED  FD_MASK_1-NOT: PRINTF_STDOUT -FD_MASK_1: PRINTF_STDERR +FD_MASK_1-DAG: PRINTF_STDERR  FD_MASK_1-NOT: STREAM_COUT -FD_MASK_1: STREAM_CERR -FD_MASK_1: INITED +FD_MASK_1-DAG: STREAM_CERR +FD_MASK_1-DAG: INITED -FD_MASK_2: PRINTF_STDOUT +FD_MASK_2-DAG: PRINTF_STDOUT +FD_MASK_2-DAG: STREAM_COUT +FD_MASK_2-DAG: INITED  FD_MASK_2-NOT: PRINTF_STDERR -FD_MASK_2: STREAM_COUT -FD_MASK_2-NOTE: STREAM_CERR -FD_MASK_2: INITED +FD_MASK_2-NOT: STREAM_CERR  FD_MASK_3-NOT: PRINTF_STDOUT  FD_MASK_3-NOT: PRINTF_STDERR diff --git a/test/fuzzer/fuzzer-finalstats.test b/test/fuzzer/fuzzer-finalstats.test index 4f983bea825e9..d8c991e308478 100644 --- a/test/fuzzer/fuzzer-finalstats.test +++ b/test/fuzzer/fuzzer-finalstats.test @@ -1,12 +1,12 @@  RUN: %cpp_compiler %S/SimpleTest.cpp -o %t-SimpleTest -RUN: %t-SimpleTest -seed=1 -runs=77 -print_final_stats=1 2>&1 | FileCheck %s --check-prefix=FINAL_STATS +RUN: %run %t-SimpleTest -seed=1 -runs=77 -print_final_stats=1 2>&1 | FileCheck %s --check-prefix=FINAL_STATS  FINAL_STATS: stat::number_of_executed_units: 77  FINAL_STATS: stat::average_exec_per_sec:     0  FINAL_STATS: stat::new_units_added:  FINAL_STATS: stat::slowest_unit_time_sec:    0  FINAL_STATS: stat::peak_rss_mb: -RUN: %t-SimpleTest %S/dict1.txt -runs=33 -print_final_stats=1 2>&1 | FileCheck %s --check-prefix=FINAL_STATS1 +RUN: %run %t-SimpleTest %S/dict1.txt -runs=33 -print_final_stats=1 2>&1 | FileCheck %s --check-prefix=FINAL_STATS1  FINAL_STATS1: stat::number_of_executed_units: 33  FINAL_STATS1: stat::peak_rss_mb: diff --git a/test/fuzzer/fuzzer-flags.test b/test/fuzzer/fuzzer-flags.test index b812b01695d89..916c6eed889f0 100644 --- a/test/fuzzer/fuzzer-flags.test +++ b/test/fuzzer/fuzzer-flags.test @@ -1,19 +1,19 @@  RUN: %cpp_compiler %S/FlagsTest.cpp -o %t-FlagsTest -RUN: %t-FlagsTest -runs=10 -foo_bar=1 2>&1 | FileCheck %s --check-prefix=FOO_BAR +RUN: %run %t-FlagsTest -runs=10 -foo_bar=1 2>&1 | FileCheck %s --check-prefix=FOO_BAR  FOO_BAR: WARNING: unrecognized flag '-foo_bar=1'; use -help=1 to list all flags  FOO_BAR: BINGO -RUN: %t-FlagsTest -runs=10 --max_len=100 2>&1 | FileCheck %s --check-prefix=DASH_DASH +RUN: %run %t-FlagsTest -runs=10 --max_len=100 2>&1 | FileCheck %s --check-prefix=DASH_DASH  DASH_DASH: WARNING: did you mean '-max_len=100' (single dash)?  DASH_DASH: INFO: A corpus is not provided, starting from an empty corpus -RUN: %t-FlagsTest -help=1 2>&1 | FileCheck %s --check-prefix=NO_INTERNAL +RUN: %run %t-FlagsTest -help=1 2>&1 | FileCheck %s --check-prefix=NO_INTERNAL  NO_INTERNAL-NOT: internal flag -RUN: %t-FlagsTest --foo-bar -runs=10 -ignore_remaining_args=1 --baz -help=1 test 2>&1 | FileCheck %s --check-prefix=PASSTHRU +RUN: %run %t-FlagsTest --foo-bar -runs=10 -ignore_remaining_args=1 --baz -help=1 test 2>&1 | FileCheck %s --check-prefix=PASSTHRU  PASSTHRU: BINGO --foo-bar --baz -help=1 test  RUN: mkdir -p %t/T0 %t/T1  RUN: echo z > %t/T1/z -RUN: %t-FlagsTest -runs=10 --foo-bar -merge=1 %t/T0 %t/T1 -ignore_remaining_args=1 --baz -help=1 test 2>&1 | FileCheck %s --check-prefix=PASSTHRU-MERGE +RUN: %run %t-FlagsTest -runs=10 --foo-bar -merge=1 %t/T0 %t/T1 -ignore_remaining_args=1 --baz -help=1 test 2>&1 | FileCheck %s --check-prefix=PASSTHRU-MERGE  PASSTHRU-MERGE: BINGO --foo-bar --baz -help=1 test diff --git a/test/fuzzer/fuzzer-leak.test b/test/fuzzer/fuzzer-leak.test index 0652a88f9d5d1..2b61811d5d1b7 100644 --- a/test/fuzzer/fuzzer-leak.test +++ b/test/fuzzer/fuzzer-leak.test @@ -1,10 +1,11 @@  REQUIRES: lsan +  RUN: %cpp_compiler %S/LeakTest.cpp -o %t-LeakTest  RUN: %cpp_compiler %S/ThreadedLeakTest.cpp -o %t-ThreadedLeakTest  RUN: %cpp_compiler %S/LeakTimeoutTest.cpp -o %t-LeakTimeoutTest  RUN: rm -rf %t-corpus && mkdir -p %t-corpus -RUN: not %t-LeakTest -runs=100000 -detect_leaks=1 %t-corpus 2>&1 | FileCheck %s --check-prefix=LEAK_DURING +RUN: not %run %t-LeakTest -runs=100000 -detect_leaks=1 %t-corpus 2>&1 | FileCheck %s --check-prefix=LEAK_DURING  LEAK_DURING: ERROR: LeakSanitizer: detected memory leaks  LEAK_DURING: Direct leak of 4 byte(s) in 1 object(s) allocated from:  LEAK_DURING: INFO: to ignore leaks on libFuzzer side use -detect_leaks=0 @@ -13,29 +14,29 @@ LEAK_DURING-NOT: DONE  LEAK_DURING-NOT: Done  // Verify leaking input was not added to corpus -RUN: %t-LeakTest -runs=0 %t-corpus +RUN: %run %t-LeakTest -runs=0 %t-corpus -RUN: not %t-LeakTest -runs=0 -detect_leaks=1 %S 2>&1 | FileCheck %s --check-prefix=LEAK_IN_CORPUS +RUN: not %run %t-LeakTest -runs=0 -detect_leaks=1 %S 2>&1 | FileCheck %s --check-prefix=LEAK_IN_CORPUS  LEAK_IN_CORPUS: ERROR: LeakSanitizer: detected memory leaks  LEAK_IN_CORPUS: INFO: a leak has been found in the initial corpus. -RUN: not %t-LeakTest -runs=100000000 %S/hi.txt 2>&1 | FileCheck %s --check-prefix=MULTI_RUN_LEAK +RUN: not %run %t-LeakTest -runs=100000000 %S/hi.txt 2>&1 | FileCheck %s --check-prefix=MULTI_RUN_LEAK  MULTI_RUN_LEAK-NOT: pulse  MULTI_RUN_LEAK: LeakSanitizer: detected memory leaks -RUN: not %t-LeakTest -runs=100000 -detect_leaks=0 2>&1 | FileCheck %s --check-prefix=LEAK_AFTER -RUN: not %t-LeakTest -runs=100000                 2>&1 | FileCheck %s --check-prefix=LEAK_DURING -RUN: not %t-ThreadedLeakTest -runs=100000 -detect_leaks=0 2>&1 | FileCheck %s --check-prefix=LEAK_AFTER -RUN: not %t-ThreadedLeakTest -runs=100000                 2>&1 | FileCheck %s --check-prefix=LEAK_DURING +RUN: not %run %t-LeakTest -runs=100000 -detect_leaks=0 2>&1 | FileCheck %s --check-prefix=LEAK_AFTER +RUN: not %run %t-LeakTest -runs=100000                 2>&1 | FileCheck %s --check-prefix=LEAK_DURING +RUN: not %run %t-ThreadedLeakTest -runs=100000 -detect_leaks=0 2>&1 | FileCheck %s --check-prefix=LEAK_AFTER +RUN: not %run %t-ThreadedLeakTest -runs=100000                 2>&1 | FileCheck %s --check-prefix=LEAK_DURING  LEAK_AFTER: Done 100000 runs in  LEAK_AFTER: ERROR: LeakSanitizer: detected memory leaks -RUN: not %t-LeakTest -runs=100000 -max_len=1 2>&1 | FileCheck %s --check-prefix=MAX_LEN_1 +RUN: not %run %t-LeakTest -runs=100000 -max_len=1 2>&1 | FileCheck %s --check-prefix=MAX_LEN_1  MAX_LEN_1: Test unit written to ./leak-7cf184f4c67ad58283ecb19349720b0cae756829 -RUN: not %t-LeakTimeoutTest -timeout=1 2>&1 | FileCheck %s --check-prefix=LEAK_TIMEOUT +RUN: not %run %t-LeakTimeoutTest -timeout=1 2>&1 | FileCheck %s --check-prefix=LEAK_TIMEOUT  LEAK_TIMEOUT: ERROR: libFuzzer: timeout after  LEAK_TIMEOUT-NOT: LeakSanitizer -RUN: %t-LeakTest -error_exitcode=0 +RUN: %run %t-LeakTest -error_exitcode=0 diff --git a/test/fuzzer/fuzzer-mutationstats.test b/test/fuzzer/fuzzer-mutationstats.test new file mode 100644 index 0000000000000..95743a818d1f4 --- /dev/null +++ b/test/fuzzer/fuzzer-mutationstats.test @@ -0,0 +1,5 @@ +RUN: %cpp_compiler %S/SimpleTest.cpp -o %t-MutationStatsTest +RUN: not %run %t-MutationStatsTest -print_mutation_stats=1 2>&1 | FileCheck %s + +# Ensures there are some non-zero values in the usefulness percentages printed. +CHECK: stat::mutation_usefulness:   {{[0-9]+\.[0-9]+}} diff --git a/test/fuzzer/fuzzer-oom-with-profile.test b/test/fuzzer/fuzzer-oom-with-profile.test index 75cf48430a467..918197abd5a24 100644 --- a/test/fuzzer/fuzzer-oom-with-profile.test +++ b/test/fuzzer/fuzzer-oom-with-profile.test @@ -1,6 +1,6 @@  REQUIRES: linux  RUN: %cpp_compiler %S/OutOfMemoryTest.cpp -o %t-OutOfMemoryTest -RUN: not %t-OutOfMemoryTest -rss_limit_mb=300 2>&1 | FileCheck %s +RUN: not %run %t-OutOfMemoryTest -rss_limit_mb=300 2>&1 | FileCheck %s  CHECK: ERROR: libFuzzer: out-of-memory (used: {{.*}}; limit: 300Mb)  CHECK: Live Heap Allocations  CHECK: Test unit written to ./oom- diff --git a/test/fuzzer/fuzzer-oom.test b/test/fuzzer/fuzzer-oom.test index 308c4c5cd3946..e82fb47c5bed4 100644 --- a/test/fuzzer/fuzzer-oom.test +++ b/test/fuzzer/fuzzer-oom.test @@ -1,16 +1,17 @@ +UNSUPPORTED: aarch64  RUN: %cpp_compiler %S/OutOfMemoryTest.cpp -o %t-OutOfMemoryTest  RUN: %cpp_compiler %S/OutOfMemorySingleLargeMallocTest.cpp -o %t-OutOfMemorySingleLargeMallocTest  RUN: %cpp_compiler %S/AccumulateAllocationsTest.cpp -o %t-AccumulateAllocationsTest -RUN: not %t-OutOfMemoryTest -rss_limit_mb=300 2>&1 | FileCheck %s +RUN: not %run %t-OutOfMemoryTest -rss_limit_mb=300 2>&1 | FileCheck %s  CHECK: ERROR: libFuzzer: out-of-memory (used: {{.*}}; limit: 300Mb)  CHECK: Test unit written to ./oom-  SUMMARY: libFuzzer: out-of-memory -RUN: not %t-OutOfMemorySingleLargeMallocTest -rss_limit_mb=300    2>&1 | FileCheck %s --check-prefix=SINGLE_LARGE_MALLOC -RUN: not %t-OutOfMemorySingleLargeMallocTest -malloc_limit_mb=300 2>&1 | FileCheck %s --check-prefix=SINGLE_LARGE_MALLOC -RUN: not %t-OutOfMemorySingleLargeMallocTest -rss_limit_mb=1000 -malloc_limit_mb=300 2>&1 | FileCheck %s --check-prefix=SINGLE_LARGE_MALLOC +RUN: not %run %t-OutOfMemorySingleLargeMallocTest -rss_limit_mb=300    2>&1 | FileCheck %s --check-prefix=SINGLE_LARGE_MALLOC +RUN: not %run %t-OutOfMemorySingleLargeMallocTest -malloc_limit_mb=300 2>&1 | FileCheck %s --check-prefix=SINGLE_LARGE_MALLOC +RUN: not %run %t-OutOfMemorySingleLargeMallocTest -rss_limit_mb=1000 -malloc_limit_mb=300 2>&1 | FileCheck %s --check-prefix=SINGLE_LARGE_MALLOC  We used to check for "out-of-memory (malloc(53{{.*}}))", but that would fail  sometimes, so now we accept any OOM message. @@ -19,4 +20,4 @@ SINGLE_LARGE_MALLOC: libFuzzer: out-of-memory  SINGLE_LARGE_MALLOC: in LLVMFuzzerTestOneInput  # Check that -rss_limit_mb=0 means no limit. -RUN: %t-AccumulateAllocationsTest -runs=1000 -rss_limit_mb=0 +RUN: %run %t-AccumulateAllocationsTest -runs=1000 -rss_limit_mb=0 diff --git a/test/fuzzer/fuzzer-printcovpcs.test b/test/fuzzer/fuzzer-printcovpcs.test index e55ce14aa72fe..decf0a7e5fffe 100644 --- a/test/fuzzer/fuzzer-printcovpcs.test +++ b/test/fuzzer/fuzzer-printcovpcs.test @@ -1,5 +1,7 @@ +XFAIL: ios +UNSUPPORTED: aarch64  RUN: %cpp_compiler %S/SimpleTest.cpp -o %t-SimpleTest -RUN: not %t-SimpleTest -print_pcs=1 -seed=1 2>&1 | FileCheck %s --check-prefix=PCS +RUN: not %run %t-SimpleTest -print_pcs=1 -seed=1 2>&1 | FileCheck %s --check-prefix=PCS  PCS-NOT: NEW_PC  PCS:INITED  PCS:NEW_PC: {{0x[a-f0-9]+}} diff --git a/test/fuzzer/fuzzer-runs.test b/test/fuzzer/fuzzer-runs.test index 04987eee50291..b3f20c475aa9c 100644 --- a/test/fuzzer/fuzzer-runs.test +++ b/test/fuzzer/fuzzer-runs.test @@ -1,9 +1,9 @@  RUN: mkdir -p %t  RUN: %cpp_compiler %S/NthRunCrashTest.cpp -o %t-NthRunCrashTest  RUN: echo abcd > %t/NthRunCrashTest.in -RUN: %t-NthRunCrashTest %t/NthRunCrashTest.in -RUN: %t-NthRunCrashTest %t/NthRunCrashTest.in -runs=10 -RUN: not %t-NthRunCrashTest %t/NthRunCrashTest.in -runs=10000 2>&1 | FileCheck %s +RUN: %run %t-NthRunCrashTest %t/NthRunCrashTest.in +RUN: %run %t-NthRunCrashTest %t/NthRunCrashTest.in -runs=10 +RUN: not %run %t-NthRunCrashTest %t/NthRunCrashTest.in -runs=10000 2>&1 | FileCheck %s  RUN: rm %t/NthRunCrashTest.in  CHECK: BINGO diff --git a/test/fuzzer/fuzzer-seed.test b/test/fuzzer/fuzzer-seed.test index a69ea5432849a..b6343ffa3dd73 100644 --- a/test/fuzzer/fuzzer-seed.test +++ b/test/fuzzer/fuzzer-seed.test @@ -1,4 +1,4 @@  RUN: %cpp_compiler %S/NullDerefTest.cpp -o %t-SimpleCmpTest -RUN: %t-SimpleCmpTest -seed=-1 -runs=0 2>&1 | FileCheck %s --check-prefix=CHECK_SEED_MINUS_ONE +RUN: %run %t-SimpleCmpTest -seed=-1 -runs=0 2>&1 | FileCheck %s --check-prefix=CHECK_SEED_MINUS_ONE  CHECK_SEED_MINUS_ONE: Seed: 4294967295 diff --git a/test/fuzzer/fuzzer-segv.test b/test/fuzzer/fuzzer-segv.test index 4d3c7575f7a8b..0c4fafe080778 100644 --- a/test/fuzzer/fuzzer-segv.test +++ b/test/fuzzer/fuzzer-segv.test @@ -1,8 +1,8 @@  RUN: %cpp_compiler %S/NullDerefTest.cpp -o %t-NullDerefTest -RUN: env ASAN_OPTIONS=handle_segv=0 not %t-NullDerefTest 2>&1 | FileCheck %s --check-prefix=LIBFUZZER_OWN_SEGV_HANDLER +RUN: env ASAN_OPTIONS=handle_segv=0 not %run %t-NullDerefTest 2>&1 | FileCheck %s --check-prefix=LIBFUZZER_OWN_SEGV_HANDLER  LIBFUZZER_OWN_SEGV_HANDLER: == ERROR: libFuzzer: deadly signal  LIBFUZZER_OWN_SEGV_HANDLER: SUMMARY: libFuzzer: deadly signal  LIBFUZZER_OWN_SEGV_HANDLER: Test unit written to ./crash- -RUN: env ASAN_OPTIONS=handle_segv=1 not %t-NullDerefTest 2>&1 | FileCheck %s --check-prefix=LIBFUZZER_ASAN_SEGV_HANDLER +RUN: env ASAN_OPTIONS=handle_segv=1 not %run %t-NullDerefTest 2>&1 | FileCheck %s --check-prefix=LIBFUZZER_ASAN_SEGV_HANDLER  LIBFUZZER_ASAN_SEGV_HANDLER: ERROR: AddressSanitizer: {{SEGV|access-violation}} on unknown address diff --git a/test/fuzzer/fuzzer-singleinputs.test b/test/fuzzer/fuzzer-singleinputs.test index 468da5622af93..704f9caa57f94 100644 --- a/test/fuzzer/fuzzer-singleinputs.test +++ b/test/fuzzer/fuzzer-singleinputs.test @@ -1,15 +1,15 @@  RUN: %cpp_compiler %S/NullDerefTest.cpp -o %t-NullDerefTest  RUN: %cpp_compiler %S/SimpleTest.cpp -o %t-SimpleTest -RUN: not %t-NullDerefTest %S/hi.txt 2>&1 | FileCheck %s --check-prefix=SingleInput +RUN: not %run %t-NullDerefTest %S/hi.txt 2>&1 | FileCheck %s --check-prefix=SingleInput  SingleInput-NOT: Test unit written to ./crash-  RUN: rm -rf  %tmp/SINGLE_INPUTS  RUN: mkdir -p  %tmp/SINGLE_INPUTS  RUN: echo aaa > %tmp/SINGLE_INPUTS/aaa  RUN: echo bbb > %tmp/SINGLE_INPUTS/bbb -RUN: %t-SimpleTest            %tmp/SINGLE_INPUTS/aaa %tmp/SINGLE_INPUTS/bbb 2>&1 | FileCheck %s --check-prefix=SINGLE_INPUTS -RUN: %t-SimpleTest -max_len=2 %tmp/SINGLE_INPUTS/aaa %tmp/SINGLE_INPUTS/bbb 2>&1 | FileCheck %s --check-prefix=SINGLE_INPUTS +RUN: %run %t-SimpleTest            %tmp/SINGLE_INPUTS/aaa %tmp/SINGLE_INPUTS/bbb 2>&1 | FileCheck %s --check-prefix=SINGLE_INPUTS +RUN: %run %t-SimpleTest -max_len=2 %tmp/SINGLE_INPUTS/aaa %tmp/SINGLE_INPUTS/bbb 2>&1 | FileCheck %s --check-prefix=SINGLE_INPUTS  RUN: rm -rf  %tmp/SINGLE_INPUTS  SINGLE_INPUTS: SimpleTest{{.*}}: Running 2 inputs 1 time(s) each.  SINGLE_INPUTS: aaa in diff --git a/test/fuzzer/fuzzer-threaded.test b/test/fuzzer/fuzzer-threaded.test index 572ed5a355186..3321e19585c0b 100644 --- a/test/fuzzer/fuzzer-threaded.test +++ b/test/fuzzer/fuzzer-threaded.test @@ -1,8 +1,8 @@  CHECK: Done 1000 runs in  RUN: %cpp_compiler %S/ThreadedTest.cpp -o %t-ThreadedTest -RUN: %t-ThreadedTest -use_traces=1 -runs=1000  2>&1 | FileCheck %s -RUN: %t-ThreadedTest -use_traces=1 -runs=1000  2>&1 | FileCheck %s -RUN: %t-ThreadedTest -use_traces=1 -runs=1000  2>&1 | FileCheck %s -RUN: %t-ThreadedTest -use_traces=1 -runs=1000  2>&1 | FileCheck %s +RUN: %run %t-ThreadedTest -use_traces=1 -runs=1000  2>&1 | FileCheck %s +RUN: %run %t-ThreadedTest -use_traces=1 -runs=1000  2>&1 | FileCheck %s +RUN: %run %t-ThreadedTest -use_traces=1 -runs=1000  2>&1 | FileCheck %s +RUN: %run %t-ThreadedTest -use_traces=1 -runs=1000  2>&1 | FileCheck %s diff --git a/test/fuzzer/fuzzer-timeout.test b/test/fuzzer/fuzzer-timeout.test index 41f4ba3643983..a924cde73373e 100644 --- a/test/fuzzer/fuzzer-timeout.test +++ b/test/fuzzer/fuzzer-timeout.test @@ -1,6 +1,6 @@  RUN: %cpp_compiler %S/TimeoutTest.cpp -o %t-TimeoutTest  RUN: %cpp_compiler %S/TimeoutEmptyTest.cpp -o %t-TimeoutEmptyTest -RUN: not %t-TimeoutTest -timeout=1 2>&1 | FileCheck %s --check-prefix=TimeoutTest +RUN: not %run %t-TimeoutTest -timeout=1 2>&1 | FileCheck %s --check-prefix=TimeoutTest  TimeoutTest: ALARM: working on the last Unit for  TimeoutTest: Test unit written to ./timeout-  TimeoutTest: == ERROR: libFuzzer: timeout after @@ -9,13 +9,13 @@ TimeoutTest: #1  TimeoutTest: #2  TimeoutTest: SUMMARY: libFuzzer: timeout -RUN: not %t-TimeoutTest -timeout=1 %S/hi.txt 2>&1 | FileCheck %s --check-prefix=SingleInputTimeoutTest +RUN: not %run %t-TimeoutTest -timeout=1 %S/hi.txt 2>&1 | FileCheck %s --check-prefix=SingleInputTimeoutTest  SingleInputTimeoutTest: ALARM: working on the last Unit for {{[1-3]}} seconds  SingleInputTimeoutTest-NOT: Test unit written to ./timeout- -RUN: %t-TimeoutTest -timeout=1 -timeout_exitcode=0 +RUN: %run %t-TimeoutTest -timeout=1 -timeout_exitcode=0 -RUN: not %t-TimeoutEmptyTest -timeout=1 2>&1 | FileCheck %s --check-prefix=TimeoutEmptyTest +RUN: not %run %t-TimeoutEmptyTest -timeout=1 2>&1 | FileCheck %s --check-prefix=TimeoutEmptyTest  TimeoutEmptyTest: ALARM: working on the last Unit for  TimeoutEmptyTest: == ERROR: libFuzzer: timeout after  TimeoutEmptyTest: SUMMARY: libFuzzer: timeout diff --git a/test/fuzzer/fuzzer-ubsan.test b/test/fuzzer/fuzzer-ubsan.test index 49c190cd034b5..6bc2c38636688 100644 --- a/test/fuzzer/fuzzer-ubsan.test +++ b/test/fuzzer/fuzzer-ubsan.test @@ -1,5 +1,5 @@  RUN: %cpp_compiler -fsanitize=undefined -fno-sanitize-recover=all %S/SignedIntOverflowTest.cpp -o %t-SignedIntOverflowTest-Ubsan -RUN: not %t-SignedIntOverflowTest-Ubsan 2>&1 | FileCheck %s +RUN: not %run %t-SignedIntOverflowTest-Ubsan 2>&1 | FileCheck %s  CHECK: runtime error: signed integer overflow: 2147483647 + 1 cannot be represented in type 'int'  CHECK: Test unit written to ./crash- diff --git a/test/fuzzer/fuzzer.test b/test/fuzzer/fuzzer.test deleted file mode 100644 index 29bc8f0ce795f..0000000000000 --- a/test/fuzzer/fuzzer.test +++ /dev/null @@ -1,70 +0,0 @@ -CHECK: BINGO -Done1000000: Done 1000000 runs in -RUN: %cpp_compiler %S/BogusInitializeTest.cpp -o %t-BogusInitializeTest -RUN: %cpp_compiler %S/BufferOverflowOnInput.cpp -o %t-BufferOverflowOnInput -RUN: %cpp_compiler %S/CounterTest.cpp -o %t-CounterTest -RUN: %cpp_compiler %S/DSO1.cpp -fPIC -shared -o %t-DSO1.so -RUN: %cpp_compiler %S/DSO2.cpp -fPIC -shared -o %t-DSO2.so -RUN: %cpp_compiler %S/DSOTestMain.cpp %S/DSOTestExtra.cpp -L. %t-DSO1.so %t-DSO2.so -o %t-DSOTest -RUN: %cpp_compiler %S/FullCoverageSetTest.cpp -o %t-FullCoverageSetTest -RUN: %cpp_compiler %S/InitializeTest.cpp -o %t-InitializeTest -RUN: %cpp_compiler %S/NotinstrumentedTest.cpp -fsanitize-coverage=0 -o %t-NotinstrumentedTest-NoCoverage -RUN: %cpp_compiler %S/NullDerefOnEmptyTest.cpp -o %t-NullDerefOnEmptyTest -RUN: %cpp_compiler %S/NullDerefTest.cpp -o %t-NullDerefTest -RUN: %cpp_compiler %S/SimpleCmpTest.cpp -o %t-SimpleCmpTest -RUN: %cpp_compiler %S/SimpleTest.cpp -o %t-SimpleTest -RUN: %cpp_compiler %S/StrncmpOOBTest.cpp -o %t-StrncmpOOBTest - -RUN: not %t-SimpleTest 2>&1 | FileCheck %s - -# only_ascii mode. Will perform some minimal self-validation. -RUN: not %t-SimpleTest -only_ascii=1 2>&1 - -RUN: %t-SimpleCmpTest -max_total_time=1 -use_cmp=0 2>&1 | FileCheck %s --check-prefix=MaxTotalTime -MaxTotalTime: Done {{.*}} runs in {{.}} second(s) - -RUN: not %t-NullDerefTest                  2>&1 | FileCheck %s --check-prefix=NullDerefTest -RUN: not %t-NullDerefTest -close_fd_mask=3 2>&1 | FileCheck %s --check-prefix=NullDerefTest -NullDerefTest: ERROR: AddressSanitizer: {{SEGV|access-violation}} on unknown address -NullDerefTest: Test unit written to ./crash- -RUN: not %t-NullDerefTest  -artifact_prefix=ZZZ 2>&1 | FileCheck %s --check-prefix=NullDerefTestPrefix -NullDerefTestPrefix: Test unit written to ZZZcrash- -RUN: not %t-NullDerefTest  -artifact_prefix=ZZZ -exact_artifact_path=FOOBAR 2>&1 | FileCheck %s --check-prefix=NullDerefTestExactPath -NullDerefTestExactPath: Test unit written to FOOBAR - -RUN: not %t-NullDerefOnEmptyTest -print_final_stats=1 2>&1 | FileCheck %s --check-prefix=NULL_DEREF_ON_EMPTY -NULL_DEREF_ON_EMPTY: stat::number_of_executed_units: - -#not %t-FullCoverageSetTest -timeout=15 -seed=1 -mutate_depth=2 -use_full_coverage_set=1 2>&1 | FileCheck %s - -RUN: not %t-CounterTest  -max_len=6 -seed=1 -timeout=15 2>&1 | FileCheck %s --check-prefix=COUNTERS - -COUNTERS: INITED {{.*}} {{bits:|ft:}} -COUNTERS: NEW {{.*}} {{bits:|ft:}} {{[1-9]*}} -COUNTERS: NEW {{.*}} {{bits:|ft:}} {{[1-9]*}} -COUNTERS: BINGO - -# Don't run UninstrumentedTest for now since we build libFuzzer itself with asan. -DISABLED: not %t-UninstrumentedTest-Uninstrumented 2>&1 | FileCheck %s --check-prefix=UNINSTRUMENTED -UNINSTRUMENTED: ERROR: __sanitizer_set_death_callback is not defined. Exiting. - -RUN: not %t-NotinstrumentedTest-NoCoverage 2>&1 | FileCheck %s --check-prefix=NO_COVERAGE -NO_COVERAGE: ERROR: no interesting inputs were found. Is the code instrumented for coverage? Exiting - -RUN: not %t-BufferOverflowOnInput 2>&1 | FileCheck %s --check-prefix=OOB -OOB: AddressSanitizer: heap-buffer-overflow -OOB: is located 0 bytes to the right of 3-byte region - -RUN: not %t-InitializeTest -use_value_profile=1 2>&1 | FileCheck %s - -RUN: not %t-DSOTest 2>&1 | FileCheck %s --check-prefix=DSO -DSO: INFO: Loaded 3 modules -DSO: BINGO - -RUN: env ASAN_OPTIONS=strict_string_checks=1 not %t-StrncmpOOBTest -seed=1 -runs=1000000 2>&1 | FileCheck %s --check-prefix=STRNCMP -STRNCMP: AddressSanitizer: heap-buffer-overflow -STRNCMP-NOT: __sanitizer_weak_hook_strncmp -STRNCMP: in LLVMFuzzerTestOneInput - -RUN: not %t-BogusInitializeTest 2>&1 | FileCheck %s --check-prefix=BOGUS_INITIALIZE -BOGUS_INITIALIZE: argv[0] has been modified in LLVMFuzzerInitialize diff --git a/test/fuzzer/gc-sections.test b/test/fuzzer/gc-sections.test index 8785bb00ec1ba..b8abfbbdf17bd 100644 --- a/test/fuzzer/gc-sections.test +++ b/test/fuzzer/gc-sections.test @@ -1,12 +1,14 @@ -REQUIRES: linux +REQUIRES: linux, lld-available  No gc-sections:  RUN: %cpp_compiler %S/GcSectionsTest.cpp -o %t  RUN: nm %t | grep UnusedFunctionShouldBeRemovedByLinker | count 1 -With gc-sections. Currently, we can't remove unused code. -DISABLED: %cpp_compiler %S/GcSectionsTest.cpp -o %t -ffunction-sections -Wl,-gc-sections -DISABLED: nm %t | grep UnusedFunctionShouldBeRemovedByLinker | count 1 +With gc-sections. Currently, we can't remove unused code except with LLD. +RUN: %cpp_compiler %S/GcSectionsTest.cpp -o %t -fuse-ld=lld -ffunction-sections -Wl,-gc-sections +RUN: nm %t | not grep UnusedFunctionShouldBeRemovedByLinker +RUN: %run %t -runs=0 2>&1 | FileCheck %s +CHECK-NOT: ERROR: The size of coverage PC tables does not match  With gc sections, with trace-pc. Unused code is removed.  RUN: %cpp_compiler %S/GcSectionsTest.cpp -o %t -fsanitize-coverage=0 -fsanitize-coverage=trace-pc -ffunction-sections -Wl,-gc-sections diff --git a/test/fuzzer/handle-unstable.test b/test/fuzzer/handle-unstable.test new file mode 100644 index 0000000000000..798ee2dc042fb --- /dev/null +++ b/test/fuzzer/handle-unstable.test @@ -0,0 +1,42 @@ +# Tests -handle_unstable +UNSUPPORTED: aarch64 + +RUN: %cpp_compiler %S/PrintUnstableStatsTest.cpp -o %t-HandleUnstableTest + +; Normal +RUN: %run %t-HandleUnstableTest -print_coverage=1 -runs=100000 2>&1 | FileCheck %s --check-prefix=NORMAL +NORMAL-DAG: det0() +NORMAL-DAG: det1() +NORMAL-DAG: det2() +NORMAL-DAG: det3() +NORMAL-DAG: det4() +NORMAL-DAG: ini0() +NORMAL-DAG: ini1() +NORMAL-DAG: ini2() +NORMAL-DAG: t0() +NORMAL-DAG: t1() +NORMAL-DAG: t2() +NORMAL-DAG: t3() +NORMAL-DAG: t4() + +; MinUnstable +RUN: %run %t-HandleUnstableTest -print_coverage=1 -handle_unstable=1 -runs=100000 2>&1 | FileCheck %s --check-prefix=MIN +MIN-NOT: ini0() +MIN-NOT: ini1() +MIN-NOT: ini2() +MIN: det0() +MIN: det1() +MIN: det2() +MIN: det3() +MIN: det4() + +; ZeroUnstable +RUN: %run %t-HandleUnstableTest -print_coverage=1 -handle_unstable=2 -runs=1 2>&1 | FileCheck %s --check-prefix=ZERO +ZERO-NOT: ini0() +ZERO-NOT: ini1() +ZERO-NOT: ini2() +ZERO: det0() +ZERO: det1() +ZERO: det2() +ZERO: det3() +ZERO: det4() diff --git a/test/fuzzer/initialize.test b/test/fuzzer/initialize.test new file mode 100644 index 0000000000000..dc6e8697558e5 --- /dev/null +++ b/test/fuzzer/initialize.test @@ -0,0 +1,3 @@ +CHECK: BINGO +RUN: %cpp_compiler %S/InitializeTest.cpp -o %t-InitializeTest +RUN: not %run %t-InitializeTest -use_value_profile=1 2>&1 | FileCheck %s diff --git a/test/fuzzer/inline-8bit-counters.test b/test/fuzzer/inline-8bit-counters.test deleted file mode 100644 index 76ae1f537f723..0000000000000 --- a/test/fuzzer/inline-8bit-counters.test +++ /dev/null @@ -1,4 +0,0 @@ -RUN: %cpp_compiler %S/SimpleTest.cpp -fno-sanitize-coverage=trace-pc-guard -fsanitize-coverage=inline-8bit-counters -o %t-SimpleTest-Inline8bitCounters -CHECK: INFO: Loaded 1 modules ({{.*}} inline 8-bit counters) -CHECK: BINGO -RUN: not %t-SimpleTest-Inline8bitCounters -runs=1000000 -seed=1 2>&1 | FileCheck %s diff --git a/test/fuzzer/lit.cfg b/test/fuzzer/lit.cfg index 0350a1ad77978..8a44860d4a5dc 100644 --- a/test/fuzzer/lit.cfg +++ b/test/fuzzer/lit.cfg @@ -2,7 +2,7 @@ import lit.formats  import sys  import os -config.name = "LLVMFuzzer" +config.name = "libFuzzer" + config.name_suffix  config.test_format = lit.formats.ShTest(True)  config.suffixes = ['.test']  config.test_source_root = os.path.dirname(__file__) @@ -25,12 +25,20 @@ else:  config.test_format = lit.formats.ShTest(execute_external)  # LeakSanitizer is not supported on OSX right now. -if sys.platform.startswith('darwin'): +if sys.platform.startswith('darwin') or sys.platform.startswith('freebsd'):    lit_config.note('lsan feature unavailable')  else:    lit_config.note('lsan feature available')    config.available_features.add('lsan') +# MemorySanitizer is not supported on OSX right now +if sys.platform.startswith('darwin'): +  lit_config.note('msan feature unavailable') +  assert 'msan' not in config.available_features +else: +  lit_config.note('msan feature available') +  config.available_features.add('msan') +  if sys.platform.startswith('win') or sys.platform.startswith('cygwin'):    config.available_features.add('windows') @@ -49,18 +57,36 @@ config.substitutions.append(('%build_dir', config.cmake_binary_dir))  libfuzzer_src_root = os.path.join(config.compiler_rt_src_root, "lib", "fuzzer")  config.substitutions.append(('%libfuzzer_src', libfuzzer_src_root)) -def generate_compiler_cmd(is_cpp=True, fuzzer_enabled=True): -  compiler_cmd = config.c_compiler -  link_cmd = '-lc++' if 'darwin' in config.target_triple else '-lstdc++' -  std_cmd = '-std=c++11' if is_cpp else '' -  sanitizers = ['address'] +def generate_compiler_cmd(is_cpp=True, fuzzer_enabled=True, msan_enabled=False): +  compiler_cmd = config.clang +  extra_cmd = config.target_flags +  if config.clang and config.stdlib == 'libc++': +    link_cmd = '-stdlib=libc++ -Wl,-rpath=%s' % config.runtime_library_dir +  elif config.clang and config.stdlib == 'static-libc++': +    link_cmd = '-stdlib=libc++ -lc++abi -static-libstdc++ -Wl,-rpath=%s' % ( +        config.runtime_library_dir) +  elif any(x in config.target_triple for x in ('darwin', 'freebsd')): +    link_cmd = '-lc++' +  else: +    link_cmd = '-lstdc++' + +  std_cmd = '--driver-mode=g++ -std=c++11' if is_cpp else '' +  if msan_enabled: +    sanitizers = ['memory'] +  else: +    sanitizers = ['address']    if fuzzer_enabled:      sanitizers.append('fuzzer')    sanitizers_cmd = ('-fsanitize=%s' % ','.join(sanitizers)) -  isysroot_cmd = config.osx_sysroot_flag if config.osx_sysroot_flag else '' -  include_cmd = '-I%s' % libfuzzer_src_root -  return '%s %s %s -gline-tables-only %s %s %s' % ( -      compiler_cmd, std_cmd, link_cmd, isysroot_cmd, sanitizers_cmd, include_cmd) +  return " ".join([ +    compiler_cmd, +    std_cmd, +    link_cmd, +    "-O2 -gline-tables-only", +    sanitizers_cmd, +    "-I%s" % libfuzzer_src_root, +    extra_cmd +  ])  config.substitutions.append(('%cpp_compiler',        generate_compiler_cmd(is_cpp=True, fuzzer_enabled=True) @@ -77,3 +103,13 @@ config.substitutions.append(('%no_fuzzer_cpp_compiler',  config.substitutions.append(('%no_fuzzer_c_compiler',        generate_compiler_cmd(is_cpp=False, fuzzer_enabled=False)        )) + +config.substitutions.append(('%msan_compiler', +      generate_compiler_cmd(is_cpp=True, fuzzer_enabled=True, msan_enabled=True) +      )) + +if config.host_os == 'Darwin': +  if config.target_arch in ["x86_64", "x86_64h"]: +    config.parallelism_group = "darwin-64bit-sanitizer" +  elif config.apple_platform != "osx" and not config.apple_platform.endswith("sim"): +    config.parallelism_group = "darwin-ios-device-sanitizer" diff --git a/test/fuzzer/lit.site.cfg.in b/test/fuzzer/lit.site.cfg.in index 7f70c8f67d69d..b333c78e59e9a 100644 --- a/test/fuzzer/lit.site.cfg.in +++ b/test/fuzzer/lit.site.cfg.in @@ -1,17 +1,24 @@  @LIT_SITE_CFG_IN_HEADER@ -config.test_exec_root = "@CMAKE_CURRENT_BINARY_DIR@" -  config.cpp_compiler = "@LIBFUZZER_TEST_COMPILER@"  config.target_flags = "@LIBFUZZER_TEST_FLAGS@"  config.c_compiler = "@LIBFUZZER_TEST_COMPILER@" +config.stdlib = "@LIBFUZZER_TEST_STDLIB@" +config.apple_platform = "@LIBFUZZER_TEST_APPLE_PLATFORM@" +config.name_suffix = "@LIBFUZZER_TEST_CONFIG_SUFFIX@"  config.osx_sysroot_flag = "@OSX_SYSROOT_FLAG@"  config.cmake_binary_dir = "@CMAKE_BINARY_DIR@" +config.llvm_library_dir = "@LLVM_LIBRARY_DIR@"  config.target_triple = "@TARGET_TRIPLE@"  # Load common config for all compiler-rt lit tests.  lit_config.load_config(config,      "@COMPILER_RT_BINARY_DIR@/test/lit.common.configured") +if config.enable_per_target_runtime_dir: +  config.runtime_library_dir = config.compiler_rt_libdir +else: +  config.runtime_library_dir = "@LLVM_LIBRARY_DIR@" +  lit_config.load_config(config, "@CMAKE_CURRENT_SOURCE_DIR@/lit.cfg") diff --git a/test/fuzzer/max-number-of-runs.test b/test/fuzzer/max-number-of-runs.test index efe7a9c0f629f..c1fa931015102 100644 --- a/test/fuzzer/max-number-of-runs.test +++ b/test/fuzzer/max-number-of-runs.test @@ -1,10 +1,10 @@  RUN: %cpp_compiler %S/AccumulateAllocationsTest.cpp -o %t-AccumulateAllocationsTest -RUN: %t-AccumulateAllocationsTest -seed=1 -runs=2 2>&1 | FileCheck %s --check-prefix=CHECK1 +RUN: %run %t-AccumulateAllocationsTest -seed=1 -runs=2 2>&1 | FileCheck %s --check-prefix=CHECK1  CHECK1: Done 2 runs -RUN: %t-AccumulateAllocationsTest -seed=1 -runs=3 2>&1 | FileCheck %s --check-prefix=CHECK2 +RUN: %run %t-AccumulateAllocationsTest -seed=1 -runs=3 2>&1 | FileCheck %s --check-prefix=CHECK2  CHECK2: Done 3 runs -RUN: %t-AccumulateAllocationsTest -seed=1 -runs=4 2>&1 | FileCheck %s --check-prefix=CHECK3 +RUN: %run %t-AccumulateAllocationsTest -seed=1 -runs=4 2>&1 | FileCheck %s --check-prefix=CHECK3  CHECK3: Done 4 runs diff --git a/test/fuzzer/memcmp.test b/test/fuzzer/memcmp.test index 3431a524ced5d..5657cab41dfc2 100644 --- a/test/fuzzer/memcmp.test +++ b/test/fuzzer/memcmp.test @@ -1,3 +1,4 @@ +UNSUPPORTED: freebsd  RUN: %cpp_compiler %S/MemcmpTest.cpp -o %t-MemcmpTest -RUN: not %t-MemcmpTest               -seed=1 -runs=10000000   2>&1 | FileCheck %s +RUN: not %run %t-MemcmpTest               -seed=1 -runs=10000000   2>&1 | FileCheck %s  CHECK: BINGO diff --git a/test/fuzzer/memcmp64.test b/test/fuzzer/memcmp64.test index 223c3bd42a7df..24d14bf73bbf4 100644 --- a/test/fuzzer/memcmp64.test +++ b/test/fuzzer/memcmp64.test @@ -1,3 +1,4 @@ +UNSUPPORTED: freebsd  RUN: %cpp_compiler %S/Memcmp64BytesTest.cpp -o %t-Memcmp64BytesTest -RUN: not %t-Memcmp64BytesTest        -seed=1 -runs=1000000   2>&1 | FileCheck %s +RUN: not %run %t-Memcmp64BytesTest        -seed=1 -runs=1000000   2>&1 | FileCheck %s  CHECK: BINGO diff --git a/test/fuzzer/merge-control-file.test b/test/fuzzer/merge-control-file.test index 2da5c4ccfb2bc..64b747116a9ff 100644 --- a/test/fuzzer/merge-control-file.test +++ b/test/fuzzer/merge-control-file.test @@ -1,3 +1,4 @@ +XFAIL: ios  RUN: mkdir -p %t  RUN: %cpp_compiler %S/FullCoverageSetTest.cpp -o %t/T @@ -10,9 +11,9 @@ RUN: echo ..Z... > %t/T0/3  # Test what happens if the control file is junk.  RUN: echo JUNK > %t/MCF -RUN: not %t/T -merge=1 %t/T1 %t/T2 -merge_control_file=%t/MCF 2>&1 | FileCheck %s --check-prefix=JUNK +RUN: not %run %t/T -merge=1 %t/T1 %t/T2 -merge_control_file=%t/MCF 2>&1 | FileCheck %s --check-prefix=JUNK  RUN: echo 3 > %t/MCF; echo 0 >> %t/MCF; echo %t/T1/1 >> %t/MCF -RUN: not %t/T -merge=1 %t/T1 %t/T2 -merge_control_file=%t/MCF 2>&1 | FileCheck %s --check-prefix=JUNK +RUN: not %run %t/T -merge=1 %t/T1 %t/T2 -merge_control_file=%t/MCF 2>&1 | FileCheck %s --check-prefix=JUNK  JUNK: MERGE-OUTER: non-empty control file provided: {{.*}}MCF  JUNK: MERGE-OUTER: bad control file, will overwrite it @@ -21,18 +22,18 @@ JUNK: MERGE-OUTER: bad control file, will overwrite it  RUN: rm -f %t/T1/*; cp %t/T0/* %t/T1  RUN: echo 3 > %t/MCF; echo 0 >> %t/MCF; echo %t/T1/1 >> %t/MCF; echo %t/T1/2 >> %t/MCF; echo %t/T1/3 >> %t/MCF -RUN: %t/T -merge=1 %t/T1 %t/T2 -merge_control_file=%t/MCF 2>&1 | FileCheck %s --check-prefix=OK_0 +RUN: %run %t/T -merge=1 %t/T1 %t/T2 -merge_control_file=%t/MCF 2>&1 | FileCheck %s --check-prefix=OK_0  OK_0: MERGE-OUTER: control file ok, 3 files total, first not processed file 0  OK_0: MERGE-OUTER: 3 new files with {{.*}} new features added  RUN: rm -f %t/T1/*; cp %t/T0/* %t/T1  RUN: echo 3 > %t/MCF; echo 0 >> %t/MCF; echo %t/T1/1 >> %t/MCF; echo %t/T1/2 >> %t/MCF; echo %t/T1/3 >> %t/MCF -RUN: %t/T -merge=1 %t/T1 %t/T2 -merge_control_file=%t/MCF -save_coverage_summary=%t/SUMMARY 2>&1 | FileCheck %s --check-prefix=SAVE_SUMMARY +RUN: %run %t/T -merge=1 %t/T1 %t/T2 -merge_control_file=%t/MCF -save_coverage_summary=%t/SUMMARY 2>&1 | FileCheck %s --check-prefix=SAVE_SUMMARY  SAVE_SUMMARY: MERGE-OUTER: writing coverage summary for 3 files to {{.*}}/SUMMARY  RUN: rm -f %t/T1/*; cp %t/T0/* %t/T1  RUN: echo 3 > %t/MCF; echo 0 >> %t/MCF; echo %t/T1/1 >> %t/MCF; echo %t/T1/2 >> %t/MCF; echo %t/T1/3 >> %t/MCF -RUN: %t/T -merge=1 %t/T1 %t/T2 -merge_control_file=%t/MCF -load_coverage_summary=%t/SUMMARY 2>&1 | FileCheck %s --check-prefix=LOAD_SUMMARY +RUN: %run %t/T -merge=1 %t/T1 %t/T2 -merge_control_file=%t/MCF -load_coverage_summary=%t/SUMMARY 2>&1 | FileCheck %s --check-prefix=LOAD_SUMMARY  LOAD_SUMMARY: MERGE-OUTER: coverage summary loaded from  RUN: rm -f %t/T1/*; cp %t/T0/* %t/T1 @@ -41,7 +42,7 @@ RUN: echo STARTED 0 1 >> %t/MCF  RUN: echo DONE 0 11 >> %t/MCF  RUN: echo STARTED 1 2 >> %t/MCF  RUN: echo DONE 1 12 >> %t/MCF -RUN: %t/T -merge=1 %t/T1 %t/T2 -merge_control_file=%t/MCF 2>&1 | FileCheck %s --check-prefix=OK_2 +RUN: %run %t/T -merge=1 %t/T1 %t/T2 -merge_control_file=%t/MCF 2>&1 | FileCheck %s --check-prefix=OK_2  OK_2: MERGE-OUTER: control file ok, 3 files total, first not processed file 2  OK_2: MERGE-OUTER: 3 new files with {{.*}} new features added @@ -53,5 +54,5 @@ RUN: echo STARTED 1 2 >> %t/MCF  RUN: echo DONE 1 12 >> %t/MCF  RUN: echo STARTED 2 2 >> %t/MCF  RUN: echo DONE 2 13 >> %t/MCF -RUN: %t/T -merge=1 %t/T1 %t/T2 -merge_control_file=%t/MCF 2>&1 | FileCheck %s --check-prefix=OK_3 +RUN: %run %t/T -merge=1 %t/T1 %t/T2 -merge_control_file=%t/MCF 2>&1 | FileCheck %s --check-prefix=OK_3  OK_3: MERGE-OUTER: nothing to do, merge has been completed before diff --git a/test/fuzzer/merge-posix.test b/test/fuzzer/merge-posix.test index e34e3a325b741..db0a48b5481e4 100644 --- a/test/fuzzer/merge-posix.test +++ b/test/fuzzer/merge-posix.test @@ -1,3 +1,4 @@ +XFAIL: ios  RUN: %cpp_compiler %S/FullCoverageSetTest.cpp -o %t-FullCoverageSetTest  RUN: rm -rf  %tmp/T1 %tmp/T2 @@ -15,9 +16,9 @@ RUN: echo ....E. > %tmp/T2/5  RUN: echo .....R > %tmp/T2/6  # Check that we can report an error if file size exceeded -RUN: (ulimit -f 1; not %t-FullCoverageSetTest -merge=1 %tmp/T1 %tmp/T2 2>&1 | FileCheck %s --check-prefix=SIGXFSZ) +RUN: (ulimit -f 1; not %run %t-FullCoverageSetTest -merge=1 %tmp/T1 %tmp/T2 2>&1 | FileCheck %s --check-prefix=SIGXFSZ)  SIGXFSZ: ERROR: libFuzzer: file size exceeded  # Check that we honor TMPDIR -RUN: TMPDIR=DIR_DOES_NOT_EXIST not %t-FullCoverageSetTest -merge=1 %tmp/T1 %tmp/T2 2>&1 | FileCheck %s --check-prefix=TMPDIR +RUN: TMPDIR=DIR_DOES_NOT_EXIST not %run %t-FullCoverageSetTest -merge=1 %tmp/T1 %tmp/T2 2>&1 | FileCheck %s --check-prefix=TMPDIR  TMPDIR: MERGE-OUTER: failed to write to the control file: DIR_DOES_NOT_EXIST/libFuzzerTemp diff --git a/test/fuzzer/merge-sigusr.test b/test/fuzzer/merge-sigusr.test index efb00daa4643a..a03e5440a8b88 100644 --- a/test/fuzzer/merge-sigusr.test +++ b/test/fuzzer/merge-sigusr.test @@ -1,4 +1,5 @@  # Check that libFuzzer honors SIGUSR1/SIGUSR2 +UNSUPPORTED: darwin  RUN: rm -rf %t  RUN: mkdir -p %t  RUN: %cpp_compiler %S/SleepOneSecondTest.cpp -o %t/LFSIGUSR @@ -12,7 +13,7 @@ RUN: echo e > %t/C2/e  RUN: echo f > %t/C2/f  RUN: echo g > %t/C2/g -RUN: %t/LFSIGUSR -merge=1 -merge_control_file=%t/MCF %t/C1 %t/C2  2>  %t/log & export PID=$! +RUN: %run %t/LFSIGUSR -merge=1 -merge_control_file=%t/MCF %t/C1 %t/C2  2>  %t/log & export PID=$!  RUN: sleep 3  RUN: pkill -SIGUSR2 -f %t/LFSIGUSR  RUN: sleep 3 diff --git a/test/fuzzer/merge-summary.test b/test/fuzzer/merge-summary.test index 3e21c23ef38d7..116cf1db87552 100644 --- a/test/fuzzer/merge-summary.test +++ b/test/fuzzer/merge-summary.test @@ -9,9 +9,9 @@ RUN: echo F..... > %t/T2/a  RUN: echo .U.... > %t/T2/b  RUN: echo ..Z... > %t/T2/c -RUN: %t-FullCoverageSetTest -merge=1 %t/T1 %t/T2 -save_coverage_summary=%t/SUMMARY 2>&1 | FileCheck %s --check-prefix=SAVE_SUMMARY +RUN: %run %t-FullCoverageSetTest -merge=1 %t/T1 %t/T2 -save_coverage_summary=%t/SUMMARY 2>&1 | FileCheck %s --check-prefix=SAVE_SUMMARY  SAVE_SUMMARY: MERGE-OUTER: writing coverage summary for 6 files to {{.*}}SUMMARY  RUN: rm %t/T1/* -RUN: %t-FullCoverageSetTest -merge=1 %t/T1 %t/T2 -load_coverage_summary=%t/SUMMARY 2>&1 | FileCheck %s --check-prefix=LOAD_SUMMARY +RUN: %run %t-FullCoverageSetTest -merge=1 %t/T1 %t/T2 -load_coverage_summary=%t/SUMMARY 2>&1 | FileCheck %s --check-prefix=LOAD_SUMMARY  LOAD_SUMMARY: MERGE-OUTER: coverage summary loaded from {{.*}}SUMMAR  LOAD_SUMMARY: MERGE-OUTER: 0 new files with 0 new features added diff --git a/test/fuzzer/merge.test b/test/fuzzer/merge.test index d17405595eb72..ec41c82b93449 100644 --- a/test/fuzzer/merge.test +++ b/test/fuzzer/merge.test @@ -1,3 +1,4 @@ +XFAIL: ios  CHECK: BINGO  RUN: %cpp_compiler %S/FullCoverageSetTest.cpp -o %t-FullCoverageSetTest @@ -10,7 +11,7 @@ RUN: echo ..Z... > %t/T0/3  # T1 has 3 elements, T2 is empty.  RUN: cp %t/T0/* %t/T1/ -RUN: %t-FullCoverageSetTest         -merge=1 %t/T1 %t/T2 2>&1 | FileCheck %s --check-prefix=CHECK1 +RUN: %run %t-FullCoverageSetTest         -merge=1 %t/T1 %t/T2 2>&1 | FileCheck %s --check-prefix=CHECK1  CHECK1: MERGE-OUTER: 3 files, 3 in the initial corpus  CHECK1: MERGE-OUTER: 0 new files with 0 new features added @@ -22,12 +23,12 @@ RUN: echo .U.... > %t/T2/b  RUN: echo ..Z... > %t/T2/c  # T1 has 3 elements, T2 has 6 elements, only 3 are new. -RUN: %t-FullCoverageSetTest         -merge=1 %t/T1 %t/T2 2>&1 | FileCheck %s --check-prefix=CHECK2 +RUN: %run %t-FullCoverageSetTest         -merge=1 %t/T1 %t/T2 2>&1 | FileCheck %s --check-prefix=CHECK2  CHECK2: MERGE-OUTER: 9 files, 3 in the initial corpus  CHECK2: MERGE-OUTER: 3 new files with 3 new features added  # Now, T1 has 6 units and T2 has no new interesting units. -RUN: %t-FullCoverageSetTest         -merge=1 %t/T1 %t/T2 2>&1 | FileCheck %s --check-prefix=CHECK3 +RUN: %run %t-FullCoverageSetTest         -merge=1 %t/T1 %t/T2 2>&1 | FileCheck %s --check-prefix=CHECK3  CHECK3: MERGE-OUTER: 12 files, 6 in the initial corpus  CHECK3: MERGE-OUTER: 0 new files with 0 new features added @@ -35,14 +36,14 @@ CHECK3: MERGE-OUTER: 0 new files with 0 new features added  RUN: rm %t/T1/*  RUN: cp %t/T0/* %t/T1/  RUN: echo looooooooong > %t/T2/looooooooong -RUN: %t-FullCoverageSetTest         -merge=1 %t/T1 %t/T2 -max_len=6 2>&1 | FileCheck %s --check-prefix=MAX_LEN +RUN: %run %t-FullCoverageSetTest         -merge=1 %t/T1 %t/T2 -max_len=6 2>&1 | FileCheck %s --check-prefix=MAX_LEN  MAX_LEN: MERGE-OUTER: 3 new files  # Check that we respect -merge_control_file=FILE  RUN: rm %t/T1/*  RUN: cp %t/T0/* %t/T1/  RUN: rm -f %t/MCF -RUN: %t-FullCoverageSetTest -merge=1 -merge_control_file=%t/MCF %t/T1 %t/T2 2>&1 | FileCheck %s --check-prefix=MCF +RUN: %run %t-FullCoverageSetTest -merge=1 -merge_control_file=%t/MCF %t/T1 %t/T2 2>&1 | FileCheck %s --check-prefix=MCF  RUN: grep STARTED %t/MCF  RUN: grep DONE %t/MCF  MCF: MERGE-INNER: using the control file {{.*}}MCF @@ -53,18 +54,18 @@ MCF: MERGE-OUTER: 3 new files  RUN: rm %t/T1/*  RUN: cp %t/T0/* %t/T1/  RUN: echo 'FUZZER' > %t/T2/FUZZER -RUN: %t-FullCoverageSetTest -merge=1 %t/T1 %t/T2 2>&1 | FileCheck %s --check-prefix=MERGE_WITH_CRASH +RUN: %run %t-FullCoverageSetTest -merge=1 %t/T1 %t/T2 2>&1 | FileCheck %s --check-prefix=MERGE_WITH_CRASH  MERGE_WITH_CRASH: MERGE-OUTER: succesfull in 2 attempt(s)  MERGE_WITH_CRASH: MERGE-OUTER: 3 new files  # Check that we actually limit the size with max_len  RUN: rm %t/T1/* %t/T2/*  RUN: echo 'FUZZER' > %t/T2/FUZZER -RUN: %t-FullCoverageSetTest -merge=1 %t/T1 %t/T2  -max_len=5 2>&1 | FileCheck %s --check-prefix=MERGE_LEN5 +RUN: %run %t-FullCoverageSetTest -merge=1 %t/T1 %t/T2  -max_len=5 2>&1 | FileCheck %s --check-prefix=MERGE_LEN5  RUN: not grep FUZZER %t/T1/*  RUN: grep FUZZE %t/T1/*  MERGE_LEN5: MERGE-OUTER: succesfull in 1 attempt(s)  RUN: rm -rf  %t/T1/* %t/T2/* -RUN: not %t-FullCoverageSetTest -merge=1 %t/T1 %t/T2 2>&1 | FileCheck %s --check-prefix=EMPTY +RUN: not %run %t-FullCoverageSetTest -merge=1 %t/T1 %t/T2 2>&1 | FileCheck %s --check-prefix=EMPTY  EMPTY: MERGE-OUTER: zero succesfull attempts, exiting diff --git a/test/fuzzer/minimize_crash.test b/test/fuzzer/minimize_crash.test index 77ab370fa8992..de44b8747e04c 100644 --- a/test/fuzzer/minimize_crash.test +++ b/test/fuzzer/minimize_crash.test @@ -1,16 +1,17 @@  RUN: %cpp_compiler %S/NullDerefTest.cpp -o %t-NullDerefTest  RUN: %cpp_compiler %S/SingleByteInputTest.cpp -o %t-SingleByteInputTest +RUN: mkdir -p %t.dir -RUN: echo 'Hi!rv349f34t3gg' > not_minimal_crash -RUN: %t-NullDerefTest -minimize_crash=1 not_minimal_crash -max_total_time=2 2>&1 | FileCheck %s -CHECK: CRASH_MIN: failed to minimize beyond ./minimized-from-{{.*}} (3 bytes), exiting -RUN: %t-NullDerefTest -minimize_crash=1 not_minimal_crash -max_total_time=2 -exact_artifact_path=exact_minimized_path 2>&1 | FileCheck %s --check-prefix=CHECK_EXACT -CHECK_EXACT: CRASH_MIN: failed to minimize beyond exact_minimized_path (3 bytes), exiting -RUN: rm not_minimal_crash minimized-from-* exact_minimized_path +RUN: echo 'Hi!rv349f34t3gg' > %t.dir/not_minimal_crash +RUN: %run %t-NullDerefTest -minimize_crash=1 %t.dir/not_minimal_crash -max_total_time=2 2>&1 | FileCheck %s +CHECK: CRASH_MIN: failed to minimize beyond {{.*}}minimized-from{{.*}} (3 bytes), exiting +RUN: %run %t-NullDerefTest -minimize_crash=1 %t.dir/not_minimal_crash -max_total_time=2 -exact_artifact_path=%t.exact_minimized_path 2>&1 | FileCheck %s --check-prefix=CHECK_EXACT +CHECK_EXACT: CRASH_MIN: failed to minimize beyond {{.*}}exact_minimized_path{{.*}} (3 bytes), exiting +RUN: rm %t.dir/not_minimal_crash %t.exact_minimized_path -RUN: echo -n 'abcd*xyz' > not_minimal_crash -RUN: %t-SingleByteInputTest -minimize_crash=1 not_minimal_crash -exact_artifact_path=exact_minimized_path 2>&1 | FileCheck %s --check-prefix=MIN1 -MIN1: Test unit written to exact_minimized_path -MIN1: Test unit written to exact_minimized_path +RUN: echo -n 'abcd*xyz' > %t.dir/not_minimal_crash +RUN: %run %t-SingleByteInputTest -minimize_crash=1 %t.dir/not_minimal_crash -exact_artifact_path=%t.exact_minimized_path 2>&1 | FileCheck %s --check-prefix=MIN1 +MIN1: Test unit written to {{.*}}exact_minimized_path +MIN1: Test unit written to {{.*}}exact_minimized_path  MIN1: INFO: The input is small enough, exiting -MIN1: CRASH_MIN: failed to minimize beyond exact_minimized_path (1 bytes), exiting +MIN1: CRASH_MIN: failed to minimize beyond {{.*}}exact_minimized_path (1 bytes), exiting diff --git a/test/fuzzer/minimize_two_crashes.test b/test/fuzzer/minimize_two_crashes.test index e6ff9990ffd82..3c528f7076669 100644 --- a/test/fuzzer/minimize_two_crashes.test +++ b/test/fuzzer/minimize_two_crashes.test @@ -1,10 +1,12 @@  # Test that the minimizer stops when it sees a differe bug. +UNSUPPORTED: freebsd -RUN: %cpp_compiler %S/TwoDifferentBugsTest.cpp -o %t-TwoDifferentBugsTest +# TODO: Find out why test fails on Darwin with -O2. +RUN: %cpp_compiler -O0 %S/TwoDifferentBugsTest.cpp -o %t-TwoDifferentBugsTest  RUN: rm -rf %t && mkdir %t  RUN: echo H12345678901234667888090 > %t/long_crash -RUN: env ASAN_OPTIONS=dedup_token_length=3 %t-TwoDifferentBugsTest -seed=1 -minimize_crash=1 %t/long_crash -exact_artifact_path=%t/result 2>&1 | FileCheck %s +RUN: env ASAN_OPTIONS=dedup_token_length=3 %run %t-TwoDifferentBugsTest -seed=1 -minimize_crash=1 %t/long_crash -exact_artifact_path=%t/result 2>&1 | FileCheck %s  CHECK: DedupToken1: DEDUP_TOKEN: Bar  CHECK: DedupToken2: DEDUP_TOKEN: Bar @@ -12,7 +14,7 @@ CHECK: DedupToken1: DEDUP_TOKEN: Bar  CHECK: DedupToken2: DEDUP_TOKEN: Foo  CHECK: CRASH_MIN: mismatch in dedup tokens -RUN: not  %t-TwoDifferentBugsTest %t/result 2>&1 | FileCheck %s --check-prefix=VERIFY +RUN: not  %run %t-TwoDifferentBugsTest %t/result 2>&1 | FileCheck %s --check-prefix=VERIFY  VERIFY: ERROR: AddressSanitizer:  VERIFY: in Bar diff --git a/test/fuzzer/msan.test b/test/fuzzer/msan.test new file mode 100644 index 0000000000000..2e0339bb8ff7b --- /dev/null +++ b/test/fuzzer/msan.test @@ -0,0 +1,24 @@ +REQUIRES: msan +RUN: %msan_compiler %S/SimpleTestStdio.cpp -o %t +RUN: not %run %t -seed=1 -runs=10000000 2>&1 | FileCheck %s --check-prefix=NO-REPORT + +RUN: %msan_compiler %S/SimpleCmpTest.cpp -o %t +RUN: not %run %t -seed=1 -runs=10000000 2>&1 | FileCheck %s --check-prefix=NO-REPORT + +RUN: %msan_compiler %S/MemcmpTest.cpp -o %t +RUN: not %run %t -seed=1 -runs=10000000 2>&1 | FileCheck %s --check-prefix=NO-REPORT + +RUN: %msan_compiler %S/StrcmpTest.cpp -o %t +RUN: not %run %t -seed=1 -runs=10000000 2>&1 | FileCheck %s --check-prefix=NO-REPORT + +NO-REPORT-NOT: MemorySanitizer +NO-REPORT: BINGO + + +RUN: %msan_compiler %S/UseAfterDtor.cpp -o %t +RUN: MSAN_OPTIONS=poison_in_dtor=1 not %run %t -seed=1 -runs=10000000 2>&1 | FileCheck %s --check-prefix=REPORT + +RUN: %msan_compiler %S/UninitializedStrlen.cpp -o %t +RUN: not %run %t -seed=1 -runs=10000000 2>&1 | FileCheck %s --check-prefix=REPORT + +REPORT: MemorySanitizer: use-of-uninitialized-value diff --git a/test/fuzzer/not-instrumented.test b/test/fuzzer/not-instrumented.test new file mode 100644 index 0000000000000..2330c47700675 --- /dev/null +++ b/test/fuzzer/not-instrumented.test @@ -0,0 +1,4 @@ +RUN: %cpp_compiler %S/NotinstrumentedTest.cpp -fsanitize-coverage=0 -o %t-NotinstrumentedTest-NoCoverage +RUN: not %run %t-NotinstrumentedTest-NoCoverage 2>&1 | FileCheck %s --check-prefix=NO_COVERAGE + +NO_COVERAGE: ERROR: no interesting inputs were found. Is the code instrumented for coverage? Exiting diff --git a/test/fuzzer/null-deref-on-empty.test b/test/fuzzer/null-deref-on-empty.test new file mode 100644 index 0000000000000..f159a79f4838d --- /dev/null +++ b/test/fuzzer/null-deref-on-empty.test @@ -0,0 +1,4 @@ +RUN: %cpp_compiler %S/NullDerefOnEmptyTest.cpp -o %t-NullDerefOnEmptyTest + +RUN: not %run %t-NullDerefOnEmptyTest -print_final_stats=1 2>&1 | FileCheck %s --check-prefix=NULL_DEREF_ON_EMPTY +NULL_DEREF_ON_EMPTY: stat::number_of_executed_units: diff --git a/test/fuzzer/null-deref.test b/test/fuzzer/null-deref.test new file mode 100644 index 0000000000000..31eb5990da33d --- /dev/null +++ b/test/fuzzer/null-deref.test @@ -0,0 +1,10 @@ +RUN: %cpp_compiler %S/NullDerefTest.cpp -o %t-NullDerefTest + +RUN: not %run %t-NullDerefTest                  2>&1 | FileCheck %s --check-prefix=NullDerefTest +RUN: not %run %t-NullDerefTest -close_fd_mask=3 2>&1 | FileCheck %s --check-prefix=NullDerefTest +NullDerefTest: ERROR: AddressSanitizer: {{SEGV|access-violation}} on unknown address +NullDerefTest: Test unit written to ./crash- +RUN: not %run %t-NullDerefTest  -artifact_prefix=ZZZ 2>&1 | FileCheck %s --check-prefix=NullDerefTestPrefix +NullDerefTestPrefix: Test unit written to ZZZcrash- +RUN: not %run %t-NullDerefTest  -artifact_prefix=ZZZ -exact_artifact_path=FOOBAR 2>&1 | FileCheck %s --check-prefix=NullDerefTestExactPath +NullDerefTestExactPath: Test unit written to FOOBAR diff --git a/test/fuzzer/only-some-bytes.test b/test/fuzzer/only-some-bytes.test new file mode 100644 index 0000000000000..fbfef14c78509 --- /dev/null +++ b/test/fuzzer/only-some-bytes.test @@ -0,0 +1,38 @@ +# Tests the data flow tracer. +REQUIRES: linux +UNSUPPORTED: aarch64 + +# Build the tracer and the test. +RUN: %no_fuzzer_cpp_compiler -c -fno-sanitize=all -fsanitize=dataflow  %S/../../lib/fuzzer/dataflow/DataFlow.cpp -o  %t-DataFlow.o +RUN: %no_fuzzer_cpp_compiler    -fno-sanitize=all -fsanitize=dataflow -fsanitize-coverage=trace-pc-guard,pc-table,func,trace-cmp   %S/OnlySomeBytesTest.cpp     %t-DataFlow.o -o %t-DFT +RUN: %cpp_compiler %S/OnlySomeBytesTest.cpp -o %t-Fuzz + +# Prepare the inputs. +RUN: rm -rf %t/* +RUN: mkdir -p %t/IN +RUN: echo -n 0123456789012345678901234567890123456789012345678901234567891234 > %t/IN/6 +RUN: cat  %t/IN/6 %t/IN/6 %t/IN/6 %t/IN/6 > %t/IN/8 +RUN: cat  %t/IN/8 %t/IN/8 %t/IN/8 %t/IN/8 > %t/IN/10 +RUN: cat  %t/IN/10 %t/IN/10 %t/IN/10 %t/IN/10 > %t/IN/12 +# %t/IN/12 is 4096 bytes-long. + +RUN: %t-Fuzz -focus_function=f0 -runs=0 %t/IN 2>&1 | FileCheck %s --check-prefix=NO_FOCUSED_INPUT +NO_FOCUSED_INPUT: INFO: 0/2 inputs touch the focus function + +RUN: (echo -n ABC; cat %t/IN/12) > %t/IN/ABC +RUN: %t-Fuzz -focus_function=f0 -runs=0 %t/IN 2>&1 | FileCheck %s --check-prefix=ONE_FOCUSED_INPUT +ONE_FOCUSED_INPUT: INFO: 1/3 inputs touch the focus function + +RUN: rm -rf %t/IN_DFT +RUN: %libfuzzer_src/scripts/collect_data_flow.py %t-DFT %t/IN %t/IN_DFT > /dev/null 2>&1 + +# Repeat twice to make sure that the inputs with DFT are not removed from the corpus. +RUN: %t-Fuzz -focus_function=f0 -data_flow_trace=%t/IN_DFT -runs=100 %t/IN 2>&1 | FileCheck %s --check-prefix=HAVE_DFT +RUN: %t-Fuzz -focus_function=f0 -data_flow_trace=%t/IN_DFT -runs=100 %t/IN 2>&1 | FileCheck %s --check-prefix=HAVE_DFT +HAVE_DFT: INFO: 1/{{.*}} inputs have the Data Flow Trace + +# Collect DFT, then use it. +RUN: rm -rf %t/C  && mkdir %t/C &&  cp %t/IN/* %t/C +RUN: rm -rf %t/C_DFT && %libfuzzer_src/scripts/collect_data_flow.py %t-DFT %t/C %t/C_DFT > /dev/null 2>&1 +RUN: not %t-Fuzz -focus_function=f0 -data_flow_trace=%t/C_DFT -seed=1 -runs=1000000 -use_value_profile=3 %t/C 2> %t/log +RUN: grep BINGO %t/log diff --git a/test/fuzzer/overwrite-input.test b/test/fuzzer/overwrite-input.test index 3695622d03526..e5ddd62cbdc70 100644 --- a/test/fuzzer/overwrite-input.test +++ b/test/fuzzer/overwrite-input.test @@ -1,3 +1,3 @@  RUN: %cpp_compiler %S/OverwriteInputTest.cpp -o %t-OverwriteInputTest -RUN: not %t-OverwriteInputTest 2>&1 | FileCheck %s +RUN: not %run %t-OverwriteInputTest 2>&1 | FileCheck %s  CHECK: ERROR: libFuzzer: fuzz target overwrites it's const input diff --git a/test/fuzzer/print-func.test b/test/fuzzer/print-func.test index 930e9992a2f9c..c74da218282e2 100644 --- a/test/fuzzer/print-func.test +++ b/test/fuzzer/print-func.test @@ -1,6 +1,7 @@ +UNSUPPORTED: darwin, aarch64  RUN: %cpp_compiler %S/PrintFuncTest.cpp -o %t -RUN: %t -seed=1 -runs=100000 2>&1 | FileCheck %s -RUN: %t -seed=1 -runs=100000 -print_funcs=0 2>&1 | FileCheck %s --check-prefix=NO +RUN: %run %t -seed=1 -runs=100000 2>&1 | FileCheck %s +RUN: %run %t -seed=1 -runs=100000 -print_funcs=0 2>&1 | FileCheck %s --check-prefix=NO  CHECK: NEW_FUNC{{.*}} FunctionA  CHECK: NEW_FUNC{{.*}} FunctionB  CHECK: NEW_FUNC{{.*}} FunctionC diff --git a/test/fuzzer/print_unstable_stats.test b/test/fuzzer/print_unstable_stats.test new file mode 100644 index 0000000000000..bba99aecc838b --- /dev/null +++ b/test/fuzzer/print_unstable_stats.test @@ -0,0 +1,3 @@ +RUN: %cpp_compiler %S/PrintUnstableStatsTest.cpp -o %t-PrintUnstableStatsTest +RUN: %run %t-PrintUnstableStatsTest -print_unstable_stats=1 -runs=100000 2>&1 | FileCheck %s --check-prefix=LONG +LONG: stat::stability_rate: 27.59 diff --git a/test/fuzzer/recommended-dictionary.test b/test/fuzzer/recommended-dictionary.test index 41b62c924ceb0..e1d58c96fa205 100644 --- a/test/fuzzer/recommended-dictionary.test +++ b/test/fuzzer/recommended-dictionary.test @@ -1,5 +1,6 @@ +UNSUPPORTED: freebsd  RUN: %cpp_compiler %S/RepeatedMemcmp.cpp -o %t-RepeatedMemcmp -RUN: %t-RepeatedMemcmp -seed=11 -runs=100000 -max_len=20 2>&1 | FileCheck %s --check-prefix=RECOMMENDED_DICT +RUN: %run %t-RepeatedMemcmp -seed=11 -runs=100000 -max_len=20 2>&1 | FileCheck %s --check-prefix=RECOMMENDED_DICT  RECOMMENDED_DICT:###### Recommended dictionary. ######  RECOMMENDED_DICT-DAG: "foo"  RECOMMENDED_DICT-DAG: "bar" diff --git a/test/fuzzer/reduce_inputs.test b/test/fuzzer/reduce_inputs.test index 94f8cc4f37a8f..e65f572277297 100644 --- a/test/fuzzer/reduce_inputs.test +++ b/test/fuzzer/reduce_inputs.test @@ -4,13 +4,13 @@ RUN: rm -rf %t/C  RUN: mkdir -p %t/C  RUN: %cpp_compiler %S/ShrinkControlFlowSimpleTest.cpp -o %t-ShrinkControlFlowSimpleTest  RUN: %cpp_compiler %S/ShrinkControlFlowTest.cpp -o %t-ShrinkControlFlowTest -RUN: %t-ShrinkControlFlowSimpleTest  -exit_on_item=0eb8e4ed029b774d80f2b66408203801cb982a60   -runs=1000000 %t/C 2>&1 | FileCheck %s +RUN: %run %t-ShrinkControlFlowSimpleTest  -exit_on_item=0eb8e4ed029b774d80f2b66408203801cb982a60   -runs=1000000 %t/C 2>&1 | FileCheck %s  CHECK: INFO: found item with checksum '0eb8e4ed029b774d80f2b66408203801cb982a60'  # Test that reduce_inputs deletes redundant files in the corpus. -RUN: %t-ShrinkControlFlowSimpleTest -runs=0 %t/C 2>&1 | FileCheck %s --check-prefix=COUNT +RUN: %run %t-ShrinkControlFlowSimpleTest -runs=0 %t/C 2>&1 | FileCheck %s --check-prefix=COUNT  COUNT: seed corpus: files: 4  # a bit longer test -RUN: %t-ShrinkControlFlowTest  -exit_on_item=0eb8e4ed029b774d80f2b66408203801cb982a60  -seed=1 -runs=1000000  2>&1 | FileCheck %s +RUN: %run %t-ShrinkControlFlowTest  -exit_on_item=0eb8e4ed029b774d80f2b66408203801cb982a60  -seed=42 -runs=1000000  2>&1 | FileCheck %s diff --git a/test/fuzzer/repeated-bytes.test b/test/fuzzer/repeated-bytes.test index 0bba2a91688ff..e749a3e239a47 100644 --- a/test/fuzzer/repeated-bytes.test +++ b/test/fuzzer/repeated-bytes.test @@ -1,3 +1,3 @@  RUN: %cpp_compiler %S/RepeatedBytesTest.cpp -o %t-RepeatedBytesTest  CHECK: BINGO -RUN: not %t-RepeatedBytesTest -seed=1 -runs=1000000 2>&1 | FileCheck %s +RUN: not %run %t-RepeatedBytesTest -seed=1 -runs=1000000 2>&1 | FileCheck %s diff --git a/test/fuzzer/shrink.test b/test/fuzzer/shrink.test index 2988d4bbb043d..5abbcc90b8c05 100644 --- a/test/fuzzer/shrink.test +++ b/test/fuzzer/shrink.test @@ -1,9 +1,9 @@  RUN: %cpp_compiler %S/ShrinkControlFlowTest.cpp -o %t-ShrinkControlFlowTest  RUN: %cpp_compiler %S/ShrinkValueProfileTest.cpp -o %t-ShrinkValueProfileTest -RUN: %t-ShrinkControlFlowTest -seed=1 -exit_on_item=0eb8e4ed029b774d80f2b66408203801cb982a60 -runs=1000000  -shrink=1 -reduce_inputs=0 2>&1 | FileCheck %s --check-prefix=SHRINK1 +RUN: %run %t-ShrinkControlFlowTest -seed=1 -exit_on_item=0eb8e4ed029b774d80f2b66408203801cb982a60 -runs=1000000  -shrink=1 -reduce_inputs=0 2>&1 | FileCheck %s --check-prefix=SHRINK1  # Limit max_len to run this negative test faster. -RUN: %t-ShrinkControlFlowTest -seed=1 -exit_on_item=0eb8e4ed029b774d80f2b66408203801cb982a60 -runs=1000000 -shrink=0 -reduce_inputs=0 -max_len=64 2>&1 | FileCheck %s --check-prefix=SHRINK0 -RUN: %t-ShrinkValueProfileTest -seed=1 -exit_on_item=aea2e3923af219a8956f626558ef32f30a914ebc -runs=100000 -shrink=1 -reduce_inputs=0 -use_value_profile=1 2>&1 | FileCheck %s --check-prefix=SHRINK1_VP +RUN: %run %t-ShrinkControlFlowTest -seed=1 -exit_on_item=0eb8e4ed029b774d80f2b66408203801cb982a60 -runs=1000000 -shrink=0 -reduce_inputs=0 -max_len=64 2>&1 | FileCheck %s --check-prefix=SHRINK0 +RUN: %run %t-ShrinkValueProfileTest -seed=1 -exit_on_item=aea2e3923af219a8956f626558ef32f30a914ebc -runs=100000 -shrink=1 -reduce_inputs=0 -use_value_profile=1 2>&1 | FileCheck %s --check-prefix=SHRINK1_VP  SHRINK0: Done 1000000 runs in  SHRINK1: INFO: found item with checksum '0eb8e4ed029b774d80f2b66408203801cb982a60', exiting. diff --git a/test/fuzzer/sigusr.test b/test/fuzzer/sigusr.test index 12e3ac996c6ce..0b3ddc72832de 100644 --- a/test/fuzzer/sigusr.test +++ b/test/fuzzer/sigusr.test @@ -1,9 +1,10 @@ +UNSUPPORTED: darwin  # Check that libFuzzer honors SIGUSR1/SIGUSR2  RUN: rm -rf %t  RUN: mkdir -p %t  RUN: %cpp_compiler %S/SleepOneSecondTest.cpp -o %t/LFSIGUSR -RUN: %t/LFSIGUSR 2> %t/log & export PID=$! +RUN: %run %t/LFSIGUSR 2> %t/log & export PID=$!  RUN: sleep 2  RUN: kill -SIGUSR1 $PID  RUN: sleep 3 diff --git a/test/fuzzer/simple-cmp.test b/test/fuzzer/simple-cmp.test index 08123ed3ac474..e146379b2a5b7 100644 --- a/test/fuzzer/simple-cmp.test +++ b/test/fuzzer/simple-cmp.test @@ -1,3 +1,7 @@  RUN: %cpp_compiler %S/SimpleCmpTest.cpp -o %t-SimpleCmpTest + +RUN: not %run %t-SimpleCmpTest -seed=1 -runs=100000000 2>&1 | FileCheck %s +RUN: %run %t-SimpleCmpTest -max_total_time=1 -use_cmp=0 2>&1 | FileCheck %s --check-prefix=MaxTotalTime +MaxTotalTime: Done {{.*}} runs in {{.}} second(s) +  CHECK: BINGO -RUN: not %t-SimpleCmpTest -seed=1 -runs=100000000 2>&1 | FileCheck %s diff --git a/test/fuzzer/simple.test b/test/fuzzer/simple.test new file mode 100644 index 0000000000000..97a09be7cec92 --- /dev/null +++ b/test/fuzzer/simple.test @@ -0,0 +1,7 @@ +CHECK: BINGO +RUN: %cpp_compiler %S/SimpleTest.cpp -o %t-SimpleTest + +RUN: not %run %t-SimpleTest 2>&1 | FileCheck %s + +# only_ascii mode. Will perform some minimal self-validation. +RUN: not %run %t-SimpleTest -only_ascii=1 2>&1 diff --git a/test/fuzzer/standalone.test b/test/fuzzer/standalone.test index e6483703f9661..cd2422e4e6838 100644 --- a/test/fuzzer/standalone.test +++ b/test/fuzzer/standalone.test @@ -2,7 +2,7 @@ RUN: %no_fuzzer_c_compiler %libfuzzer_src/standalone/StandaloneFuzzTargetMain.c  RUN: %no_fuzzer_cpp_compiler %S/InitializeTest.cpp -c -o %t_2.o  RUN: %no_fuzzer_cpp_compiler %t_1.o %t_2.o -o %t-StandaloneInitializeTest -RUN: %t-StandaloneInitializeTest %S/hi.txt %S/dict1.txt 2>&1 | FileCheck %s +RUN: %run %t-StandaloneInitializeTest %S/hi.txt %S/dict1.txt 2>&1 | FileCheck %s  CHECK: StandaloneFuzzTargetMain: running 2 inputs  CHECK: Done:    {{.*}}hi.txt: (3 bytes)  CHECK: Done:    {{.*}}dict1.txt: (61 bytes) diff --git a/test/fuzzer/strcmp.test b/test/fuzzer/strcmp.test index 47ad8f9ba0f5b..bd917bba6b698 100644 --- a/test/fuzzer/strcmp.test +++ b/test/fuzzer/strcmp.test @@ -1,4 +1,5 @@ +UNSUPPORTED: freebsd  RUN: %cpp_compiler %S/StrcmpTest.cpp -o %t-StrcmpTest -RUN: not %t-StrcmpTest               -seed=1 -runs=2000000   2>&1 | FileCheck %s +RUN: not %run %t-StrcmpTest               -seed=1 -runs=2000000   2>&1 | FileCheck %s  CHECK: BINGO diff --git a/test/fuzzer/strncmp-oob.test b/test/fuzzer/strncmp-oob.test new file mode 100644 index 0000000000000..a0365d961833c --- /dev/null +++ b/test/fuzzer/strncmp-oob.test @@ -0,0 +1,6 @@ +RUN: %cpp_compiler %S/StrncmpOOBTest.cpp -o %t-StrncmpOOBTest + +RUN: env ASAN_OPTIONS=strict_string_checks=1 not %run %t-StrncmpOOBTest -seed=1 -runs=1000000 2>&1 | FileCheck %s --check-prefix=STRNCMP +STRNCMP: AddressSanitizer: heap-buffer-overflow +STRNCMP-NOT: __sanitizer_weak_hook_strncmp +STRNCMP: in LLVMFuzzerTestOneInput diff --git a/test/fuzzer/strncmp.test b/test/fuzzer/strncmp.test index 49693c8de8f01..50189445b102c 100644 --- a/test/fuzzer/strncmp.test +++ b/test/fuzzer/strncmp.test @@ -1,4 +1,5 @@ +UNSUPPORTED: freebsd  RUN: %cpp_compiler %S/StrncmpTest.cpp -o %t-StrncmpTest -RUN: not %t-StrncmpTest              -seed=2 -runs=10000000   2>&1 | FileCheck %s +RUN: not %run %t-StrncmpTest              -seed=2 -runs=10000000   2>&1 | FileCheck %s  CHECK: BINGO diff --git a/test/fuzzer/strstr.test b/test/fuzzer/strstr.test index c39d5801acdba..f1fb210b47c7f 100644 --- a/test/fuzzer/strstr.test +++ b/test/fuzzer/strstr.test @@ -1,4 +1,5 @@ +UNSUPPORTED: freebsd  RUN: %cpp_compiler %S/StrstrTest.cpp -o %t-StrstrTest -RUN: not %t-StrstrTest               -seed=1 -runs=2000000   2>&1 | FileCheck %s +RUN: not %run %t-StrstrTest               -seed=1 -runs=2000000   2>&1 | FileCheck %s  CHECK: BINGO diff --git a/test/fuzzer/swap-cmp.test b/test/fuzzer/swap-cmp.test index 5c2379cde4f6a..7f7e2f60fa633 100644 --- a/test/fuzzer/swap-cmp.test +++ b/test/fuzzer/swap-cmp.test @@ -1,3 +1,3 @@  RUN: %cpp_compiler %S/SwapCmpTest.cpp -o %t-SwapCmpTest  CHECK: BINGO -RUN: not %t-SwapCmpTest -seed=1 -runs=10000000 2>&1 | FileCheck %s +RUN: not %run %t-SwapCmpTest -seed=1 -runs=10000000 2>&1 | FileCheck %s diff --git a/test/fuzzer/symbolize-deadlock.test b/test/fuzzer/symbolize-deadlock.test new file mode 100644 index 0000000000000..25b519fd3fed0 --- /dev/null +++ b/test/fuzzer/symbolize-deadlock.test @@ -0,0 +1,2 @@ +RUN: %cpp_compiler %S/SymbolizeDeadlock.cpp -o %t +RUN: not %run %t -rss_limit_mb=20 2>&1 diff --git a/test/fuzzer/target-function.test b/test/fuzzer/target-function.test new file mode 100644 index 0000000000000..afd29ab8a83f4 --- /dev/null +++ b/test/fuzzer/target-function.test @@ -0,0 +1,30 @@ +# Tests -focus_function +# +# TODO: don't require linux. +# REQUIRES: linux +UNSUPPORTED: aarch64 + +RUN: %cpp_compiler %S/OnlySomeBytesTest.cpp -o %t-exe + +RUN: %t-exe -runs=100 2>&1 | FileCheck %s --check-prefix=FOCUS_NONE +FOCUS_NONE-NOT: INFO: Focus function is set to +FOCUS_NONE-NOT: INFO: {{.*}} inputs touch the focus function + +RUN: %t-exe -runs=100 -focus_function=WRONG 2>&1 | FileCheck %s --check-prefix=FOCUS_WRONG +FOCUS_WRONG-NOT: INFO: Focus function is set to +FOCUS_WRONG: INFO: 0/1 inputs touch the focus function + +RUN: %t-exe -runs=100 -focus_function=f0 2>&1 | FileCheck %s --check-prefix=FOCUS_F0 +FOCUS_F0: INFO: Focus function is set to 'f0' +FOCUS_F0: INFO: 0/1 inputs touch the focus function + +RUN: rm -rf %t-corpus +RUN: mkdir %t-corpus +# ABC triggers the focus function, others don't. +RUN: echo ABC$(for((i=0;i<2048;i++)); do echo -n x; done) > %t-corpus/ABC +RUN: echo AXY$(for((i=0;i<2048;i++)); do echo -n x; done) > %t-corpus/AXY +RUN: echo ABX$(for((i=0;i<2048;i++)); do echo -n x; done) > %t-corpus/ABX + +RUN: %t-exe -runs=10000 -focus_function=f0 %t-corpus 2>&1 | FileCheck %s --check-prefix=CORPUS_1_3 +CORPUS_1_3: INFO: 1/3 inputs touch the focus function +CORPUS_1_3: DONE {{.*}} focus: diff --git a/test/fuzzer/three-bytes.test b/test/fuzzer/three-bytes.test new file mode 100644 index 0000000000000..0b2187552cf57 --- /dev/null +++ b/test/fuzzer/three-bytes.test @@ -0,0 +1,8 @@ +Tests -use_value_profile=2 (alternative VP metric). +RUN: %cpp_compiler %S/ThreeBytes.cpp -o %t + +RUN:     %run %t -seed=1 -runs=30000 +RUN:     %run %t -seed=1 -runs=30000 -use_value_profile=1 +RUN: not %run %t -seed=1 -runs=1000000 -use_value_profile=2 2>&1 | FileCheck %s + +CHECK: Test unit written diff --git a/test/fuzzer/trace-malloc-2.test b/test/fuzzer/trace-malloc-2.test index 56f16d7860129..2b32b95ed3e6d 100644 --- a/test/fuzzer/trace-malloc-2.test +++ b/test/fuzzer/trace-malloc-2.test @@ -4,7 +4,7 @@ UNSUPPORTED: darwin  RUN: %cpp_compiler %S/TraceMallocTest.cpp -o %t-TraceMallocTest -RUN: %t-TraceMallocTest -seed=1 -trace_malloc=2 -runs=1000 2>&1 | FileCheck %s --check-prefix=TRACE2 +RUN: %run %t-TraceMallocTest -seed=1 -trace_malloc=2 -runs=1000 2>&1 | FileCheck %s --check-prefix=TRACE2  TRACE2-DAG: FREE[0]  TRACE2-DAG: MALLOC[0]  TRACE2-DAG: in LLVMFuzzerTestOneInput diff --git a/test/fuzzer/trace-malloc-threaded.test b/test/fuzzer/trace-malloc-threaded.test index 11f3f049155fe..8f972d61f5c63 100644 --- a/test/fuzzer/trace-malloc-threaded.test +++ b/test/fuzzer/trace-malloc-threaded.test @@ -1,10 +1,11 @@  // FIXME: This test infinite loops on darwin because it crashes  // printing a stack trace repeatedly -UNSUPPORTED: darwin +UNSUPPORTED: darwin, aarch64 -RUN: %cpp_compiler %S/TraceMallocThreadedTest.cpp -o %t-TraceMallocThreadedTest +RUN: %cpp_compiler %S/TraceMallocThreadedTest.cpp -o \ +RUN:   %t-TraceMallocThreadedTest -RUN: %t-TraceMallocThreadedTest -trace_malloc=2 -runs=1 2>&1 | FileCheck %s +RUN: %run %t-TraceMallocThreadedTest -trace_malloc=2 -runs=1 2>&1 | FileCheck %s  CHECK: {{MALLOC\[[0-9]+] +0x[0-9]+ 5639}}  CHECK-NEXT: {{ +\#0 +}}  CHECK-NEXT: {{ +\#1 +}} diff --git a/test/fuzzer/trace-malloc-unbalanced.test b/test/fuzzer/trace-malloc-unbalanced.test index 8be5fab0ca43f..193df01ddeff0 100644 --- a/test/fuzzer/trace-malloc-unbalanced.test +++ b/test/fuzzer/trace-malloc-unbalanced.test @@ -6,10 +6,10 @@ UNSUPPORTED: darwin  RUN: %cpp_compiler %S/TraceMallocTest.cpp -o %t-TraceMallocTest -RUN: %t-TraceMallocTest -seed=1 -trace_malloc=1 -runs=200 2>&1 | \ +RUN: %run %t-TraceMallocTest -seed=1 -trace_malloc=1 -runs=200 2>&1 | \  RUN:    %libfuzzer_src/scripts/unbalanced_allocs.py --skip=5 | FileCheck %s -RUN: %t-TraceMallocTest -seed=1 -trace_malloc=2 -runs=200 2>&1 | \ +RUN: %run %t-TraceMallocTest -seed=1 -trace_malloc=2 -runs=200 2>&1 | \  RUN:    %libfuzzer_src/scripts/unbalanced_allocs.py --skip=5 | FileCheck %s --check-prefixes=CHECK,CHECK2  CHECK: MallocFreeTracer: START diff --git a/test/fuzzer/trace-malloc.test b/test/fuzzer/trace-malloc.test index 979be99b7ac27..156d06a0c01ed 100644 --- a/test/fuzzer/trace-malloc.test +++ b/test/fuzzer/trace-malloc.test @@ -1,6 +1,6 @@  RUN: %cpp_compiler %S/TraceMallocTest.cpp -o %t-TraceMallocTest -RUN: %t-TraceMallocTest -seed=1 -trace_malloc=1 -runs=10000 2>&1 | FileCheck %s +RUN: %run %t-TraceMallocTest -seed=1 -trace_malloc=1 -runs=10000 2>&1 | FileCheck %s  CHECK-DAG: MallocFreeTracer: STOP 0 0 (same)  CHECK-DAG: MallocFreeTracer: STOP 0 1 (DIFFERENT)  CHECK-DAG: MallocFreeTracer: STOP 1 0 (DIFFERENT) diff --git a/test/fuzzer/trace-pc.test b/test/fuzzer/trace-pc.test index eaa0cb08afbed..30049331e360d 100644 --- a/test/fuzzer/trace-pc.test +++ b/test/fuzzer/trace-pc.test @@ -1,3 +1,3 @@ -RUN: %cpp_compiler %S/SimpleTest.cpp -fno-sanitize-coverage=edge,trace-cmp,indirect-calls,8bit-counters,trace-pc-guard -fsanitize-coverage=trace-pc -o %t-SimpleTest-TracePC +RUN: %cpp_compiler %S/SimpleTest.cpp -fsanitize-coverage=0 -fsanitize-coverage=trace-pc -o %t-SimpleTest-TracePC  CHECK: BINGO -RUN: not %t-SimpleTest-TracePC -runs=1000000 -seed=1 2>&1 | FileCheck %s +RUN: not %run %t-SimpleTest-TracePC -runs=1000000 -seed=1 2>&1 | FileCheck %s diff --git a/test/fuzzer/ulimit.test b/test/fuzzer/ulimit.test index 8772caa2d4c35..076866c509401 100644 --- a/test/fuzzer/ulimit.test +++ b/test/fuzzer/ulimit.test @@ -1,3 +1,3 @@  RUN: %cpp_compiler %S/SimpleTest.cpp -o %t-SimpleTest  RUN: ulimit -s 1000 -RUN: not %t-SimpleTest +RUN: not %run %t-SimpleTest diff --git a/test/fuzzer/value-profile-cmp.test b/test/fuzzer/value-profile-cmp.test index 64244297c64a0..b927422d10ff5 100644 --- a/test/fuzzer/value-profile-cmp.test +++ b/test/fuzzer/value-profile-cmp.test @@ -1,3 +1,3 @@  CHECK: BINGO  RUN: %cpp_compiler %S/SimpleCmpTest.cpp -o %t-SimpleCmpTest -RUN: not %t-SimpleCmpTest -seed=1 -use_cmp=0 -use_value_profile=1 -runs=100000000 2>&1 | FileCheck %s +RUN: not %run %t-SimpleCmpTest -seed=1 -use_cmp=0 -use_value_profile=1 -runs=100000000 2>&1 | FileCheck %s diff --git a/test/fuzzer/value-profile-cmp2.test b/test/fuzzer/value-profile-cmp2.test index a585c9317fab3..4bf119fcb3dfd 100644 --- a/test/fuzzer/value-profile-cmp2.test +++ b/test/fuzzer/value-profile-cmp2.test @@ -1,3 +1,3 @@  CHECK: BINGO  RUN: %cpp_compiler -fno-sanitize=address %S/SimpleHashTest.cpp -o %t-SimpleHashTest -RUN: not %t-SimpleHashTest -seed=1 -use_cmp=0 -use_value_profile=1 -runs=100000000 -max_len=64 2>&1 | FileCheck %s +RUN: not %run %t-SimpleHashTest -seed=1 -use_cmp=0 -use_value_profile=1 -runs=100000000 -max_len=64 2>&1 | FileCheck %s diff --git a/test/fuzzer/value-profile-cmp3.test b/test/fuzzer/value-profile-cmp3.test index d2284750b51ed..58ba18b9001e5 100644 --- a/test/fuzzer/value-profile-cmp3.test +++ b/test/fuzzer/value-profile-cmp3.test @@ -1,3 +1,3 @@  CHECK: BINGO  RUN: %cpp_compiler %S/AbsNegAndConstantTest.cpp -o %t-AbsNegAndConstantTest -RUN: not %t-AbsNegAndConstantTest -seed=1 -use_cmp=0 -use_value_profile=1 -runs=100000000 2>&1 | FileCheck %s +RUN: not %run %t-AbsNegAndConstantTest -seed=1 -use_cmp=0 -use_value_profile=1 -runs=100000000 2>&1 | FileCheck %s diff --git a/test/fuzzer/value-profile-cmp4.test b/test/fuzzer/value-profile-cmp4.test index bcbc67b1801fa..05bc3f435912d 100644 --- a/test/fuzzer/value-profile-cmp4.test +++ b/test/fuzzer/value-profile-cmp4.test @@ -1,3 +1,3 @@  CHECK: BINGO  RUN: %cpp_compiler %S/AbsNegAndConstant64Test.cpp -o %t-AbsNegAndConstant64Test -RUN: not %t-AbsNegAndConstant64Test -seed=1 -use_cmp=0 -use_value_profile=1 -runs=100000000 2>&1 | FileCheck %s +RUN: not %run %t-AbsNegAndConstant64Test -seed=1 -use_cmp=0 -use_value_profile=1 -runs=100000000 2>&1 | FileCheck %s diff --git a/test/fuzzer/value-profile-div.test b/test/fuzzer/value-profile-div.test index 8711a25466e57..59cc7c2f95526 100644 --- a/test/fuzzer/value-profile-div.test +++ b/test/fuzzer/value-profile-div.test @@ -1,4 +1,6 @@ +XFAIL: ios +UNSUPPORTED: aarch64  CHECK: AddressSanitizer: {{FPE|int-divide-by-zero}}  RUN: %cpp_compiler %S/DivTest.cpp -fsanitize-coverage=trace-div -o %t-DivTest -RUN: not %t-DivTest -seed=1 -use_value_profile=1 -runs=10000000 2>&1 | FileCheck %s +RUN: not %run %t-DivTest -seed=1 -use_value_profile=1 -runs=10000000 2>&1 | FileCheck %s diff --git a/test/fuzzer/value-profile-load.test b/test/fuzzer/value-profile-load.test index 3bf2a658a5b29..607b81cd527fe 100644 --- a/test/fuzzer/value-profile-load.test +++ b/test/fuzzer/value-profile-load.test @@ -1,3 +1,3 @@  CHECK: AddressSanitizer: global-buffer-overflow -RUN: %cpp_compiler %S/LoadTest.cpp -fsanitize-coverage=trace-pc-guard,indirect-calls,trace-gep,trace-div,trace-cmp -o %t-LoadTest -RUN: not %t-LoadTest -seed=2 -use_cmp=0 -use_value_profile=1 -runs=20000000 2>&1 | FileCheck %s +RUN: %cpp_compiler %S/LoadTest.cpp -fsanitize-coverage=trace-gep -o %t-LoadTest +RUN: not %run %t-LoadTest -seed=2 -use_cmp=0 -use_value_profile=1 -runs=20000000 2>&1 | FileCheck %s diff --git a/test/fuzzer/value-profile-mem.test b/test/fuzzer/value-profile-mem.test index 0b0c21d689ce0..57c844e92261b 100644 --- a/test/fuzzer/value-profile-mem.test +++ b/test/fuzzer/value-profile-mem.test @@ -1,3 +1,4 @@ +UNSUPPORTED: freebsd  CHECK: BINGO  RUN: %cpp_compiler %S/SingleMemcmpTest.cpp -o %t-SingleMemcmpTest -RUN: not %t-SingleMemcmpTest -seed=1  -use_cmp=0 -use_value_profile=1 -runs=10000000 2>&1 | FileCheck %s +RUN: not %run %t-SingleMemcmpTest -seed=1  -use_cmp=0 -use_value_profile=1 -runs=10000000 2>&1 | FileCheck %s diff --git a/test/fuzzer/value-profile-set.test b/test/fuzzer/value-profile-set.test index e2e3fb47f3ad0..e55f1e4a853a6 100644 --- a/test/fuzzer/value-profile-set.test +++ b/test/fuzzer/value-profile-set.test @@ -1,4 +1,4 @@  CHECK: BINGO  RUN: %cpp_compiler %S/FourIndependentBranchesTest.cpp -o %t-FourIndependentBranchesTest -RUN: not %t-FourIndependentBranchesTest -seed=1 -use_cmp=0 -use_value_profile=1 -runs=100000000 2>&1 | FileCheck %s +RUN: not %run %t-FourIndependentBranchesTest -seed=1 -use_cmp=0 -use_value_profile=1 -runs=100000000 2>&1 | FileCheck %s diff --git a/test/fuzzer/value-profile-strcmp.test b/test/fuzzer/value-profile-strcmp.test index f5c766a658f45..647121f228205 100644 --- a/test/fuzzer/value-profile-strcmp.test +++ b/test/fuzzer/value-profile-strcmp.test @@ -1,3 +1,4 @@ +UNSUPPORTED: freebsd  CHECK: BINGO  RUN: %cpp_compiler %S/SingleStrcmpTest.cpp -o %t-SingleStrcmpTest -RUN: not %t-SingleStrcmpTest -seed=1  -use_cmp=0 -use_value_profile=1 -runs=10000000 2>&1 | FileCheck %s +RUN: not %run %t-SingleStrcmpTest -seed=1  -use_cmp=0 -use_value_profile=1 -runs=10000000 2>&1 | FileCheck %s diff --git a/test/fuzzer/value-profile-strncmp.test b/test/fuzzer/value-profile-strncmp.test index 2dfe43c4abc5e..b60b97f86f3e3 100644 --- a/test/fuzzer/value-profile-strncmp.test +++ b/test/fuzzer/value-profile-strncmp.test @@ -1,3 +1,4 @@ +UNSUPPORTED: freebsd  CHECK: BINGO  RUN: %cpp_compiler %S/SingleStrncmpTest.cpp -o %t-SingleStrncmpTest -RUN: not %t-SingleStrncmpTest -seed=1 -use_cmp=0 -use_value_profile=1 -runs=100000000 2>&1 | FileCheck %s +RUN: not %run %t-SingleStrncmpTest -seed=1 -use_cmp=0 -use_value_profile=1 -runs=100000000 2>&1 | FileCheck %s diff --git a/test/fuzzer/value-profile-switch.test b/test/fuzzer/value-profile-switch.test index 7edb312a07b07..cc3d4944c0bf0 100644 --- a/test/fuzzer/value-profile-switch.test +++ b/test/fuzzer/value-profile-switch.test @@ -1,5 +1,6 @@ +XFAIL: ios  CHECK: BINGO  RUN: %cpp_compiler %S/SwitchTest.cpp -o %t-SwitchTest  RUN: %cpp_compiler %S/Switch2Test.cpp -o %t-Switch2Test -RUN: not %t-SwitchTest  -use_cmp=0 -use_value_profile=1 -runs=100000000 -seed=1 2>&1 | FileCheck %s -RUN: not %t-Switch2Test -use_cmp=0 -use_value_profile=1 -runs=100000000 -seed=1 2>&1 | FileCheck %s +RUN: not %run %t-SwitchTest  -use_cmp=0 -use_value_profile=1 -runs=100000000 -seed=1 2>&1 | FileCheck %s +RUN: not %run %t-Switch2Test -use_cmp=0 -use_value_profile=1 -runs=100000000 -seed=1 2>&1 | FileCheck %s diff --git a/test/hwasan/TestCases/Linux/aligned_alloc-alignment.cc b/test/hwasan/TestCases/Linux/aligned_alloc-alignment.cc new file mode 100644 index 0000000000000..a5dc7f661c7a8 --- /dev/null +++ b/test/hwasan/TestCases/Linux/aligned_alloc-alignment.cc @@ -0,0 +1,25 @@ +// RUN: %clangxx_hwasan -O0 %s -o %t +// RUN: %env_hwasan_opts=allocator_may_return_null=0 not %run %t 2>&1 | FileCheck %s +// RUN: %env_hwasan_opts=allocator_may_return_null=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-NULL + +// UNSUPPORTED: android + +// REQUIRES: stable-runtime + +#include <stdio.h> +#include <stdlib.h> + +extern void *aligned_alloc(size_t alignment, size_t size); + +int main() { +  void *p = aligned_alloc(17, 100); +  // CHECK: ERROR: HWAddressSanitizer: invalid alignment requested in aligned_alloc: 17 +  // CHECK: {{#0 0x.* in .*}}{{aligned_alloc|memalign}} +  // CHECK: {{#1 0x.* in main .*aligned_alloc-alignment.cc:}}[[@LINE-3]] +  // CHECK: SUMMARY: HWAddressSanitizer: invalid-aligned-alloc-alignment + +  printf("pointer after failed aligned_alloc: %zd\n", (size_t)p); +  // CHECK-NULL: pointer after failed aligned_alloc: 0 + +  return 0; +} diff --git a/test/hwasan/TestCases/Linux/lit.local.cfg b/test/hwasan/TestCases/Linux/lit.local.cfg new file mode 100644 index 0000000000000..57271b8078a49 --- /dev/null +++ b/test/hwasan/TestCases/Linux/lit.local.cfg @@ -0,0 +1,9 @@ +def getRoot(config): +  if not config.parent: +    return config +  return getRoot(config.parent) + +root = getRoot(config) + +if root.host_os not in ['Linux']: +  config.unsupported = True diff --git a/test/hwasan/TestCases/Linux/pvalloc-overflow.cc b/test/hwasan/TestCases/Linux/pvalloc-overflow.cc new file mode 100644 index 0000000000000..a4897c1279e7b --- /dev/null +++ b/test/hwasan/TestCases/Linux/pvalloc-overflow.cc @@ -0,0 +1,46 @@ +// RUN: %clangxx_hwasan -O0 %s -o %t +// RUN: %env_hwasan_opts=allocator_may_return_null=0 not %run %t m1 2>&1 | FileCheck %s +// RUN: %env_hwasan_opts=allocator_may_return_null=1     %run %t m1 2>&1 | FileCheck %s --check-prefix=CHECK-NULL +// RUN: %env_hwasan_opts=allocator_may_return_null=0 not %run %t psm1 2>&1 | FileCheck %s +// RUN: %env_hwasan_opts=allocator_may_return_null=1     %run %t psm1 2>&1 | FileCheck %s --check-prefix=CHECK-NULL + +// UNSUPPORTED: android + +// REQUIRES: stable-runtime + +// Checks that pvalloc overflows are caught. If the allocator is allowed to +// return null, the errno should be set to ENOMEM. + +#include <assert.h> +#include <errno.h> +#include <malloc.h> +#include <stdint.h> +#include <string.h> +#include <unistd.h> + +int main(int argc, char *argv[]) { +  assert(argc == 2); +  const char *action = argv[1]; + +  const size_t page_size = sysconf(_SC_PAGESIZE); + +  void *p = nullptr; +  if (!strcmp(action, "m1")) { +    p = pvalloc((uintptr_t)-1); +  } else if (!strcmp(action, "psm1")) { +    p = pvalloc((uintptr_t)-(page_size - 1)); +  } else { +    assert(0); +  } + +  fprintf(stderr, "errno: %d\n", errno); + +  return p != nullptr; +} + +// CHECK: {{ERROR: HWAddressSanitizer: pvalloc parameters overflow: size .* rounded up to system page size .* cannot be represented in type size_t}} +// CHECK: {{#0 0x.* in .*pvalloc}} +// CHECK: {{#1 0x.* in main .*pvalloc-overflow.cc:}} +// CHECK: SUMMARY: HWAddressSanitizer: pvalloc-overflow + +// CHECK-NULL: errno: 12 diff --git a/test/hwasan/TestCases/Posix/lit.local.cfg b/test/hwasan/TestCases/Posix/lit.local.cfg new file mode 100644 index 0000000000000..60a9460820a62 --- /dev/null +++ b/test/hwasan/TestCases/Posix/lit.local.cfg @@ -0,0 +1,9 @@ +def getRoot(config): +  if not config.parent: +    return config +  return getRoot(config.parent) + +root = getRoot(config) + +if root.host_os in ['Windows']: +  config.unsupported = True diff --git a/test/hwasan/TestCases/Posix/posix_memalign-alignment.cc b/test/hwasan/TestCases/Posix/posix_memalign-alignment.cc new file mode 100644 index 0000000000000..1ecc39c42f23f --- /dev/null +++ b/test/hwasan/TestCases/Posix/posix_memalign-alignment.cc @@ -0,0 +1,22 @@ +// RUN: %clangxx_hwasan -O0 %s -o %t +// RUN: %env_hwasan_opts=allocator_may_return_null=0 not %run %t 2>&1 | FileCheck %s +// RUN: %env_hwasan_opts=allocator_may_return_null=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-NULL + +// REQUIRES: stable-runtime + +#include <stdio.h> +#include <stdlib.h> + +int main() { +  void *p = reinterpret_cast<void*>(42); +  int res = posix_memalign(&p, 17, 100); +  // CHECK: ERROR: HWAddressSanitizer: invalid alignment requested in posix_memalign: 17 +  // CHECK: {{#0 0x.* in .*posix_memalign}} +  // CHECK: {{#1 0x.* in main .*posix_memalign-alignment.cc:}}[[@LINE-3]] +  // CHECK: SUMMARY: HWAddressSanitizer: invalid-posix-memalign-alignment + +  printf("pointer after failed posix_memalign: %zd\n", (size_t)p); +  // CHECK-NULL: pointer after failed posix_memalign: 42 + +  return 0; +} diff --git a/test/msan/allocator_returns_null.cc b/test/hwasan/TestCases/allocator_returns_null.cc index 583b5b4f76be8..8d2ef38d4ab79 100644 --- a/test/msan/allocator_returns_null.cc +++ b/test/hwasan/TestCases/allocator_returns_null.cc @@ -1,42 +1,44 @@ -// Test the behavior of malloc/calloc/realloc/new when the allocation size is -// more than MSan allocator's max allowed one. -// By default (allocator_may_return_null=0) the process should crash. -// With allocator_may_return_null=1 the allocator should return 0, except the -// operator new(), which should crash anyway (operator new(std::nothrow) should -// return nullptr, indeed). +// Test the behavior of malloc/calloc/realloc/new when the allocation size +// exceeds the HWASan allocator's max allowed one. +// By default (allocator_may_return_null=0) the process should crash. With +// allocator_may_return_null=1 the allocator should return 0 and set errno to +// the appropriate error code.  // -// RUN: %clangxx_msan -O0 %s -o %t +// RUN: %clangxx_hwasan -O0 %s -o %t  // RUN: not %run %t malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mCRASH -// RUN: MSAN_OPTIONS=allocator_may_return_null=0 not %run %t malloc 2>&1 \ +// RUN: %env_hwasan_opts=allocator_may_return_null=0 not %run %t malloc 2>&1 \  // RUN:   | FileCheck %s --check-prefix=CHECK-mCRASH -// RUN: MSAN_OPTIONS=allocator_may_return_null=1     %run %t malloc 2>&1 \ +// RUN: %env_hwasan_opts=allocator_may_return_null=1     %run %t malloc 2>&1 \  // RUN:   | FileCheck %s --check-prefix=CHECK-mNULL -// RUN: MSAN_OPTIONS=allocator_may_return_null=0 not %run %t calloc 2>&1 \ +// RUN: %env_hwasan_opts=allocator_may_return_null=0 not %run %t calloc 2>&1 \  // RUN:   | FileCheck %s --check-prefix=CHECK-cCRASH -// RUN: MSAN_OPTIONS=allocator_may_return_null=1     %run %t calloc 2>&1 \ +// RUN: %env_hwasan_opts=allocator_may_return_null=1     %run %t calloc 2>&1 \  // RUN:   | FileCheck %s --check-prefix=CHECK-cNULL -// RUN: MSAN_OPTIONS=allocator_may_return_null=0 not %run %t calloc-overflow 2>&1 \ +// RUN: %env_hwasan_opts=allocator_may_return_null=0 not %run %t calloc-overflow 2>&1 \  // RUN:   | FileCheck %s --check-prefix=CHECK-coCRASH -// RUN: MSAN_OPTIONS=allocator_may_return_null=1     %run %t calloc-overflow 2>&1 \ +// RUN: %env_hwasan_opts=allocator_may_return_null=1     %run %t calloc-overflow 2>&1 \  // RUN:   | FileCheck %s --check-prefix=CHECK-coNULL -// RUN: MSAN_OPTIONS=allocator_may_return_null=0 not %run %t realloc 2>&1 \ +// RUN: %env_hwasan_opts=allocator_may_return_null=0 not %run %t realloc 2>&1 \  // RUN:   | FileCheck %s --check-prefix=CHECK-rCRASH -// RUN: MSAN_OPTIONS=allocator_may_return_null=1     %run %t realloc 2>&1 \ +// RUN: %env_hwasan_opts=allocator_may_return_null=1     %run %t realloc 2>&1 \  // RUN:   | FileCheck %s --check-prefix=CHECK-rNULL -// RUN: MSAN_OPTIONS=allocator_may_return_null=0 not %run %t realloc-after-malloc 2>&1 \ +// RUN: %env_hwasan_opts=allocator_may_return_null=0 not %run %t realloc-after-malloc 2>&1 \  // RUN:   | FileCheck %s --check-prefix=CHECK-mrCRASH -// RUN: MSAN_OPTIONS=allocator_may_return_null=1     %run %t realloc-after-malloc 2>&1 \ +// RUN: %env_hwasan_opts=allocator_may_return_null=1     %run %t realloc-after-malloc 2>&1 \  // RUN:   | FileCheck %s --check-prefix=CHECK-mrNULL -// RUN: MSAN_OPTIONS=allocator_may_return_null=0 not %run %t new 2>&1 \ +// RUN: %env_hwasan_opts=allocator_may_return_null=0 not %run %t new 2>&1 \  // RUN:   | FileCheck %s --check-prefix=CHECK-nCRASH -// RUN: MSAN_OPTIONS=allocator_may_return_null=1 not %run %t new 2>&1 \ -// RUN:   | FileCheck %s --check-prefix=CHECK-nCRASH -// RUN: MSAN_OPTIONS=allocator_may_return_null=0 not %run %t new-nothrow 2>&1 \ +// RUN: %env_hwasan_opts=allocator_may_return_null=1 not %run %t new 2>&1 \ +// RUN:   | FileCheck %s --check-prefix=CHECK-nCRASH-OOM +// RUN: %env_hwasan_opts=allocator_may_return_null=0 not %run %t new-nothrow 2>&1 \  // RUN:   | FileCheck %s --check-prefix=CHECK-nnCRASH -// RUN: MSAN_OPTIONS=allocator_may_return_null=1     %run %t new-nothrow 2>&1 \ +// RUN: %env_hwasan_opts=allocator_may_return_null=1     %run %t new-nothrow 2>&1 \  // RUN:   | FileCheck %s --check-prefix=CHECK-nnNULL -// UNSUPPORTED: win32 +// REQUIRES: stable-runtime + +// TODO(alekseyshl): Fix it. +// UNSUPPORTED: android  #include <assert.h>  #include <errno.h> @@ -47,21 +49,13 @@  #include <new>  int main(int argc, char **argv) { -  // Disable stderr buffering. Needed on Windows. -  setvbuf(stderr, NULL, _IONBF, 0); -    assert(argc == 2);    const char *action = argv[1];    fprintf(stderr, "%s:\n", action); -  static const size_t kMaxAllowedMallocSizePlusOne = -#if __LP64__ || defined(_WIN64) -      (8UL << 30) + 1; -#else -      (2UL << 30) + 1; -#endif +  static const size_t kMaxAllowedMallocSizePlusOne = (2UL << 30) + 1; -  void *x = 0; +  void *x = nullptr;    if (!strcmp(action, "malloc")) {      x = malloc(kMaxAllowedMallocSizePlusOne);    } else if (!strcmp(action, "calloc")) { @@ -89,43 +83,36 @@ int main(int argc, char **argv) {    fprintf(stderr, "errno: %d\n", errno); -  // The NULL pointer is printed differently on different systems, while (long)0 -  // is always the same. -  fprintf(stderr, "x: %lx\n", (long)x);    free(x); -  return x != 0; +  return x != nullptr;  }  // CHECK-mCRASH: malloc: -// CHECK-mCRASH: MemorySanitizer's allocator is terminating the process +// CHECK-mCRASH: SUMMARY: HWAddressSanitizer: allocation-size-too-big  // CHECK-cCRASH: calloc: -// CHECK-cCRASH: MemorySanitizer's allocator is terminating the process +// CHECK-cCRASH: SUMMARY: HWAddressSanitizer: allocation-size-too-big  // CHECK-coCRASH: calloc-overflow: -// CHECK-coCRASH: MemorySanitizer's allocator is terminating the process +// CHECK-coCRASH: SUMMARY: HWAddressSanitizer: calloc-overflow  // CHECK-rCRASH: realloc: -// CHECK-rCRASH: MemorySanitizer's allocator is terminating the process +// CHECK-rCRASH: SUMMARY: HWAddressSanitizer: allocation-size-too-big  // CHECK-mrCRASH: realloc-after-malloc: -// CHECK-mrCRASH: MemorySanitizer's allocator is terminating the process +// CHECK-mrCRASH: SUMMARY: HWAddressSanitizer: allocation-size-too-big  // CHECK-nCRASH: new: -// CHECK-nCRASH: MemorySanitizer's allocator is terminating the process +// CHECK-nCRASH: SUMMARY: HWAddressSanitizer: allocation-size-too-big +// CHECK-nCRASH-OOM: new: +// CHECK-nCRASH-OOM: SUMMARY: HWAddressSanitizer: out-of-memory  // CHECK-nnCRASH: new-nothrow: -// CHECK-nnCRASH: MemorySanitizer's allocator is terminating the process +// CHECK-nnCRASH: SUMMARY: HWAddressSanitizer: allocation-size-too-big  // CHECK-mNULL: malloc:  // CHECK-mNULL: errno: 12 -// CHECK-mNULL: x: 0  // CHECK-cNULL: calloc:  // CHECK-cNULL: errno: 12 -// CHECK-cNULL: x: 0  // CHECK-coNULL: calloc-overflow:  // CHECK-coNULL: errno: 12 -// CHECK-coNULL: x: 0  // CHECK-rNULL: realloc:  // CHECK-rNULL: errno: 12 -// CHECK-rNULL: x: 0  // CHECK-mrNULL: realloc-after-malloc:  // CHECK-mrNULL: errno: 12 -// CHECK-mrNULL: x: 0  // CHECK-nnNULL: new-nothrow: -// CHECK-nnNULL: x: 0 diff --git a/test/hwasan/TestCases/check-interface.cc b/test/hwasan/TestCases/check-interface.cc new file mode 100644 index 0000000000000..7ad9114803592 --- /dev/null +++ b/test/hwasan/TestCases/check-interface.cc @@ -0,0 +1,22 @@ +// RUN: %clangxx_hwasan -mllvm -hwasan-instrument-with-calls=1 -O0 %s -o %t +// RUN: %clangxx_hwasan -mllvm -hwasan-instrument-with-calls=1 -O0 %s -o %t -fsanitize-recover=hwaddress + +// REQUIRES: stable-runtime + +// Utilizes all flavors of __hwasan_load/store interface functions to verify +// that the instrumentation and the interface provided by HWASan do match. +// In case of a discrepancy, this test fails to link. + +#include <sanitizer/hwasan_interface.h> + +#define F(T) void f_##T(T *a, T *b) { *a = *b; } + +F(uint8_t) +F(uint16_t) +F(uint32_t) +F(uint64_t) + +typedef unsigned V32 __attribute__((__vector_size__(32))); +F(V32) + +int main() {} diff --git a/test/hwasan/TestCases/stack-oob.cc b/test/hwasan/TestCases/stack-oob.cc new file mode 100644 index 0000000000000..60b9a6295005c --- /dev/null +++ b/test/hwasan/TestCases/stack-oob.cc @@ -0,0 +1,25 @@ +// RUN: %clangxx_hwasan -DSIZE=16 -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_hwasan -DSIZE=64 -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_hwasan -DSIZE=0x1000 -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s + +// REQUIRES: stable-runtime + +#include <stdlib.h> +#include <sanitizer/hwasan_interface.h> + +__attribute__((noinline)) +int f() { +  char z[SIZE]; +  char *volatile p = z; +  return p[SIZE]; +} + +int main() { +  return f(); +  // CHECK: READ of size 1 at +  // CHECK: #0 {{.*}} in f{{.*}}stack-oob.cc:14 + +  // CHECK: HWAddressSanitizer can not describe address in more detail. + +  // CHECK: SUMMARY: HWAddressSanitizer: tag-mismatch {{.*}} in f +} diff --git a/test/hwasan/TestCases/stack-uar.cc b/test/hwasan/TestCases/stack-uar.cc new file mode 100644 index 0000000000000..e99dcceed5338 --- /dev/null +++ b/test/hwasan/TestCases/stack-uar.cc @@ -0,0 +1,23 @@ +// RUN: %clangxx_hwasan -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s + +// REQUIRES: stable-runtime + +#include <stdlib.h> +#include <sanitizer/hwasan_interface.h> + +__attribute__((noinline)) +char *f() { +  char z[0x1000]; +  char *volatile p = z; +  return p; +} + +int main() { +  return *f(); +  // CHECK: READ of size 1 at +  // CHECK: #0 {{.*}} in main{{.*}}stack-uar.cc:16 + +  // CHECK: HWAddressSanitizer can not describe address in more detail. + +  // CHECK: SUMMARY: HWAddressSanitizer: tag-mismatch {{.*}} in main +} diff --git a/test/hwasan/TestCases/use-after-free.c b/test/hwasan/TestCases/use-after-free.c new file mode 100644 index 0000000000000..b9f6060112c14 --- /dev/null +++ b/test/hwasan/TestCases/use-after-free.c @@ -0,0 +1,39 @@ +// RUN: %clang_hwasan -O0 -DLOAD %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefixes=CHECK,LOAD +// RUN: %clang_hwasan -O1 -DLOAD %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefixes=CHECK,LOAD +// RUN: %clang_hwasan -O2 -DLOAD %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefixes=CHECK,LOAD +// RUN: %clang_hwasan -O3 -DLOAD %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefixes=CHECK,LOAD + +// RUN: %clang_hwasan -O0 -DSTORE %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefixes=CHECK,STORE + +// REQUIRES: stable-runtime + +#include <stdlib.h> +#include <sanitizer/hwasan_interface.h> + +int main() { +  __hwasan_enable_allocator_tagging(); +  char * volatile x = (char*)malloc(10); +  free(x); +  __hwasan_disable_allocator_tagging(); +#ifdef STORE +  x[5] = 42; +#endif +#ifdef LOAD +  return x[5]; +#endif +  // LOAD: READ of size 1 at +  // LOAD: #0 {{.*}} in main {{.*}}use-after-free.c:22 + +  // STORE: WRITE of size 1 at +  // STORE: #0 {{.*}} in main {{.*}}use-after-free.c:19 + +  // CHECK: freed here: +  // CHECK: #0 {{.*}} in {{.*}}free{{.*}} {{.*}}hwasan_interceptors.cc +  // CHECK: #1 {{.*}} in main {{.*}}use-after-free.c:16 + +  // CHECK: previously allocated here: +  // CHECK: #0 {{.*}} in {{.*}}malloc{{.*}} {{.*}}hwasan_interceptors.cc +  // CHECK: #1 {{.*}} in main {{.*}}use-after-free.c:15 + +  // CHECK: SUMMARY: HWAddressSanitizer: tag-mismatch {{.*}} in main +} diff --git a/test/hwasan/TestCases/use-after-free.cc b/test/hwasan/TestCases/use-after-free.cc deleted file mode 100644 index 37637898d7a1a..0000000000000 --- a/test/hwasan/TestCases/use-after-free.cc +++ /dev/null @@ -1,39 +0,0 @@ -// RUN: %clangxx_hwasan -O0 -DLOAD %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefixes=CHECK,LOAD -// RUN: %clangxx_hwasan -O1 -DLOAD %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefixes=CHECK,LOAD -// RUN: %clangxx_hwasan -O2 -DLOAD %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefixes=CHECK,LOAD -// RUN: %clangxx_hwasan -O3 -DLOAD %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefixes=CHECK,LOAD - -// RUN: %clangxx_hwasan -O0 -DSTORE %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefixes=CHECK,STORE - -// REQUIRES: stable-runtime - -#include <stdlib.h> -#include <sanitizer/hwasan_interface.h> - -int main() { -  __hwasan_enable_allocator_tagging(); -  char * volatile x = (char*)malloc(10); -  free(x); -  __hwasan_disable_allocator_tagging(); -#ifdef STORE -  x[5] = 42; -#endif -#ifdef LOAD -  return x[5]; -#endif -  // LOAD: READ of size 1 at -  // LOAD: #0 {{.*}} in main {{.*}}use-after-free.cc:22 - -  // STORE: WRITE of size 1 at -  // STORE: #0 {{.*}} in main {{.*}}use-after-free.cc:19 - -  // CHECK: freed here: -  // CHECK: #0 {{.*}} in free {{.*}}hwasan_interceptors.cc -  // CHECK: #1 {{.*}} in main {{.*}}use-after-free.cc:16 - -  // CHECK: previously allocated here: -  // CHECK: #0 {{.*}} in __interceptor_malloc {{.*}}hwasan_interceptors.cc -  // CHECK: #1 {{.*}} in main {{.*}}use-after-free.cc:15 - -  // CHECK: SUMMARY: HWAddressSanitizer: tag-mismatch {{.*}} in main -} diff --git a/test/hwasan/lit.cfg b/test/hwasan/lit.cfg index 4f099af5b7fce..3ebba51d05e45 100644 --- a/test/hwasan/lit.cfg +++ b/test/hwasan/lit.cfg @@ -9,7 +9,7 @@ config.name = 'HWAddressSanitizer' + getattr(config, 'name_suffix', 'default')  config.test_source_root = os.path.dirname(__file__)  # Setup default compiler flags used with -fsanitize=memory option. -clang_hwasan_cflags = ["-fsanitize=hwaddress", config.target_cflags] + config.debug_info_flags +clang_hwasan_cflags = ["-fsanitize=hwaddress", "-mllvm", "-hwasan-generate-tags-with-calls", config.target_cflags] + config.debug_info_flags  clang_hwasan_cxxflags = config.cxx_mode_flags + clang_hwasan_cflags  def build_invocation(compile_flags): @@ -18,7 +18,7 @@ def build_invocation(compile_flags):  config.substitutions.append( ("%clang_hwasan ", build_invocation(clang_hwasan_cflags)) )  config.substitutions.append( ("%clangxx_hwasan ", build_invocation(clang_hwasan_cxxflags)) ) -default_hwasan_opts_str = ':'.join(['disable_allocator_tagging=1'] + config.default_sanitizer_opts) +default_hwasan_opts_str = ':'.join(['disable_allocator_tagging=1', 'random_tags=0'] + config.default_sanitizer_opts)  if default_hwasan_opts_str:    config.environment['HWASAN_OPTIONS'] = default_hwasan_opts_str    default_hwasan_opts_str += ':' diff --git a/test/lit.common.cfg b/test/lit.common.cfg index 0840f65a71615..5274b49c654fd 100644 --- a/test/lit.common.cfg +++ b/test/lit.common.cfg @@ -7,6 +7,7 @@ import os  import platform  import re  import subprocess +import json  import lit.formats  import lit.util @@ -37,7 +38,11 @@ if compiler_id == "Clang":    # reports and stack traces even with minimal debug info.    config.debug_info_flags = ["-gline-tables-only"]    if platform.system() == 'Windows': +    # On Windows, use CodeView with column info instead of DWARF. Both VS and +    # windbg do not behave well when column info is enabled, but users have +    # requested it because it makes ASan reports more precise.      config.debug_info_flags.append("-gcodeview") +    config.debug_info_flags.append("-gcolumn-info")  elif compiler_id == 'GNU':    config.cxx_mode_flags = ["-x c++"]    config.debug_info_flags = ["-g"] @@ -86,8 +91,10 @@ config.environment['PATH'] = path  if platform.system() == 'Windows' and '-win' in config.target_triple:    config.environment['LIB'] = os.environ['LIB'] +config.available_features.add(config.host_os.lower()) +  if re.match(r'^x86_64.*-linux', config.target_triple): -      config.available_features.add("x86_64-linux") +  config.available_features.add("x86_64-linux")  # Use ugly construction to explicitly prohibit "clang", "clang++" etc.  # in RUN lines. @@ -100,17 +107,50 @@ if config.emulator:    config.substitutions.append( ('%run', config.emulator) )    config.substitutions.append( ('%env ', "env ") )    config.compile_wrapper = "" -elif config.ios: +elif config.host_os == 'Darwin' and config.apple_platform != "osx": +  # Darwin tests can be targetting macOS, a device or a simulator. All devices +  # are declared as "ios", even for iOS derivatives (tvOS, watchOS). Similarly, +  # all simulators are "iossim". See the table below. +  # +  # ========================================================================= +  # Target             | Feature set +  # ========================================================================= +  # macOS              | darwin +  # iOS device         | darwin, ios +  # iOS simulator      | darwin, ios, iossim +  # tvOS device        | darwin, ios, tvos +  # tvOS simulator     | darwin, ios, iossim, tvos, tvossim +  # watchOS device     | darwin, ios, watchos +  # watchOS simulator  | darwin, ios, iossim, watchos, watchossim +  # ========================================================================= + +  ios_or_iossim = "iossim" if config.apple_platform.endswith("sim") else "ios" +    config.available_features.add('ios') -  device_id_env = "SANITIZER_IOSSIM_TEST_DEVICE_IDENTIFIER" if config.iossim else "SANITIZER_IOS_TEST_DEVICE_IDENTIFIER" -  if device_id_env in os.environ: config.environment[device_id_env] = os.environ[device_id_env] +  if ios_or_iossim == "iossim": +    config.available_features.add('iossim') +  if config.apple_platform != "ios" and config.apple_platform != "iossim": +    config.available_features.add(config.apple_platform) +    ios_commands_dir = os.path.join(config.compiler_rt_src_root, "test", "sanitizer_common", "ios_commands") -  run_wrapper = os.path.join(ios_commands_dir, "iossim_run.py" if config.iossim else "ios_run.py") + +  device_id_env = "SANITIZER_" + ios_or_iossim.upper() + "_TEST_DEVICE_IDENTIFIER" +  run_wrapper = os.path.join(ios_commands_dir, ios_or_iossim + "_run.py") +  env_wrapper = os.path.join(ios_commands_dir, ios_or_iossim + "_env.py") +  compile_wrapper = os.path.join(ios_commands_dir, ios_or_iossim + "_compile.py") +  prepare_script = os.path.join(ios_commands_dir, ios_or_iossim + "_prepare.py") + +  if device_id_env in os.environ: +    config.environment[device_id_env] = os.environ[device_id_env]    config.substitutions.append(('%run', run_wrapper)) -  env_wrapper = os.path.join(ios_commands_dir, "iossim_env.py" if config.iossim else "ios_env.py")    config.substitutions.append(('%env ', env_wrapper + " ")) -  compile_wrapper = os.path.join(ios_commands_dir, "iossim_compile.py" if config.iossim else "ios_compile.py")    config.compile_wrapper = compile_wrapper + +  prepare_output = subprocess.check_output([prepare_script, config.apple_platform, config.clang]).strip() +  if len(prepare_output) > 0: print(prepare_output) +  prepare_output_json = prepare_output.split("\n")[-1] +  prepare_output = json.loads(prepare_output_json) +  config.environment.update(prepare_output["env"])  elif config.android:    config.available_features.add('android')    compile_wrapper = os.path.join(config.compiler_rt_src_root, "test", "sanitizer_common", "android_commands", "android_compile.py") + " " @@ -197,8 +237,19 @@ if config.host_os == 'Darwin':      pass    config.substitutions.append( ("%macos_min_target_10_11", "-mmacosx-version-min=10.11") ) + +  isIOS = config.apple_platform != "osx" +  # rdar://problem/22207160 +  config.substitutions.append( ("%darwin_min_target_with_full_runtime_arc_support", +      "-miphoneos-version-min=9.0" if isIOS else "-mmacosx-version-min=10.11") ) + +  # 32-bit iOS simulator is deprecated and removed in latest Xcode. +  if config.apple_platform == "iossim": +    if config.target_arch == "i386": +      config.unsupported = True  else:    config.substitutions.append( ("%macos_min_target_10_11", "") ) +  config.substitutions.append( ("%darwin_min_target_with_full_runtime_arc_support", "") )  if config.android:    adb = os.environ.get('ADB', 'adb') @@ -265,6 +316,8 @@ if config.lto_supported:      config.lto_flags += ["-flto=thin"]    else:      config.lto_flags += ["-flto"] +  if config.use_newpm: +    config.lto_flags += ["-fexperimental-new-pass-manager"]  # Ask llvm-config about assertion mode.  try: @@ -291,20 +344,43 @@ if platform.system() == 'Windows':  if platform.system() == 'Darwin':    lit_config.parallelism_groups["darwin-64bit-sanitizer"] = 3 -if config.host_os == 'Darwin': -  config.substitutions.append( ("%ld_flags_rpath_exe", '-Wl,-rpath,@executable_path/ %dynamiclib') ) -  config.substitutions.append( ("%ld_flags_rpath_so", '-install_name @rpath/`basename %dynamiclib`') ) -elif config.host_os == 'FreeBSD': -  config.substitutions.append( ("%ld_flags_rpath_exe", "-Wl,-z,origin -Wl,-rpath,\$ORIGIN -L%T -l%xdynamiclib_namespec") ) -  config.substitutions.append( ("%ld_flags_rpath_so", '') ) -elif config.host_os == 'Linux': -  config.substitutions.append( ("%ld_flags_rpath_exe", "-Wl,-rpath,\$ORIGIN -L%T -l%xdynamiclib_namespec") ) -  config.substitutions.append( ("%ld_flags_rpath_so", '') ) - -# Must be defined after the substitutions that use %dynamiclib. -config.substitutions.append( ("%dynamiclib", '%T/%xdynamiclib_filename') ) -config.substitutions.append( ("%xdynamiclib_filename", 'lib%xdynamiclib_namespec.so') ) -config.substitutions.append( ("%xdynamiclib_namespec", '%basename_t.dynamic') ) +# The current implementation of the tools in sanitizer_common/ios_comamnds +# do not support parallel execution so force sequential execution of the +# tests on iOS devices. +if config.host_os == 'Darwin' and config.apple_platform != "osx" and not config.apple_platform.endswith("sim"): +  lit_config.warning("iOS device test cases being run sequentially") +  lit_config.parallelism_groups["darwin-ios-device-sanitizer"] = 1 + +# Multiple substitutions are necessary to support multiple shared objects used +# at once. +# Note that substitutions with numbers have to be defined first to avoid +# being subsumed by substitutions with smaller postfix. +for postfix in ["2", "1", ""]: +  if config.host_os == 'Darwin': +    config.substitutions.append( ("%ld_flags_rpath_exe" + postfix, '-Wl,-rpath,@executable_path/ %dynamiclib' + postfix) ) +    config.substitutions.append( ("%ld_flags_rpath_so" + postfix, '-install_name @rpath/`basename %dynamiclib{}`'.format(postfix)) ) +  elif config.host_os in ('FreeBSD', 'NetBSD', 'OpenBSD'): +    config.substitutions.append( ("%ld_flags_rpath_exe" + postfix, "-Wl,-z,origin -Wl,-rpath,\$ORIGIN -L%T -l%xdynamiclib_namespec" + postfix) ) +    config.substitutions.append( ("%ld_flags_rpath_so" + postfix, '') ) +  elif config.host_os == 'Linux': +    config.substitutions.append( ("%ld_flags_rpath_exe" + postfix, "-Wl,-rpath,\$ORIGIN -L%T -l%xdynamiclib_namespec" + postfix) ) +    config.substitutions.append( ("%ld_flags_rpath_so" + postfix, '') ) +  elif config.host_os == 'SunOS': +    config.substitutions.append( ("%ld_flags_rpath_exe" + postfix, "-Wl,-R\$ORIGIN -L%T -l%xdynamiclib_namespec" + postfix) ) +    config.substitutions.append( ("%ld_flags_rpath_so" + postfix, '') ) + +  # Must be defined after the substitutions that use %dynamiclib. +  config.substitutions.append( ("%dynamiclib" + postfix, '%T/%xdynamiclib_filename' + postfix) ) +  config.substitutions.append( ("%xdynamiclib_filename" + postfix, 'lib%xdynamiclib_namespec{}.so'.format(postfix)) ) +  config.substitutions.append( ("%xdynamiclib_namespec", '%basename_t.dynamic') ) + +# Provide a substituion that can be used to tell Clang to use a static libstdc++. +# The substitution expands to nothing on non Linux platforms. +# FIXME: This should check the target OS, not the host OS. +if config.host_os == 'Linux': +  config.substitutions.append( ("%linux_static_libstdcplusplus", "-stdlib=libstdc++ -static-libstdc++") ) +else: +  config.substitutions.append( ("%linux_static_libstdcplusplus", "") )  config.default_sanitizer_opts = []  if config.host_os == 'Darwin': diff --git a/test/lit.common.configured.in b/test/lit.common.configured.in index 32a88200bf2db..63d55bfdea812 100644 --- a/test/lit.common.configured.in +++ b/test/lit.common.configured.in @@ -16,6 +16,7 @@ set_default("llvm_src_root", "@LLVM_MAIN_SRC_DIR@")  set_default("llvm_obj_root", "@LLVM_BINARY_DIR@")  set_default("compiler_rt_src_root", "@COMPILER_RT_SOURCE_DIR@")  set_default("compiler_rt_obj_root", "@COMPILER_RT_BINARY_DIR@") +set_default("enable_per_target_runtime_dir", @LLVM_ENABLE_PER_TARGET_RUNTIME_DIR_PYBOOL@)  set_default("llvm_tools_dir", "@LLVM_TOOLS_DIR@")  set_default("llvm_shlib_dir", "@LLVM_LIBRARY_OUTPUT_INTDIR@")  set_default("gold_executable", "@GOLD_EXECUTABLE@") @@ -26,17 +27,22 @@ set_default("compiler_rt_debug", @COMPILER_RT_DEBUG_PYBOOL@)  set_default("compiler_rt_libdir", "@COMPILER_RT_RESOLVED_LIBRARY_OUTPUT_DIR@")  set_default("emulator", "@COMPILER_RT_EMULATOR@")  set_default("asan_shadow_scale", "@COMPILER_RT_ASAN_SHADOW_SCALE@") -set_default("ios", False) -set_default("iossim", False) +set_default("apple_platform", "osx")  set_default("sanitizer_can_use_cxxabi", @SANITIZER_CAN_USE_CXXABI_PYBOOL@)  set_default("has_lld", @COMPILER_RT_HAS_LLD_PYBOOL@)  set_default("can_symbolize", @CAN_SYMBOLIZE@)  set_default("use_lld", False)  set_default("use_thinlto", False)  set_default("use_lto", config.use_thinlto) +set_default("use_newpm", False)  set_default("android", @ANDROID_PYBOOL@)  config.available_features.add('target-is-%s' % config.target_arch) +if config.enable_per_target_runtime_dir: +  set_default("target_suffix", "") +else: +  set_default("target_suffix", "-%s" % config.target_arch) +  # LLVM tools dir can be passed in lit parameters, so try to  # apply substitution.  try: diff --git a/test/lsan/TestCases/Linux/fork_with_threads.cc b/test/lsan/TestCases/Linux/fork_with_threads.cc new file mode 100644 index 0000000000000..221c5d249d772 --- /dev/null +++ b/test/lsan/TestCases/Linux/fork_with_threads.cc @@ -0,0 +1,35 @@ +// Test forked process does not run lsan. +// RUN: %clangxx_lsan %s -o %t && %run %t 2>&1 | FileCheck %s + +#include <pthread.h> +#include <stdlib.h> +#include <sys/wait.h> +#include <unistd.h> + +static pthread_barrier_t barrier; + +// CHECK-NOT: SUMMARY: {{(Leak|Address)}}Sanitizer: +static void *thread_func(void *arg) { +  void *buffer = malloc(1337); +  pthread_barrier_wait(&barrier); +  for (;;) +    pthread_yield(); +  return 0; +} + +int main() { +  pthread_barrier_init(&barrier, 0, 2); +  pthread_t tid; +  int res = pthread_create(&tid, 0, thread_func, 0); +  pthread_barrier_wait(&barrier); +  pthread_barrier_destroy(&barrier); + +  pid_t pid = fork(); +  if (pid > 0) { +    int status = 0; +    waitpid(pid, &status, 0); +  } +  return 0; +} + +// CHECK: WARNING: LeakSanitizer is disabled in forked process diff --git a/test/lsan/TestCases/Linux/log-path_test.cc b/test/lsan/TestCases/Linux/log-path_test.cc new file mode 100644 index 0000000000000..a31b4f64acc5d --- /dev/null +++ b/test/lsan/TestCases/Linux/log-path_test.cc @@ -0,0 +1,26 @@ +// RUN: %clangxx_lsan %s -o %t +// The globs below do not work in the lit shell. + +// Regular run. +// RUN: %env_lsan_opts="use_stacks=0" not %run %t > %t.out 2>&1 +// RUN: FileCheck %s --check-prefix=CHECK-ERROR < %t.out + +// Good log_path. +// RUN: rm -f %t.log.* +// RUN: %env_lsan_opts="use_stacks=0:log_path='"%t.log"'" not %run %t > %t.out 2>&1 +// RUN: FileCheck %s --check-prefix=CHECK-ERROR < %t.log.* + +#include <stdio.h> +#include <stdlib.h> +#include "sanitizer_common/print_address.h" + +int main() { +  void *stack_var = malloc(1337); +  print_address("Test alloc: ", 1, stack_var); +  // Do not return from main to prevent the pointer from going out of scope. +  exit(0); +} + +// CHECK-ERROR: LeakSanitizer: detected memory leaks +// CHECK-ERROR: Direct leak of 1337 byte(s) in 1 object(s) allocated from +// CHECK-ERROR: SUMMARY: {{(Leak|Address)}}Sanitizer: diff --git a/test/lsan/TestCases/Linux/use_tls_dynamic.cc b/test/lsan/TestCases/Linux/use_tls_dynamic.cc index f5df231ba9a6b..4d70a46f8183f 100644 --- a/test/lsan/TestCases/Linux/use_tls_dynamic.cc +++ b/test/lsan/TestCases/Linux/use_tls_dynamic.cc @@ -5,7 +5,7 @@  // RUN: %env_lsan_opts=$LSAN_BASE:"use_tls=0" not %run %t 2>&1 | FileCheck %s  // RUN: %env_lsan_opts=$LSAN_BASE:"use_tls=1" %run %t 2>&1  // RUN: %env_lsan_opts="" %run %t 2>&1 -// UNSUPPORTED: i386-linux,arm +// UNSUPPORTED: i386-linux,arm,powerpc  #ifndef BUILD_DSO  #include <assert.h> diff --git a/test/lsan/TestCases/Posix/lit.local.cfg b/test/lsan/TestCases/Posix/lit.local.cfg new file mode 100644 index 0000000000000..60a9460820a62 --- /dev/null +++ b/test/lsan/TestCases/Posix/lit.local.cfg @@ -0,0 +1,9 @@ +def getRoot(config): +  if not config.parent: +    return config +  return getRoot(config.parent) + +root = getRoot(config) + +if root.host_os in ['Windows']: +  config.unsupported = True diff --git a/test/lsan/TestCases/allocator_returns_null.cc b/test/lsan/TestCases/allocator_returns_null.cc deleted file mode 100644 index 28dd696dc6730..0000000000000 --- a/test/lsan/TestCases/allocator_returns_null.cc +++ /dev/null @@ -1,131 +0,0 @@ -// Test the behavior of malloc/calloc/realloc/new when the allocation size is -// more than LSan allocator's max allowed one. -// By default (allocator_may_return_null=0) the process should crash. -// With allocator_may_return_null=1 the allocator should return 0, except the -// operator new(), which should crash anyway (operator new(std::nothrow) should -// return nullptr, indeed). -// -// RUN: %clangxx_lsan -O0 %s -o %t -// RUN: not %run %t malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mCRASH -// RUN: %env_lsan_opts=allocator_may_return_null=0 not %run %t malloc 2>&1 \ -// RUN:   | FileCheck %s --check-prefix=CHECK-mCRASH -// RUN: %env_lsan_opts=allocator_may_return_null=1     %run %t malloc 2>&1 \ -// RUN:   | FileCheck %s --check-prefix=CHECK-mNULL -// RUN: %env_lsan_opts=allocator_may_return_null=0 not %run %t calloc 2>&1 \ -// RUN:   | FileCheck %s --check-prefix=CHECK-cCRASH -// RUN: %env_lsan_opts=allocator_may_return_null=1     %run %t calloc 2>&1 \ -// RUN:   | FileCheck %s --check-prefix=CHECK-cNULL -// RUN: %env_lsan_opts=allocator_may_return_null=0 not %run %t calloc-overflow 2>&1 \ -// RUN:   | FileCheck %s --check-prefix=CHECK-coCRASH -// RUN: %env_lsan_opts=allocator_may_return_null=1     %run %t calloc-overflow 2>&1 \ -// RUN:   | FileCheck %s --check-prefix=CHECK-coNULL -// RUN: %env_lsan_opts=allocator_may_return_null=0 not %run %t realloc 2>&1 \ -// RUN:   | FileCheck %s --check-prefix=CHECK-rCRASH -// RUN: %env_lsan_opts=allocator_may_return_null=1     %run %t realloc 2>&1 \ -// RUN:   | FileCheck %s --check-prefix=CHECK-rNULL -// RUN: %env_lsan_opts=allocator_may_return_null=0 not %run %t realloc-after-malloc 2>&1 \ -// RUN:   | FileCheck %s --check-prefix=CHECK-mrCRASH -// RUN: %env_lsan_opts=allocator_may_return_null=1     %run %t realloc-after-malloc 2>&1 \ -// RUN:   | FileCheck %s --check-prefix=CHECK-mrNULL -// RUN: %env_lsan_opts=allocator_may_return_null=0 not %run %t new 2>&1 \ -// RUN:   | FileCheck %s --check-prefix=CHECK-nCRASH -// RUN: %env_lsan_opts=allocator_may_return_null=1 not %run %t new 2>&1 \ -// RUN:   | FileCheck %s --check-prefix=CHECK-nCRASH -// RUN: %env_lsan_opts=allocator_may_return_null=0 not %run %t new-nothrow 2>&1 \ -// RUN:   | FileCheck %s --check-prefix=CHECK-nnCRASH -// RUN: %env_lsan_opts=allocator_may_return_null=1     %run %t new-nothrow 2>&1 \ -// RUN:   | FileCheck %s --check-prefix=CHECK-nnNULL - -#include <assert.h> -#include <errno.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <limits> -#include <new> - -int main(int argc, char **argv) { -  // Disable stderr buffering. Needed on Windows. -  setvbuf(stderr, NULL, _IONBF, 0); - -  assert(argc == 2); -  const char *action = argv[1]; -  fprintf(stderr, "%s:\n", action); - -  // Use max of ASan and LSan allocator limits to cover both "lsan" and -  // "lsan + asan" configs. -  static const size_t kMaxAllowedMallocSizePlusOne = -#if __LP64__ || defined(_WIN64) -      (1ULL << 40) + 1; -#else -      (3UL << 30) + 1; -#endif - -  void *x = 0; -  if (!strcmp(action, "malloc")) { -    x = malloc(kMaxAllowedMallocSizePlusOne); -  } else if (!strcmp(action, "calloc")) { -    x = calloc((kMaxAllowedMallocSizePlusOne / 4) + 1, 4); -  } else if (!strcmp(action, "calloc-overflow")) { -    volatile size_t kMaxSizeT = std::numeric_limits<size_t>::max(); -    size_t kArraySize = 4096; -    volatile size_t kArraySize2 = kMaxSizeT / kArraySize + 10; -    x = calloc(kArraySize, kArraySize2); -  } else if (!strcmp(action, "realloc")) { -    x = realloc(0, kMaxAllowedMallocSizePlusOne); -  } else if (!strcmp(action, "realloc-after-malloc")) { -    char *t = (char*)malloc(100); -    *t = 42; -    x = realloc(t, kMaxAllowedMallocSizePlusOne); -    assert(*t == 42); -    free(t); -  } else if (!strcmp(action, "new")) { -    x = operator new(kMaxAllowedMallocSizePlusOne); -  } else if (!strcmp(action, "new-nothrow")) { -    x = operator new(kMaxAllowedMallocSizePlusOne, std::nothrow); -  } else { -    assert(0); -  } - -  fprintf(stderr, "errno: %d\n", errno); - -  // The NULL pointer is printed differently on different systems, while (long)0 -  // is always the same. -  fprintf(stderr, "x: %zu\n", (size_t)x); -  free(x); - -  return x != 0; -} - -// CHECK-mCRASH: malloc: -// CHECK-mCRASH: Sanitizer's allocator is terminating the process -// CHECK-cCRASH: calloc: -// CHECK-cCRASH: Sanitizer's allocator is terminating the process -// CHECK-coCRASH: calloc-overflow: -// CHECK-coCRASH: Sanitizer's allocator is terminating the process -// CHECK-rCRASH: realloc: -// CHECK-rCRASH: Sanitizer's allocator is terminating the process -// CHECK-mrCRASH: realloc-after-malloc: -// CHECK-mrCRASH: Sanitizer's allocator is terminating the process -// CHECK-nCRASH: new: -// CHECK-nCRASH: Sanitizer's allocator is terminating the process -// CHECK-nnCRASH: new-nothrow: -// CHECK-nnCRASH: Sanitizer's allocator is terminating the process - -// CHECK-mNULL: malloc: -// CHECK-mNULL: errno: 12 -// CHECK-mNULL: x: 0 -// CHECK-cNULL: calloc: -// CHECK-cNULL: errno: 12 -// CHECK-cNULL: x: 0 -// CHECK-coNULL: calloc-overflow: -// CHECK-coNULL: errno: 12 -// CHECK-coNULL: x: 0 -// CHECK-rNULL: realloc: -// CHECK-rNULL: errno: 12 -// CHECK-rNULL: x: 0 -// CHECK-mrNULL: realloc-after-malloc: -// CHECK-mrNULL: errno: 12 -// CHECK-mrNULL: x: 0 -// CHECK-nnNULL: new-nothrow: -// CHECK-nnNULL: x: 0 diff --git a/test/msan/Linux/name_to_handle_at.cc b/test/msan/Linux/name_to_handle_at.cc new file mode 100644 index 0000000000000..0ff8d982f4f77 --- /dev/null +++ b/test/msan/Linux/name_to_handle_at.cc @@ -0,0 +1,28 @@ +// RUN: %clangxx_msan -std=c++11 -O0 -g %s -o %t && %run %t + +#include <assert.h> +#include <fcntl.h> +#include <sanitizer/msan_interface.h> +#include <stdlib.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> + +int main(void) { +  struct file_handle *handle = reinterpret_cast<struct file_handle *>( +      malloc(sizeof(*handle) + MAX_HANDLE_SZ)); +  handle->handle_bytes = MAX_HANDLE_SZ; + +  int mount_id; +  int res = name_to_handle_at(AT_FDCWD, "/bin/cat", handle, &mount_id, 0); +  assert(!res); +  __msan_check_mem_is_initialized(&mount_id, sizeof(mount_id)); +  __msan_check_mem_is_initialized(&handle->handle_bytes, +                                  sizeof(handle->handle_bytes)); +  __msan_check_mem_is_initialized(&handle->handle_type, +                                  sizeof(handle->handle_type)); +  __msan_check_mem_is_initialized(&handle->f_handle, handle->handle_bytes); + +  free(handle); +  return 0; +} diff --git a/test/msan/Linux/sendmsg.cc b/test/msan/Linux/sendmsg.cc index 4fc6c88cc5dd1..91c3f64d7f215 100644 --- a/test/msan/Linux/sendmsg.cc +++ b/test/msan/Linux/sendmsg.cc @@ -1,10 +1,12 @@  // RUN: %clangxx_msan %s -DSEND -DPOISON -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=SEND  // RUN: %clangxx_msan %s -DSENDTO -DPOISON -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=SENDTO  // RUN: %clangxx_msan %s -DSENDMSG -DPOISON -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=SENDMSG +// RUN: %clangxx_msan %s -DSENDMMSG -DPOISON -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=SENDMMSG  // RUN: %clangxx_msan %s -DSEND -o %t && %run %t 2>&1 | FileCheck %s --check-prefix=NEGATIVE  // RUN: %clangxx_msan %s -DSENDTO -o %t && %run %t 2>&1 | FileCheck %s --check-prefix=NEGATIVE  // RUN: %clangxx_msan %s -DSENDMSG -o %t && %run %t 2>&1 | FileCheck %s --check-prefix=NEGATIVE +// RUN: %clangxx_msan %s -DSENDMMSG -o %t && %run %t 2>&1 | FileCheck %s --check-prefix=NEGATIVE  // RUN: %clangxx_msan %s -DSEND -DPOISON -o %t && \  // RUN:   MSAN_OPTIONS=intercept_send=0 %run %t 2>&1 | FileCheck %s --check-prefix=NEGATIVE @@ -12,6 +14,8 @@  // RUN:   MSAN_OPTIONS=intercept_send=0 %run %t 2>&1 | FileCheck %s --check-prefix=NEGATIVE  // RUN: %clangxx_msan %s -DSENDMSG -DPOISON -o %t && \  // RUN:   MSAN_OPTIONS=intercept_send=0 %run %t 2>&1 | FileCheck %s --check-prefix=NEGATIVE +// RUN: %clangxx_msan %s -DSENDMMSG -DPOISON -o %t && \ +// RUN:   MSAN_OPTIONS=intercept_send=0 %run %t 2>&1 | FileCheck %s --check-prefix=NEGATIVE  // UNSUPPORTED: android @@ -20,54 +24,32 @@  #include <unistd.h>  #include <stdlib.h>  #include <string.h> -#include <netdb.h>  #include <sys/types.h>  #include <sys/socket.h>  #include <sanitizer/msan_interface.h>  const int kBufSize = 10; -int sockfd; +const int kRecvBufSize = 100; +int sockfd[2];  int main() {    int ret; +  int sent;    char buf[kBufSize] = {0}; -  pthread_t client_thread; -  struct sockaddr_in serveraddr; -  struct sockaddr_in6 serveraddr6; - -  memset(&serveraddr, 0, sizeof(serveraddr)); -  serveraddr.sin_family = AF_INET; -  serveraddr.sin_addr.s_addr = htonl(INADDR_ANY); -  serveraddr.sin_port = 0; -  struct sockaddr *addr = (struct sockaddr *)&serveraddr; -  socklen_t addrlen = sizeof(serveraddr); - -  sockfd = socket(addr->sa_family, SOCK_DGRAM, 0); -  if (sockfd <= 0) { -    // Try to fall-back to IPv6 -    memset(&serveraddr6, 0, sizeof(serveraddr6)); -    serveraddr6.sin6_family = AF_INET6; -    serveraddr6.sin6_addr = in6addr_any; -    serveraddr6.sin6_port = 0; -    addr = (struct sockaddr *)&serveraddr6; -    addrlen = sizeof(serveraddr6); - -    sockfd = socket(addr->sa_family, SOCK_DGRAM, 0); -  } -  assert(sockfd > 0); - -  bind(sockfd, addr, addrlen); -  getsockname(sockfd, addr, &addrlen); +  char rbuf[kRecvBufSize]; + +  ret = socketpair(AF_LOCAL, SOCK_DGRAM, 0, sockfd); +  assert(!ret);  #if defined(POISON)    __msan_poison(buf + 7, 1);  #endif -#if defined(SENDMSG) +#if defined(SENDMSG) || defined(SENDMMSG)    struct iovec iov[2] = {{buf, 5}, {buf + 5, 5}};    struct msghdr msg; -  msg.msg_name = addr; -  msg.msg_namelen = addrlen; +  msg.msg_name = nullptr; +  msg.msg_namelen = 0;    msg.msg_iov = iov;    msg.msg_iovlen = 2;    msg.msg_control = 0; @@ -75,20 +57,95 @@ int main() {    msg.msg_flags = 0;  #endif +#if defined(SENDMMSG) +  struct iovec iov0[1] = {{buf, 7}}; +  struct msghdr msg0; +  msg0.msg_name = nullptr; +  msg0.msg_namelen = 0; +  msg0.msg_iov = iov0; +  msg0.msg_iovlen = 1; +  msg0.msg_control = 0; +  msg0.msg_controllen = 0; +  msg0.msg_flags = 0; + +  struct mmsghdr mmsg[2]; +  mmsg[0].msg_hdr = msg0; // good +  mmsg[1].msg_hdr = msg; // poisoned +#endif +  #if defined(SEND) -  ret = connect(sockfd, addr, addrlen); -  assert(ret == 0); -  ret = send(sockfd, buf, kBufSize, 0); +  sent = send(sockfd[0], buf, kBufSize, 0);    // SEND: Uninitialized bytes in __interceptor_send at offset 7 inside [{{.*}}, 10) -  assert(ret > 0); +  assert(sent > 0); + +  ret = recv(sockfd[1], rbuf, kRecvBufSize, 0); +  assert(ret == sent); +  assert(__msan_test_shadow(rbuf, kRecvBufSize) == sent);  #elif defined(SENDTO) -  ret = sendto(sockfd, buf, kBufSize, 0, addr, addrlen); +  sent = sendto(sockfd[0], buf, kBufSize, 0, nullptr, 0);    // SENDTO: Uninitialized bytes in __interceptor_sendto at offset 7 inside [{{.*}}, 10) -  assert(ret > 0); +  assert(sent > 0); + +  struct sockaddr_storage ss; +  socklen_t sslen = sizeof(ss); +  ret = recvfrom(sockfd[1], rbuf, kRecvBufSize, 0, (struct sockaddr *)&ss, +                 &sslen); +  assert(ret == sent); +  assert(__msan_test_shadow(rbuf, kRecvBufSize) == sent); +  assert(__msan_test_shadow(&ss, sizeof(ss)) == sslen);  #elif defined(SENDMSG) -  ret = sendmsg(sockfd, &msg, 0); +  sent = sendmsg(sockfd[0], &msg, 0);    // SENDMSG: Uninitialized bytes in {{.*}} at offset 2 inside [{{.*}}, 5) -  assert(ret > 0); +  assert(sent > 0); + +  struct iovec riov[2] = {{rbuf, 3}, {rbuf + 3, kRecvBufSize - 3}}; +  struct msghdr rmsg; +  rmsg.msg_name = nullptr; +  rmsg.msg_namelen = 0; +  rmsg.msg_iov = riov; +  rmsg.msg_iovlen = 2; +  rmsg.msg_control = 0; +  rmsg.msg_controllen = 0; +  rmsg.msg_flags = 0; + +  ret = recvmsg(sockfd[1], &rmsg, 0); +  assert(ret == sent); +  assert(__msan_test_shadow(rbuf, kRecvBufSize) == sent); +#elif defined(SENDMMSG) +  sent = sendmmsg(sockfd[0], mmsg, 2, 0); +  // SENDMMSG: Uninitialized bytes in {{.*}} at offset 2 inside [{{.*}}, 5) +  assert(sent == 2); +  if (ret >= 2) +    assert(mmsg[1].msg_len > 0); + +  struct iovec riov[2] = {{rbuf + kRecvBufSize / 2, kRecvBufSize / 2}}; +  struct msghdr rmsg; +  rmsg.msg_name = nullptr; +  rmsg.msg_namelen = 0; +  rmsg.msg_iov = riov; +  rmsg.msg_iovlen = 1; +  rmsg.msg_control = 0; +  rmsg.msg_controllen = 0; +  rmsg.msg_flags = 0; + +  struct iovec riov0[2] = {{rbuf, kRecvBufSize / 2}}; +  struct msghdr rmsg0; +  rmsg0.msg_name = nullptr; +  rmsg0.msg_namelen = 0; +  rmsg0.msg_iov = riov0; +  rmsg0.msg_iovlen = 1; +  rmsg0.msg_control = 0; +  rmsg0.msg_controllen = 0; +  rmsg0.msg_flags = 0; + +  struct mmsghdr rmmsg[2]; +  rmmsg[0].msg_hdr = rmsg0; +  rmmsg[1].msg_hdr = rmsg; + +  ret = recvmmsg(sockfd[1], rmmsg, 2, 0, nullptr); +  assert(ret == sent); +  assert(__msan_test_shadow(rbuf, kRecvBufSize) == 7); +  assert(__msan_test_shadow(rbuf + kRecvBufSize / 2, kRecvBufSize / 2) == 10);  #endif    fprintf(stderr, "== done\n");    // NEGATIVE: == done diff --git a/test/msan/check-handler.cc b/test/msan/check-handler.cc new file mode 100644 index 0000000000000..4721f8c3068e3 --- /dev/null +++ b/test/msan/check-handler.cc @@ -0,0 +1,16 @@ +// RUN: %clangxx_msan -O0 -g %s -o %t && not %run %t 2>&1 | FileCheck %s + +// Verify that CHECK handler prints a stack on CHECK fail. + +#include <stdlib.h> + +int main(void) { +  // Allocate chunk from the secondary allocator to trigger CHECK(IsALigned()) +  // in its free() path. +  void *p = malloc(8 << 20); +  free(reinterpret_cast<char*>(p) + 1); +  // CHECK: MemorySanitizer: bad pointer +  // CHECK: MemorySanitizer CHECK failed +  // CHECK: #0 +  return 0; +} diff --git a/test/msan/coverage-levels.cc b/test/msan/coverage-levels.cc index b881cecac7e91..5ca3b717d04fb 100644 --- a/test/msan/coverage-levels.cc +++ b/test/msan/coverage-levels.cc @@ -1,14 +1,14 @@  // Test various levels of coverage  //  // RUN: %clangxx_msan -DINIT_VAR=1 -O1 -fsanitize-coverage=func  %s -o %t -// RUN: mkdir -p %T/coverage-levels -// RUN: MSAN_OPTIONS=coverage=1:verbosity=1:coverage_dir=%T/coverage-levels %run %t 2>&1 | FileCheck %s --check-prefix=CHECK1 --check-prefix=CHECK_NOWARN +// RUN: mkdir -p %t-dir +// RUN: MSAN_OPTIONS=coverage=1:verbosity=1:coverage_dir=%t-dir %run %t 2>&1 | FileCheck %s --check-prefix=CHECK1 --check-prefix=CHECK_NOWARN  // RUN: %clangxx_msan -O1 -fsanitize-coverage=func  %s -o %t -// RUN: MSAN_OPTIONS=coverage=1:verbosity=1:coverage_dir=%T/coverage-levels not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK1 --check-prefix=CHECK_WARN +// RUN: MSAN_OPTIONS=coverage=1:verbosity=1:coverage_dir=%t-dir not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK1 --check-prefix=CHECK_WARN  // RUN: %clangxx_msan -O1 -fsanitize-coverage=bb  %s -o %t -// RUN: MSAN_OPTIONS=coverage=1:verbosity=1:coverage_dir=%T/coverage-levels not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK2 --check-prefix=CHECK_WARN +// RUN: MSAN_OPTIONS=coverage=1:verbosity=1:coverage_dir=%t-dir not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK2 --check-prefix=CHECK_WARN  // RUN: %clangxx_msan -O1 -fsanitize-coverage=edge  %s -o %t -// RUN: MSAN_OPTIONS=coverage=1:verbosity=1:coverage_dir=%T/coverage-levels not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK3 --check-prefix=CHECK_WARN +// RUN: MSAN_OPTIONS=coverage=1:verbosity=1:coverage_dir=%t-dir not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK3 --check-prefix=CHECK_WARN  volatile int sink;  int main(int argc, char **argv) { diff --git a/test/msan/dtls_test.c b/test/msan/dtls_test.c index 49d95c44c1d82..b9021e0da1aff 100644 --- a/test/msan/dtls_test.c +++ b/test/msan/dtls_test.c @@ -5,6 +5,9 @@     Regression test for a bug in msan/glibc integration,     see https://sourceware.org/bugzilla/show_bug.cgi?id=16291     and https://github.com/google/sanitizers/issues/547 + +   XFAIL: FreeBSD +   UNSUPPORTED: powerpc  */  #ifndef BUILD_SO diff --git a/test/msan/dtor-member.cc b/test/msan/dtor-member.cc index 13a059947bca3..bf20221a363bc 100644 --- a/test/msan/dtor-member.cc +++ b/test/msan/dtor-member.cc @@ -7,7 +7,7 @@  // RUN: %clangxx_msan %s -O2 -fsanitize=memory -fsanitize-memory-use-after-dtor -o %t && MSAN_OPTIONS=poison_in_dtor=1  %run %t >%t.out 2>&1  // RUN: FileCheck %s < %t.out -// RUN: %clangxx_msan %s -fsanitize=memory -o %t && MSAN_OPTIONS=poison_in_dtor=1  %run %t >%t.out 2>&1 +// RUN: %clangxx_msan %s -fsanitize=memory -fno-sanitize-memory-use-after-dtor -o %t && MSAN_OPTIONS=poison_in_dtor=1  %run %t >%t.out 2>&1  // RUN: FileCheck %s --check-prefix=CHECK-NO-FLAG < %t.out  // RUN: %clangxx_msan -fsanitize=memory -fsanitize-memory-use-after-dtor %s -o %t && MSAN_OPTIONS=poison_in_dtor=0 %run %t >%t.out 2>&1 diff --git a/test/msan/fgets_fputs.cc b/test/msan/fgets_fputs.cc new file mode 100644 index 0000000000000..1e96943980d6b --- /dev/null +++ b/test/msan/fgets_fputs.cc @@ -0,0 +1,47 @@ +// RUN: %clangxx_msan -g %s -o %t +// RUN: %run %t +// RUN: not %run %t 2 2>&1 | FileCheck %s --check-prefix=CHECK-FPUTS +// RUN: not %run %t 3 3 2>&1 | FileCheck %s --check-prefix=CHECK-PUTS + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +int test_fgets() { +  FILE *fp = fopen("/dev/zero", "r"); +  char c; + +  if (!fgets(&c, 1, fp)) +    return 1; + +  if (c == '1') // No error +    return 2; + +  fclose(fp); +  return 0; +} + +int test_fputs() { +  FILE *fp = fopen("/dev/null", "w"); +  char buf[2]; +  fputs(buf, fp); // BOOM +  return fclose(fp); +} + +void test_puts() { +  char buf[2]; +  puts(buf); // BOOM +} + +int main(int argc, char *argv[]) { +  if (argc == 1) +    test_fgets(); +  else if (argc == 2) +    test_fputs(); +  else +    test_puts(); +  return 0; +} + +// CHECK-FPUTS: Uninitialized bytes in __interceptor_fputs at offset 0 inside +// CHECK-PUTS: Uninitialized bytes in __interceptor_puts at offset 0 inside diff --git a/test/msan/fstat.cc b/test/msan/fstat.cc new file mode 100644 index 0000000000000..83f97054cea76 --- /dev/null +++ b/test/msan/fstat.cc @@ -0,0 +1,15 @@ +// RUN: %clangxx_msan -O0 %s -o %t && %run %t + +#include <sys/stat.h> +#include <stdlib.h> + +int main(void) { +  struct stat st; +  if (fstat(0, &st)) +    exit(1); + +  if (S_ISBLK(st.st_mode)) +    exit(0); + +  return 0; +} diff --git a/test/msan/getutent.cc b/test/msan/getutent.cc index 36f9e1f1f7e30..b57101068dddf 100644 --- a/test/msan/getutent.cc +++ b/test/msan/getutent.cc @@ -1,14 +1,18 @@  // RUN: %clangxx_msan -O0 -g %s -o %t && %run %t +#ifndef __FreeBSD__  #include <utmp.h> +#endif  #include <utmpx.h>  #include <sanitizer/msan_interface.h>  int main(void) { +#ifndef __FreeBSD__    setutent();    while (struct utmp *ut = getutent())      __msan_check_mem_is_initialized(ut, sizeof(*ut));    endutent(); +#endif    setutxent();    while (struct utmpx *utx = getutxent()) diff --git a/test/msan/iconv.cc b/test/msan/iconv.cc index 7beb6a01877c7..7713cb8e5f454 100644 --- a/test/msan/iconv.cc +++ b/test/msan/iconv.cc @@ -15,7 +15,7 @@ int main(void) {    char inbuf_[100];    strcpy(inbuf_, "sample text");    char outbuf_[100]; -#if defined(__FreeBSD__) || defined(__NetBSD__) +#if defined(__NetBSD__)    // Some OSes expect the 2nd argument of iconv(3) to be of type const char **    const char *inbuf = inbuf_;  #else diff --git a/test/msan/lit.cfg b/test/msan/lit.cfg index cac2609998774..550d04d0812b1 100644 --- a/test/msan/lit.cfg +++ b/test/msan/lit.cfg @@ -29,7 +29,7 @@ config.substitutions.append( ("%clangxx_msan ", build_invocation(clang_msan_cxxf  # Default test suffixes.  config.suffixes = ['.c', '.cc', '.cpp'] -if config.host_os not in ['Linux', 'NetBSD']: +if config.host_os not in ['Linux', 'NetBSD', 'FreeBSD']:    config.unsupported = True  # For mips64, mips64el we have forced store_context_size to 1 because these diff --git a/test/msan/mmap.cc b/test/msan/mmap.cc index 65d8beeefe3a7..d83423735211d 100644 --- a/test/msan/mmap.cc +++ b/test/msan/mmap.cc @@ -63,9 +63,13 @@ int main() {    const size_t kMapSize = 0x1000000000ULL;  #endif    int success_count = 0; +  int flags = MAP_PRIVATE | MAP_ANONYMOUS; +#if defined(MAP_NORESERVE) +  flags |= MAP_NORESERVE; +#endif    while (true) {      void *p = mmap(0, kMapSize, PROT_WRITE, -                   MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0); +                   flags, -1, 0);      printf("%p\n", p);      if (p == MAP_FAILED) {        assert(errno == ENOMEM); diff --git a/test/msan/pthread_getattr_np_deadlock.cc b/test/msan/pthread_getattr_np_deadlock.cc index 0f52280856cc5..241caa2a211d8 100644 --- a/test/msan/pthread_getattr_np_deadlock.cc +++ b/test/msan/pthread_getattr_np_deadlock.cc @@ -4,10 +4,20 @@  #include <assert.h>  #include <pthread.h> +#if defined(__FreeBSD__) +#include <pthread_np.h> +#endif  void *ThreadFn(void *) {    pthread_attr_t attr; +#if defined(__FreeBSD__) +  // On FreeBSD it needs to allocate attr underlying memory +  int res = pthread_attr_init(&attr); +  assert(!res); +  res = pthread_attr_get_np(pthread_self(), &attr); +#else    int res = pthread_getattr_np(pthread_self(), &attr); +#endif    assert(!res);    return 0;  } diff --git a/test/msan/pthread_getname_np.cc b/test/msan/pthread_getname_np.cc index ca27d8b6fd6c0..e19b652a73c90 100644 --- a/test/msan/pthread_getname_np.cc +++ b/test/msan/pthread_getname_np.cc @@ -1,5 +1,7 @@  // RUN: %clangxx_msan -std=c++11 -O0 %s -o %t && %run %t -// UNSUPPORTED: android, netbsd +// The main goal is getting the pthread name back and +// FreeBSD based do not support this feature +// UNSUPPORTED: android, netbsd, freebsd  // Regression test for a deadlock in pthread_getattr_np @@ -10,12 +12,22 @@  #include <stdio.h> +// Stall child thread on this lock to make sure it doesn't finish +// before the end of the pthread_getname_np() / pthread_setname_np() tests. +static pthread_mutex_t lock; +  void *ThreadFn(void *) { +  pthread_mutex_lock (&lock); +  pthread_mutex_unlock (&lock);    return nullptr;  }  int main(void) {    pthread_t t; + +  pthread_mutex_init (&lock, NULL); +  pthread_mutex_lock (&lock); +    int res = pthread_create(&t, 0, ThreadFn, 0);    assert(!res); @@ -28,6 +40,8 @@ int main(void) {    assert(!res);    assert(strcmp(buf, kMyThreadName) == 0); +  pthread_mutex_unlock (&lock); +    res = pthread_join(t, 0);    assert(!res);    return 0; diff --git a/test/msan/pvalloc.cc b/test/msan/pvalloc.cc deleted file mode 100644 index 7c406df79bb1a..0000000000000 --- a/test/msan/pvalloc.cc +++ /dev/null @@ -1,43 +0,0 @@ -// RUN: %clangxx_msan -O0 %s -o %t -// RUN: MSAN_OPTIONS=allocator_may_return_null=0 not %run %t m1 2>&1 | FileCheck %s -// RUN: MSAN_OPTIONS=allocator_may_return_null=1     %run %t m1 2>&1 -// RUN: MSAN_OPTIONS=allocator_may_return_null=0 not %run %t psm1 2>&1 | FileCheck %s -// RUN: MSAN_OPTIONS=allocator_may_return_null=1     %run %t psm1 2>&1 - -// UNSUPPORTED: win32, freebsd, netbsd - -// Checks that pvalloc overflows are caught. If the allocator is allowed to -// return null, the errno should be set to ENOMEM. - -#include <assert.h> -#include <errno.h> -#include <malloc.h> -#include <stdint.h> -#include <string.h> -#include <unistd.h> - -int main(int argc, char *argv[]) { -  void *p; -  size_t page_size; - -  assert(argc == 2); - -  page_size = sysconf(_SC_PAGESIZE); -  // Check that the page size is a power of two. -  assert((page_size & (page_size - 1)) == 0); - -  if (!strcmp(argv[1], "m1")) { -    p = pvalloc((uintptr_t)-1); -    assert(!p); -    assert(errno == ENOMEM); -  } -  if (!strcmp(argv[1], "psm1")) { -    p = pvalloc((uintptr_t)-(page_size - 1)); -    assert(!p); -    assert(errno == ENOMEM); -  } - -  return 0; -} - -// CHECK: MemorySanitizer's allocator is terminating the process diff --git a/test/msan/scoped-interceptors.cc b/test/msan/scoped-interceptors.cc new file mode 100644 index 0000000000000..fc7d4578482bd --- /dev/null +++ b/test/msan/scoped-interceptors.cc @@ -0,0 +1,52 @@ +// RUN: %clangxx_msan %s -o %t +// RUN: %run %t --disable-checks 0 2>&1 | FileCheck --check-prefix=DISABLED --allow-empty %s +// RUN: %run %t --disable-checks 1 2>&1 | FileCheck --check-prefix=DISABLED --allow-empty %s +// RUN: %run %t --disable-checks 2 2>&1 | FileCheck --check-prefix=DISABLED --allow-empty %s +// RUN: %run %t --disable-checks 3 2>&1 | FileCheck --check-prefix=DISABLED --allow-empty %s +// RUN: not %run %t --reenable-checks 0 2>&1 | FileCheck --check-prefix=CASE-0 %s +// RUN: not %run %t --reenable-checks 1 2>&1 | FileCheck --check-prefix=CASE-1 %s +// RUN: not %run %t --reenable-checks 2 2>&1 | FileCheck --check-prefix=CASE-2 %s +// RUN: not %run %t --reenable-checks 3 2>&1 | FileCheck --check-prefix=CASE-3 %s + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sanitizer/msan_interface.h> + +int main(int argc, char *argv[]) { +  assert(argc == 3); +  __msan_scoped_disable_interceptor_checks(); +  if (strcmp(argv[1], "--reenable-checks") == 0) +    __msan_scoped_enable_interceptor_checks(); + +  char uninit[7]; +  switch (argv[2][0]) { +    case '0': { +      char *copy = strndup(uninit, sizeof(uninit));  // BOOM +      free(copy); +      break; +      // CASE-0: Uninitialized bytes in __interceptor_strndup +    } +    case '1': { +      puts(uninit);  // BOOM +      puts(uninit);  // Ensure previous call did not enable interceptor checks. +      break; +      // CASE-1: Uninitialized bytes in __interceptor_puts +    } +    case '2': { +      int cmp = memcmp(uninit, uninit, sizeof(uninit));  // BOOM +      break; +      // CASE-2: Uninitialized bytes in __interceptor_memcmp +    } +    case '3': { +      size_t len = strlen(uninit);  // BOOM +      break; +      // CASE-3: Uninitialized bytes in __interceptor_strlen +    } +    default: assert(0); +  } +  // DISABLED-NOT: Uninitialized bytes +  return 0; +} + diff --git a/test/msan/strlen_of_shadow.cc b/test/msan/strlen_of_shadow.cc index b9cf5f065d2da..718cc08dc1fd4 100644 --- a/test/msan/strlen_of_shadow.cc +++ b/test/msan/strlen_of_shadow.cc @@ -2,6 +2,8 @@  // Check that strlen() and similar intercepted functions can be called on shadow  // memory. +// The mem_to_shadow's part might need rework +// XFAIL: freebsd  #include <assert.h>  #include <stdint.h> diff --git a/test/msan/textdomain.cc b/test/msan/textdomain.cc index 760debd68c33d..478b0993f8371 100644 --- a/test/msan/textdomain.cc +++ b/test/msan/textdomain.cc @@ -1,4 +1,6 @@  // RUN: %clangxx_msan -O0 -g %s -o %t && %run %t +// textdomain() is not a part of libc on FreeBSD and NetBSD. +// UNSUPPORTED: netbsd, freebsd  #include <libintl.h>  #include <stdio.h> diff --git a/test/msan/tls_reuse.cc b/test/msan/tls_reuse.cc index 78a328fa3ce01..9c2ee975cb572 100644 --- a/test/msan/tls_reuse.cc +++ b/test/msan/tls_reuse.cc @@ -1,6 +1,7 @@  // RUN: %clangxx_msan -O0 %s -o %t && %run %t  // Check that when TLS block is reused between threads, its shadow is cleaned. +// XFAIL: freebsd  #include <pthread.h>  #include <stdio.h> diff --git a/test/msan/tsearch.cc b/test/msan/tsearch.cc index 0d8ee8f35b257..50a2efb31fadc 100644 --- a/test/msan/tsearch.cc +++ b/test/msan/tsearch.cc @@ -1,7 +1,7 @@  // RUN: %clangxx_msan -O0 -g %s -o %t && %run %t  // tdestroy is a GNU extension -// UNSUPPORTED: netbsd +// UNSUPPORTED: netbsd, freebsd  #include <assert.h>  #include <search.h> diff --git a/test/msan/tzset.cc b/test/msan/tzset.cc index 05915e047e157..86805cd56c5df 100644 --- a/test/msan/tzset.cc +++ b/test/msan/tzset.cc @@ -1,4 +1,5 @@  // RUN: %clangxx_msan -O0 %s -o %t && %run %t +// XFAIL: freebsd  #include <stdlib.h>  #include <string.h> diff --git a/test/msan/use-after-dtor.cc b/test/msan/use-after-dtor.cc index 6c751a14f3774..45f4dcd69b783 100644 --- a/test/msan/use-after-dtor.cc +++ b/test/msan/use-after-dtor.cc @@ -1,14 +1,17 @@  // RUN: %clangxx_msan %s -fsanitize=memory -fsanitize-memory-use-after-dtor -o %t && MSAN_OPTIONS=poison_in_dtor=1 not %run %t >%t.out 2>&1 -// RUN: FileCheck %s < %t.out +// RUN: FileCheck %s --check-prefix=CHECK-UAD < %t.out  // RUN: %clangxx_msan %s -O1 -fsanitize=memory -fsanitize-memory-use-after-dtor -o %t && MSAN_OPTIONS=poison_in_dtor=1 not %run %t >%t.out 2>&1 -// RUN: FileCheck %s < %t.out +// RUN: FileCheck %s --check-prefix=CHECK-UAD < %t.out  // RUN: %clangxx_msan %s -O2 -fsanitize=memory -fsanitize-memory-use-after-dtor -o %t && MSAN_OPTIONS=poison_in_dtor=1 not %run %t >%t.out 2>&1 -// RUN: FileCheck %s < %t.out +// RUN: FileCheck %s --check-prefix=CHECK-UAD < %t.out  // RUN: %clangxx_msan %s -O1 -fsanitize=memory -fsanitize-memory-use-after-dtor -fsanitize-memory-track-origins -o %t && MSAN_OPTIONS=poison_in_dtor=1 not %run %t >%t.out 2>&1 -// RUN: FileCheck %s --check-prefix=CHECK-ORIGINS < %t.out +// RUN: FileCheck %s --check-prefixes=CHECK-UAD,CHECK-ORIGINS < %t.out + +// RUN: %clangxx_msan %s -fno-sanitize-memory-use-after-dtor -o %t && MSAN_OPTIONS=poison_in_dtor=1 not %run %t > %t.out 2>&1 +// RUN: FileCheck %s --check-prefix=CHECK-UAD-OFF < %t.out  #include <sanitizer/msan_interface.h>  #include <assert.h> @@ -32,14 +35,16 @@ int main() {    Simple *s = new(&buf) Simple();    s->~Simple(); +  fprintf(stderr, "\n");  // Need output to parse for CHECK-UAD-OFF case    return s->x_; -  // CHECK: WARNING: MemorySanitizer: use-of-uninitialized-value -  // CHECK: {{#0 0x.* in main.*use-after-dtor.cc:}}[[@LINE-3]] +  // CHECK-UAD: WARNING: MemorySanitizer: use-of-uninitialized-value +  // CHECK-UAD: {{#0 0x.* in main.*use-after-dtor.cc:}}[[@LINE-3]]    // CHECK-ORIGINS: Memory was marked as uninitialized    // CHECK-ORIGINS: {{#0 0x.* in __sanitizer_dtor_callback}}    // CHECK-ORIGINS: {{#1 0x.* in Simple::~Simple}} -  // CHECK: SUMMARY: MemorySanitizer: use-of-uninitialized-value {{.*main}} +  // CHECK-UAD: SUMMARY: MemorySanitizer: use-of-uninitialized-value {{.*main}} +  // CHECK-UAD-OFF-NOT: SUMMARY: MemorySanitizer: use-of-uninitialized-value  } diff --git a/test/msan/vector_div.cc b/test/msan/vector_div.cc new file mode 100644 index 0000000000000..4ca2369d63e6d --- /dev/null +++ b/test/msan/vector_div.cc @@ -0,0 +1,17 @@ +// Regression test for https://bugs.llvm.org/show_bug.cgi?id=37523 + +// RUN: %clangxx_msan -O0 %s -o %t && %run %t +// RUN: %clangxx_msan -O3 %s -o %t && %run %t +// REQUIRES: x86_64-target-arch + +#include <assert.h> +#include <emmintrin.h> + +int main() { +  volatile int scale = 5; +  volatile auto zz = _mm_div_ps(_mm_set1_ps(255), _mm_set1_ps(scale)); +  assert(zz[0] == 51); +  assert(zz[1] == 51); +  assert(zz[2] == 51); +  assert(zz[3] == 51); +} diff --git a/test/msan/wcsxfrm.cc b/test/msan/wcsxfrm.cc new file mode 100644 index 0000000000000..f13c5d3969a8f --- /dev/null +++ b/test/msan/wcsxfrm.cc @@ -0,0 +1,30 @@ +// RUN: %clangxx_msan -O0 -g %s -o %t && not %run %t + +#include <assert.h> +#include <locale.h> +#include <sanitizer/msan_interface.h> +#include <stdlib.h> +#include <wchar.h> + +int main(void) { +  wchar_t q[10]; +  size_t n = wcsxfrm(q, L"abcdef", sizeof(q) / sizeof(wchar_t)); +  assert(n < sizeof(q)); +  __msan_check_mem_is_initialized(q, (n + 1) * sizeof(wchar_t)); + +  locale_t loc = newlocale(LC_ALL_MASK, "", (locale_t)0); + +  __msan_poison(&q, sizeof(q)); +  n = wcsxfrm_l(q, L"qwerty", sizeof(q) / sizeof(wchar_t), loc); +  assert(n < sizeof(q)); +  __msan_check_mem_is_initialized(q, (n + 1) * sizeof(wchar_t)); + +  q[0] = 'A'; +  q[1] = '\x00'; +  __msan_poison(&q, sizeof(q)); +  wcsxfrm(NULL, q, 0); + +  // CHECK: WARNING: MemorySanitizer: use-of-uninitialized-value +  // CHECK:    in main {{.*}}wcsxfrm.cc:25 +  return 0; +} diff --git a/test/profile/Inputs/instrprof-dlopen-dlclose-main.c b/test/profile/Inputs/instrprof-dlopen-dlclose-main.c new file mode 100644 index 0000000000000..3f4a4f6cc6a63 --- /dev/null +++ b/test/profile/Inputs/instrprof-dlopen-dlclose-main.c @@ -0,0 +1,86 @@ +#include <dlfcn.h> +#include <stdio.h> +#include <stdlib.h> + +int main(int argc, char *argv[]) { +  dlerror(); +  void *f1_handle = dlopen("func.shared", RTLD_LAZY | RTLD_GLOBAL); +  if (f1_handle == NULL) { +    fprintf(stderr, "unable to open 'func.shared': %s\n", dlerror()); +    return EXIT_FAILURE; +  } + +  void (*func)(void) = (void (*)(void))dlsym(f1_handle, "func"); +  if (func == NULL) { +    fprintf(stderr, "unable to lookup symbol 'func': %s\n", dlerror()); +    return EXIT_FAILURE; +  } + +  dlerror(); +  void *f2_handle = dlopen("func2.shared", RTLD_LAZY | RTLD_GLOBAL); +  if (f2_handle == NULL) { +    fprintf(stderr, "unable to open 'func2.shared': %s\n", dlerror()); +    return EXIT_FAILURE; +  } + +  void (*func2)(void) = (void (*)(void))dlsym(f2_handle, "func2"); +  if (func2 == NULL) { +    fprintf(stderr, "unable to lookup symbol 'func2': %s\n", dlerror()); +    return EXIT_FAILURE; +  } +  func2(); + +#ifdef USE_LIB3 +  void *f3_handle = dlopen("func3.shared", RTLD_LAZY | RTLD_GLOBAL); +  if (f3_handle == NULL) { +    fprintf(stderr, "unable to open 'func3.shared': %s\n", dlerror()); +    return EXIT_FAILURE; +  } + +  void (*func3)(void) = (void (*)(void))dlsym(f3_handle, "func3"); +  if (func3 == NULL) { +    fprintf(stderr, "unable to lookup symbol 'func3': %s\n", dlerror()); +    return EXIT_FAILURE; +  } +  func3(); +#endif + +  dlerror(); +  void (*gcov_flush1)() = (void (*)())dlsym(f1_handle, "__gcov_flush"); +  if (gcov_flush1 == NULL) { +    fprintf(stderr, "unable to find __gcov_flush in func.shared': %s\n", dlerror()); +    return EXIT_FAILURE; +  } + +  dlerror(); +  void (*gcov_flush2)() = (void (*)())dlsym(f2_handle, "__gcov_flush"); +  if (gcov_flush2 == NULL) { +    fprintf(stderr, "unable to find __gcov_flush in func2.shared': %s\n", dlerror()); +    return EXIT_FAILURE; +  } + +  if (gcov_flush1 == gcov_flush2) { +    fprintf(stderr, "Same __gcov_flush found in func.shared and func2.shared\n"); +    return EXIT_FAILURE; +  } + +  dlerror(); +  if (dlclose(f2_handle) != 0) { +    fprintf(stderr, "unable to close 'func2.shared': %s\n", dlerror()); +    return EXIT_FAILURE; +  } + +  func(); + +  int g1 = 0; +  int g2 = 0; +  int n = 10; + +  if (n % 5 == 0) +    g1++; +  else +    g2++; + +  return EXIT_SUCCESS; +} + diff --git a/test/profile/Inputs/instrprof-dlopen-dlclose-main.c.gcov b/test/profile/Inputs/instrprof-dlopen-dlclose-main.c.gcov new file mode 100644 index 0000000000000..acb2076fd7634 --- /dev/null +++ b/test/profile/Inputs/instrprof-dlopen-dlclose-main.c.gcov @@ -0,0 +1,91 @@ +// CHECK:        -:    0:Source:{{.*}}Inputs/instrprof-dlopen-dlclose-main.c +// CHECK-NEXT:        -:    0:Graph:instrprof-dlopen-dlclose-main.gcno +// CHECK-NEXT:        -:    0:Data:instrprof-dlopen-dlclose-main.gcda +// CHECK-NEXT:        -:    0:Runs:1 +// CHECK-NEXT:        -:    0:Programs:1 +// CHECK-NEXT:        -:    1:#include <dlfcn.h> +// CHECK-NEXT:        -:    2:#include <stdio.h> +// CHECK-NEXT:        -:    3:#include <stdlib.h> +// CHECK-NEXT:        -:    4: +// CHECK-NEXT:        -:    5:int main(int argc, char *argv[]) { +// CHECK-NEXT:        1:    6:  dlerror(); +// CHECK-NEXT:        1:    7:  void *f1_handle = dlopen("func.shared", RTLD_LAZY | RTLD_GLOBAL); +// CHECK-NEXT:        1:    8:  if (f1_handle == NULL) { +// CHECK-NEXT:    #####:    9:    fprintf(stderr, "unable to open 'func.shared': %s\n", dlerror()); +// CHECK-NEXT:    #####:   10:    return EXIT_FAILURE; +// CHECK-NEXT:        -:   11:  } +// CHECK-NEXT:        -:   12: +// CHECK-NEXT:        1:   13:  void (*func)(void) = (void (*)(void))dlsym(f1_handle, "func"); +// CHECK-NEXT:        1:   14:  if (func == NULL) { +// CHECK-NEXT:    #####:   15:    fprintf(stderr, "unable to lookup symbol 'func': %s\n", dlerror()); +// CHECK-NEXT:    #####:   16:    return EXIT_FAILURE; +// CHECK-NEXT:        -:   17:  } +// CHECK-NEXT:        -:   18: +// CHECK-NEXT:        1:   19:  dlerror(); +// CHECK-NEXT:        1:   20:  void *f2_handle = dlopen("func2.shared", RTLD_LAZY | RTLD_GLOBAL); +// CHECK-NEXT:        1:   21:  if (f2_handle == NULL) { +// CHECK-NEXT:    #####:   22:    fprintf(stderr, "unable to open 'func2.shared': %s\n", dlerror()); +// CHECK-NEXT:    #####:   23:    return EXIT_FAILURE; +// CHECK-NEXT:        -:   24:  } +// CHECK-NEXT:        -:   25: +// CHECK-NEXT:        1:   26:  void (*func2)(void) = (void (*)(void))dlsym(f2_handle, "func2"); +// CHECK-NEXT:        1:   27:  if (func2 == NULL) { +// CHECK-NEXT:    #####:   28:    fprintf(stderr, "unable to lookup symbol 'func2': %s\n", dlerror()); +// CHECK-NEXT:    #####:   29:    return EXIT_FAILURE; +// CHECK-NEXT:        -:   30:  } +// CHECK-NEXT:        1:   31:  func2(); +// CHECK-NEXT:        -:   32: +// CHECK-NEXT:        -:   33:#ifdef USE_LIB3 +// CHECK-NEXT:        -:   34:  void *f3_handle = dlopen("func3.shared", RTLD_LAZY | RTLD_GLOBAL); +// CHECK-NEXT:        -:   35:  if (f3_handle == NULL) { +// CHECK-NEXT:        -:   36:    fprintf(stderr, "unable to open 'func3.shared': %s\n", dlerror()); +// CHECK-NEXT:        -:   37:    return EXIT_FAILURE; +// CHECK-NEXT:        -:   38:  } +// CHECK-NEXT:        -:   39: +// CHECK-NEXT:        -:   40:  void (*func3)(void) = (void (*)(void))dlsym(f3_handle, "func3"); +// CHECK-NEXT:        -:   41:  if (func3 == NULL) { +// CHECK-NEXT:        -:   42:    fprintf(stderr, "unable to lookup symbol 'func3': %s\n", dlerror()); +// CHECK-NEXT:        -:   43:    return EXIT_FAILURE; +// CHECK-NEXT:        -:   44:  } +// CHECK-NEXT:        -:   45:  func3(); +// CHECK-NEXT:        -:   46:#endif +// CHECK-NEXT:        -:   47: +// CHECK-NEXT:        1:   48:  dlerror(); +// CHECK-NEXT:        1:   49:  void (*gcov_flush1)() = (void (*)())dlsym(f1_handle, "__gcov_flush"); +// CHECK-NEXT:        1:   50:  if (gcov_flush1 == NULL) { +// CHECK-NEXT:    #####:   51:    fprintf(stderr, "unable to find __gcov_flush in func.shared': %s\n", dlerror()); +// CHECK-NEXT:    #####:   52:    return EXIT_FAILURE; +// CHECK-NEXT:        -:   53:  } +// CHECK-NEXT:        -:   54: +// CHECK-NEXT:        1:   55:  dlerror(); +// CHECK-NEXT:        1:   56:  void (*gcov_flush2)() = (void (*)())dlsym(f2_handle, "__gcov_flush"); +// CHECK-NEXT:        1:   57:  if (gcov_flush2 == NULL) { +// CHECK-NEXT:    #####:   58:    fprintf(stderr, "unable to find __gcov_flush in func2.shared': %s\n", dlerror()); +// CHECK-NEXT:    #####:   59:    return EXIT_FAILURE; +// CHECK-NEXT:        -:   60:  } +// CHECK-NEXT:        -:   61: +// CHECK-NEXT:        1:   62:  if (gcov_flush1 == gcov_flush2) { +// CHECK-NEXT:    #####:   63:    fprintf(stderr, "Same __gcov_flush found in func.shared and func2.shared\n"); +// CHECK-NEXT:    #####:   64:    return EXIT_FAILURE; +// CHECK-NEXT:        -:   65:  } +// CHECK-NEXT:        -:   66: +// CHECK-NEXT:        1:   67:  dlerror(); +// CHECK-NEXT:        1:   68:  if (dlclose(f2_handle) != 0) { +// CHECK-NEXT:    #####:   69:    fprintf(stderr, "unable to close 'func2.shared': %s\n", dlerror()); +// CHECK-NEXT:    #####:   70:    return EXIT_FAILURE; +// CHECK-NEXT:        -:   71:  } +// CHECK-NEXT:        -:   72: +// CHECK-NEXT:        1:   73:  func(); +// CHECK-NEXT:        -:   74: +// CHECK-NEXT:        1:   75:  int g1 = 0; +// CHECK-NEXT:        1:   76:  int g2 = 0; +// CHECK-NEXT:        1:   77:  int n = 10; +// CHECK-NEXT:        -:   78: +// CHECK-NEXT:        1:   79:  if (n % 5 == 0) +// CHECK-NEXT:        1:   80:    g1++; +// CHECK-NEXT:        -:   81:  else +// CHECK-NEXT:    #####:   82:    g2++; +// CHECK-NEXT:        -:   83: +// CHECK-NEXT:        1:   84:  return EXIT_SUCCESS; +// CHECK-NEXT:        1:   85:} +// CHECK-NEXT:        -:   86: diff --git a/test/profile/Inputs/instrprof-dlopen-dlclose-main_three-libs.c.gcov b/test/profile/Inputs/instrprof-dlopen-dlclose-main_three-libs.c.gcov new file mode 100644 index 0000000000000..97eef4c3b9056 --- /dev/null +++ b/test/profile/Inputs/instrprof-dlopen-dlclose-main_three-libs.c.gcov @@ -0,0 +1,91 @@ +// CHECK:        -:    0:Source:{{.*}}Inputs/instrprof-dlopen-dlclose-main.c +// CHECK-NEXT:        -:    0:Graph:instrprof-dlopen-dlclose-main.gcno +// CHECK-NEXT:        -:    0:Data:instrprof-dlopen-dlclose-main.gcda +// CHECK-NEXT:        -:    0:Runs:1 +// CHECK-NEXT:        -:    0:Programs:1 +// CHECK-NEXT:        -:    1:#include <dlfcn.h> +// CHECK-NEXT:        -:    2:#include <stdio.h> +// CHECK-NEXT:        -:    3:#include <stdlib.h> +// CHECK-NEXT:        -:    4: +// CHECK-NEXT:        -:    5:int main(int argc, char *argv[]) { +// CHECK-NEXT:        1:    6:  dlerror(); +// CHECK-NEXT:        1:    7:  void *f1_handle = dlopen("func.shared", RTLD_LAZY | RTLD_GLOBAL); +// CHECK-NEXT:        1:    8:  if (f1_handle == NULL) { +// CHECK-NEXT:    #####:    9:    fprintf(stderr, "unable to open 'func.shared': %s\n", dlerror()); +// CHECK-NEXT:    #####:   10:    return EXIT_FAILURE; +// CHECK-NEXT:        -:   11:  } +// CHECK-NEXT:        -:   12: +// CHECK-NEXT:        1:   13:  void (*func)(void) = (void (*)(void))dlsym(f1_handle, "func"); +// CHECK-NEXT:        1:   14:  if (func == NULL) { +// CHECK-NEXT:    #####:   15:    fprintf(stderr, "unable to lookup symbol 'func': %s\n", dlerror()); +// CHECK-NEXT:    #####:   16:    return EXIT_FAILURE; +// CHECK-NEXT:        -:   17:  } +// CHECK-NEXT:        -:   18: +// CHECK-NEXT:        1:   19:  dlerror(); +// CHECK-NEXT:        1:   20:  void *f2_handle = dlopen("func2.shared", RTLD_LAZY | RTLD_GLOBAL); +// CHECK-NEXT:        1:   21:  if (f2_handle == NULL) { +// CHECK-NEXT:    #####:   22:    fprintf(stderr, "unable to open 'func2.shared': %s\n", dlerror()); +// CHECK-NEXT:    #####:   23:    return EXIT_FAILURE; +// CHECK-NEXT:        -:   24:  } +// CHECK-NEXT:        -:   25: +// CHECK-NEXT:        1:   26:  void (*func2)(void) = (void (*)(void))dlsym(f2_handle, "func2"); +// CHECK-NEXT:        1:   27:  if (func2 == NULL) { +// CHECK-NEXT:    #####:   28:    fprintf(stderr, "unable to lookup symbol 'func2': %s\n", dlerror()); +// CHECK-NEXT:    #####:   29:    return EXIT_FAILURE; +// CHECK-NEXT:        -:   30:  } +// CHECK-NEXT:        1:   31:  func2(); +// CHECK-NEXT:        -:   32: +// CHECK-NEXT:        -:   33:#ifdef USE_LIB3 +// CHECK-NEXT:        1:   34:  void *f3_handle = dlopen("func3.shared", RTLD_LAZY | RTLD_GLOBAL); +// CHECK-NEXT:        1:   35:  if (f3_handle == NULL) { +// CHECK-NEXT:    #####:   36:    fprintf(stderr, "unable to open 'func3.shared': %s\n", dlerror()); +// CHECK-NEXT:    #####:   37:    return EXIT_FAILURE; +// CHECK-NEXT:        -:   38:  } +// CHECK-NEXT:        -:   39: +// CHECK-NEXT:        1:   40:  void (*func3)(void) = (void (*)(void))dlsym(f3_handle, "func3"); +// CHECK-NEXT:        1:   41:  if (func3 == NULL) { +// CHECK-NEXT:    #####:   42:    fprintf(stderr, "unable to lookup symbol 'func3': %s\n", dlerror()); +// CHECK-NEXT:    #####:   43:    return EXIT_FAILURE; +// CHECK-NEXT:        -:   44:  } +// CHECK-NEXT:        1:   45:  func3(); +// CHECK-NEXT:        -:   46:#endif +// CHECK-NEXT:        -:   47: +// CHECK-NEXT:        1:   48:  dlerror(); +// CHECK-NEXT:        1:   49:  void (*gcov_flush1)() = (void (*)())dlsym(f1_handle, "__gcov_flush"); +// CHECK-NEXT:        1:   50:  if (gcov_flush1 == NULL) { +// CHECK-NEXT:    #####:   51:    fprintf(stderr, "unable to find __gcov_flush in func.shared': %s\n", dlerror()); +// CHECK-NEXT:    #####:   52:    return EXIT_FAILURE; +// CHECK-NEXT:        -:   53:  } +// CHECK-NEXT:        -:   54: +// CHECK-NEXT:        1:   55:  dlerror(); +// CHECK-NEXT:        1:   56:  void (*gcov_flush2)() = (void (*)())dlsym(f2_handle, "__gcov_flush"); +// CHECK-NEXT:        1:   57:  if (gcov_flush2 == NULL) { +// CHECK-NEXT:    #####:   58:    fprintf(stderr, "unable to find __gcov_flush in func2.shared': %s\n", dlerror()); +// CHECK-NEXT:    #####:   59:    return EXIT_FAILURE; +// CHECK-NEXT:        -:   60:  } +// CHECK-NEXT:        -:   61: +// CHECK-NEXT:        1:   62:  if (gcov_flush1 == gcov_flush2) { +// CHECK-NEXT:    #####:   63:    fprintf(stderr, "Same __gcov_flush found in func.shared and func2.shared\n"); +// CHECK-NEXT:    #####:   64:    return EXIT_FAILURE; +// CHECK-NEXT:        -:   65:  } +// CHECK-NEXT:        -:   66: +// CHECK-NEXT:        1:   67:  dlerror(); +// CHECK-NEXT:        1:   68:  if (dlclose(f2_handle) != 0) { +// CHECK-NEXT:    #####:   69:    fprintf(stderr, "unable to close 'func2.shared': %s\n", dlerror()); +// CHECK-NEXT:    #####:   70:    return EXIT_FAILURE; +// CHECK-NEXT:        -:   71:  } +// CHECK-NEXT:        -:   72: +// CHECK-NEXT:        1:   73:  func(); +// CHECK-NEXT:        -:   74: +// CHECK-NEXT:        1:   75:  int g1 = 0; +// CHECK-NEXT:        1:   76:  int g2 = 0; +// CHECK-NEXT:        1:   77:  int n = 10; +// CHECK-NEXT:        -:   78: +// CHECK-NEXT:        1:   79:  if (n % 5 == 0) +// CHECK-NEXT:        1:   80:    g1++; +// CHECK-NEXT:        -:   81:  else +// CHECK-NEXT:    #####:   82:    g2++; +// CHECK-NEXT:        -:   83: +// CHECK-NEXT:        1:   84:  return EXIT_SUCCESS; +// CHECK-NEXT:        1:   85:} +// CHECK-NEXT:        -:   86: diff --git a/test/profile/Inputs/instrprof-dlopen-func.c b/test/profile/Inputs/instrprof-dlopen-func.c index f2de3883535a4..9a56e4976570f 100644 --- a/test/profile/Inputs/instrprof-dlopen-func.c +++ b/test/profile/Inputs/instrprof-dlopen-func.c @@ -1 +1 @@ -void func(int K) { if (K) {} } +void func(int K) {} diff --git a/test/profile/Inputs/instrprof-dlopen-func.c.gcov b/test/profile/Inputs/instrprof-dlopen-func.c.gcov new file mode 100644 index 0000000000000..3af4ec94a1b01 --- /dev/null +++ b/test/profile/Inputs/instrprof-dlopen-func.c.gcov @@ -0,0 +1,6 @@ +// CHECK:        -:    0:Source:{{.*}}Inputs/instrprof-dlopen-func.c +// CHECK-NEXT:        -:    0:Graph:instrprof-dlopen-func.gcno +// CHECK-NEXT:        -:    0:Data:instrprof-dlopen-func.gcda +// CHECK-NEXT:        -:    0:Runs:1 +// CHECK-NEXT:        -:    0:Programs:1 +// CHECK-NEXT:        1:    1:void func(int K) {} diff --git a/test/profile/Inputs/instrprof-dlopen-func2.c b/test/profile/Inputs/instrprof-dlopen-func2.c index d4d93dc0b2565..ab62f14952c77 100644 --- a/test/profile/Inputs/instrprof-dlopen-func2.c +++ b/test/profile/Inputs/instrprof-dlopen-func2.c @@ -1 +1 @@ -void func2(int K) { if (K) {} } +void func2(int K) {} diff --git a/test/profile/Inputs/instrprof-dlopen-func2.c.gcov b/test/profile/Inputs/instrprof-dlopen-func2.c.gcov new file mode 100644 index 0000000000000..7101f74b938d6 --- /dev/null +++ b/test/profile/Inputs/instrprof-dlopen-func2.c.gcov @@ -0,0 +1,6 @@ +// CHECK:        -:    0:Source:{{.*}}Inputs/instrprof-dlopen-func2.c +// CHECK-NEXT:        -:    0:Graph:instrprof-dlopen-func2.gcno +// CHECK-NEXT:        -:    0:Data:instrprof-dlopen-func2.gcda +// CHECK-NEXT:        -:    0:Runs:1 +// CHECK-NEXT:        -:    0:Programs:1 +// CHECK-NEXT:        1:    1:void func2(int K) {} diff --git a/test/profile/Inputs/instrprof-dlopen-func3.c b/test/profile/Inputs/instrprof-dlopen-func3.c new file mode 100644 index 0000000000000..ec0dddb45274f --- /dev/null +++ b/test/profile/Inputs/instrprof-dlopen-func3.c @@ -0,0 +1 @@ +void func3(int K) {} diff --git a/test/profile/Inputs/instrprof-dlopen-func3.c.gcov b/test/profile/Inputs/instrprof-dlopen-func3.c.gcov new file mode 100644 index 0000000000000..7101f74b938d6 --- /dev/null +++ b/test/profile/Inputs/instrprof-dlopen-func3.c.gcov @@ -0,0 +1,6 @@ +// CHECK:        -:    0:Source:{{.*}}Inputs/instrprof-dlopen-func2.c +// CHECK-NEXT:        -:    0:Graph:instrprof-dlopen-func2.gcno +// CHECK-NEXT:        -:    0:Data:instrprof-dlopen-func2.gcda +// CHECK-NEXT:        -:    0:Runs:1 +// CHECK-NEXT:        -:    0:Programs:1 +// CHECK-NEXT:        1:    1:void func2(int K) {} diff --git a/test/profile/Inputs/instrprof-gcov-__gcov_flush-terminate.c b/test/profile/Inputs/instrprof-gcov-__gcov_flush-terminate.c new file mode 100644 index 0000000000000..7b24d69c75fcb --- /dev/null +++ b/test/profile/Inputs/instrprof-gcov-__gcov_flush-terminate.c @@ -0,0 +1,13 @@ +int main(void) { +  int i = 22; + +  __gcov_flush(); + +  i = 42; + +  asm("int $3"); + +  i = 84; + +  return 0; +} diff --git a/test/profile/Inputs/instrprof-gcov-__gcov_flush-terminate.c.gcov b/test/profile/Inputs/instrprof-gcov-__gcov_flush-terminate.c.gcov new file mode 100644 index 0000000000000..69e229a3127ed --- /dev/null +++ b/test/profile/Inputs/instrprof-gcov-__gcov_flush-terminate.c.gcov @@ -0,0 +1,18 @@ +// CHECK:        -:    0:Source:{{.*}}Inputs/instrprof-gcov-__gcov_flush-terminate.c +// CHECK-NEXT:        -:    0:Graph:instrprof-gcov-__gcov_flush-terminate.gcno +// CHECK-NEXT:        -:    0:Data:instrprof-gcov-__gcov_flush-terminate.gcda +// CHECK-NEXT:        -:    0:Runs:1 +// CHECK-NEXT:        -:    0:Programs:1 +// CHECK-NEXT:        -:    1:int main(void) { +// CHECK-NEXT:        1:    2:  int i = 22; +// CHECK-NEXT:        -:    3: +// CHECK-NEXT:        1:    4:  __gcov_flush(); +// CHECK-NEXT:        -:    5: +// CHECK-NEXT:    #####:    6:  i = 42; +// CHECK-NEXT:        -:    7: +// CHECK-NEXT:    #####:    8:  asm("int $3"); +// CHECK-NEXT:        -:    9: +// CHECK-NEXT:    #####:   10:  i = 84; +// CHECK-NEXT:        -:   11: +// CHECK-NEXT:    #####:   12:  return 0; +// CHECK-NEXT:        -:   13:} diff --git a/test/profile/Inputs/instrprof-gcov-exceptions.cpp b/test/profile/Inputs/instrprof-gcov-exceptions.cpp new file mode 100644 index 0000000000000..327966551d097 --- /dev/null +++ b/test/profile/Inputs/instrprof-gcov-exceptions.cpp @@ -0,0 +1,11 @@ +#include <string> + +void asd(std::string i) { +} + +int main(void) +{ +  asd("22"); + +  return 0; +} diff --git a/test/profile/Inputs/instrprof-gcov-exceptions.cpp.gcov b/test/profile/Inputs/instrprof-gcov-exceptions.cpp.gcov new file mode 100644 index 0000000000000..7caf50806020b --- /dev/null +++ b/test/profile/Inputs/instrprof-gcov-exceptions.cpp.gcov @@ -0,0 +1,16 @@ +// CHECK:        -:    0:Source:{{.*}}Inputs/instrprof-gcov-exceptions.cpp +// CHECK-NEXT:        -:    0:Graph:instrprof-gcov-exceptions.gcno +// CHECK-NEXT:        -:    0:Data:instrprof-gcov-exceptions.gcda +// CHECK-NEXT:        -:    0:Runs:1 +// CHECK-NEXT:        -:    0:Programs:1 +// CHECK-NEXT:        -:    1:#include <string> +// CHECK-NEXT:        -:    2: +// CHECK-NEXT:        -:    3:void asd(std::string i) { +// CHECK-NEXT:        2:    4:} +// CHECK-NEXT:        -:    5: +// CHECK-NEXT:        -:    6:int main(void) +// CHECK-NEXT:        -:    7:{ +// CHECK-NEXT:        1:    8:  asd("22"); +// CHECK-NEXT:        -:    9: +// CHECK-NEXT:        1:   10:  return 0; +// CHECK-NEXT:        -:   11:} diff --git a/test/profile/Inputs/instrprof-gcov-multiple-bbs-single-line.c b/test/profile/Inputs/instrprof-gcov-multiple-bbs-single-line.c new file mode 100644 index 0000000000000..a2e187b5cb61f --- /dev/null +++ b/test/profile/Inputs/instrprof-gcov-multiple-bbs-single-line.c @@ -0,0 +1,20 @@ +int main(void) +{ +  int var; + +  int a = 1; +  if (a) { +    var++; +  } + +  if (a) {} + +  int b = 0; +  if (b) { +    var++; +  } + +  if (b) {} + +  return 0; +} diff --git a/test/profile/Inputs/instrprof-gcov-multiple-bbs-single-line.c.gcov b/test/profile/Inputs/instrprof-gcov-multiple-bbs-single-line.c.gcov new file mode 100644 index 0000000000000..92532af306740 --- /dev/null +++ b/test/profile/Inputs/instrprof-gcov-multiple-bbs-single-line.c.gcov @@ -0,0 +1,34 @@ +// CHECK:        -:    0:Source:{{.*}}Inputs/instrprof-gcov-multiple-bbs-single-line.c +// CHECK-NEXT:        -:    0:Graph:instrprof-gcov-multiple-bbs-single-line.gcno +// CHECK-NEXT:        -:    0:Data:instrprof-gcov-multiple-bbs-single-line.gcda +// CHECK-NEXT:        -:    0:Runs:1 +// CHECK-NEXT:        -:    0:Programs:1 +// CHECK-NEXT:function main called 1 returned 100% blocks executed 80% +// CHECK-NEXT:        -:    1:int main(void) +// CHECK-NEXT:        -:    2:{ +// CHECK-NEXT:        -:    3:  int var; +// CHECK-NEXT:        -:    4: +// CHECK-NEXT:        1:    5:  int a = 1; +// CHECK-NEXT:        1:    6:  if (a) { +// CHECK-NEXT:branch  0 taken 1 +// CHECK-NEXT:branch  1 taken 0 +// CHECK-NEXT:        1:    7:    var++; +// CHECK-NEXT:        1:    8:  } +// CHECK-NEXT:        -:    9: +// CHECK-NEXT:        1:   10:  if (a) {} +// CHECK-NEXT:branch  0 taken 1 +// CHECK-NEXT:branch  1 taken 0 +// CHECK-NEXT:        -:   11: +// CHECK-NEXT:        1:   12:  int b = 0; +// CHECK-NEXT:        1:   13:  if (b) { +// CHECK-NEXT:branch  0 taken 0 +// CHECK-NEXT:branch  1 taken 1 +// CHECK-NEXT:    #####:   14:    var++; +// CHECK-NEXT:    #####:   15:  } +// CHECK-NEXT:        -:   16: +// CHECK-NEXT:        1:   17:  if (b) {} +// CHECK-NEXT:branch  0 taken 0 +// CHECK-NEXT:branch  1 taken 1 +// CHECK-NEXT:        -:   18: +// CHECK-NEXT:        1:   19:  return 0; +// CHECK-NEXT:        -:   20:} diff --git a/test/profile/Inputs/instrprof-shared-lib.c.gcov b/test/profile/Inputs/instrprof-shared-lib.c.gcov new file mode 100644 index 0000000000000..fbc43d5f7d504 --- /dev/null +++ b/test/profile/Inputs/instrprof-shared-lib.c.gcov @@ -0,0 +1,14 @@ +// CHECK:        -:    0:Source:{{.*}}Inputs/instrprof-shared-lib.c +// CHECK-NEXT:        -:    0:Graph:instrprof-shared-lib.gcno +// CHECK-NEXT:        -:    0:Data:instrprof-shared-lib.gcda +// CHECK-NEXT:        -:    0:Runs:1 +// CHECK-NEXT:        -:    0:Programs:1 +// CHECK-NEXT:        -:    1:int g1 = 0; +// CHECK-NEXT:        -:    2:int g2 = 1; +// CHECK-NEXT:        -:    3: +// CHECK-NEXT:        -:    4:void foo(int n) { +// CHECK-NEXT:        1:    5:  if (n % 5 == 0) +// CHECK-NEXT:    #####:    6:    g1++; +// CHECK-NEXT:        -:    7:  else +// CHECK-NEXT:        1:    8:    g2++; +// CHECK-NEXT:        1:    9:} diff --git a/test/profile/Inputs/instrprof-shared-lib_called-twice.c.gcov b/test/profile/Inputs/instrprof-shared-lib_called-twice.c.gcov new file mode 100644 index 0000000000000..779c885d862d0 --- /dev/null +++ b/test/profile/Inputs/instrprof-shared-lib_called-twice.c.gcov @@ -0,0 +1,14 @@ +// CHECK:        -:    0:Source:{{.*}}Inputs/instrprof-shared-lib.c +// CHECK-NEXT:        -:    0:Graph:instrprof-shared-lib.gcno +// CHECK-NEXT:        -:    0:Data:instrprof-shared-lib.gcda +// CHECK-NEXT:        -:    0:Runs:1 +// CHECK-NEXT:        -:    0:Programs:1 +// CHECK-NEXT:        -:    1:int g1 = 0; +// CHECK-NEXT:        -:    2:int g2 = 1; +// CHECK-NEXT:        -:    3: +// CHECK-NEXT:        -:    4:void foo(int n) { +// CHECK-NEXT:        2:    5:  if (n % 5 == 0) +// CHECK-NEXT:    #####:    6:    g1++; +// CHECK-NEXT:        -:    7:  else +// CHECK-NEXT:        2:    8:    g2++; +// CHECK-NEXT:        2:    9:} diff --git a/test/profile/Inputs/instrprof-shared-lib_in-loop.c.gcov b/test/profile/Inputs/instrprof-shared-lib_in-loop.c.gcov new file mode 100644 index 0000000000000..76503d91426e3 --- /dev/null +++ b/test/profile/Inputs/instrprof-shared-lib_in-loop.c.gcov @@ -0,0 +1,14 @@ +// CHECK:        -:    0:Source:{{.*}}Inputs/instrprof-shared-lib.c +// CHECK-NEXT:        -:    0:Graph:instrprof-shared-lib.gcno +// CHECK-NEXT:        -:    0:Data:instrprof-shared-lib.gcda +// CHECK-NEXT:        -:    0:Runs:1 +// CHECK-NEXT:        -:    0:Programs:1 +// CHECK-NEXT:        -:    1:int g1 = 0; +// CHECK-NEXT:        -:    2:int g2 = 1; +// CHECK-NEXT:        -:    3: +// CHECK-NEXT:        -:    4:void foo(int n) { +// CHECK-NEXT:  1000000:    5:  if (n % 5 == 0) +// CHECK-NEXT:   360000:    6:    g1++; +// CHECK-NEXT:        -:    7:  else +// CHECK-NEXT:   640000:    8:    g2++; +// CHECK-NEXT:  1000000:    9:} diff --git a/test/profile/Inputs/instrprof-shared-main-gcov-flush.c b/test/profile/Inputs/instrprof-shared-main-gcov-flush.c new file mode 100644 index 0000000000000..9f41b7e6362aa --- /dev/null +++ b/test/profile/Inputs/instrprof-shared-main-gcov-flush.c @@ -0,0 +1,36 @@ +extern void foo(int n); +extern void __gcov_flush(void); + +int bar1 = 0; +int bar2 = 1; + +void bar(int n) { +  if (n % 5 == 0) +    bar1++; +  else +    bar2++; +} + +int main(int argc, char *argv[]) { +#ifdef SHARED_CALL_BEFORE_GCOV_FLUSH +  foo(1); +#endif + +  bar(5); + +  __gcov_flush(); + +  bar(5); + +#ifdef SHARED_CALL_AFTER_GCOV_FLUSH +  foo(1); +#endif + +#ifdef EXIT_ABRUPTLY +  _exit(0); +#endif + +  bar(5); + +  return 0; +} diff --git a/test/profile/Inputs/instrprof-shared-main-gcov-flush_no-writeout.c.gcov b/test/profile/Inputs/instrprof-shared-main-gcov-flush_no-writeout.c.gcov new file mode 100644 index 0000000000000..b2dfe2acde67b --- /dev/null +++ b/test/profile/Inputs/instrprof-shared-main-gcov-flush_no-writeout.c.gcov @@ -0,0 +1,41 @@ +// CHECK:        -:    0:Source:{{.*}}Inputs/instrprof-shared-main-gcov-flush.c +// CHECK-NEXT:        -:    0:Graph:instrprof-shared-main-gcov-flush.gcno +// CHECK-NEXT:        -:    0:Data:instrprof-shared-main-gcov-flush.gcda +// CHECK-NEXT:        -:    0:Runs:1 +// CHECK-NEXT:        -:    0:Programs:1 +// CHECK-NEXT:        -:    1:extern void foo(int n); +// CHECK-NEXT:        -:    2:extern void __gcov_flush(void); +// CHECK-NEXT:        -:    3: +// CHECK-NEXT:        -:    4:int bar1 = 0; +// CHECK-NEXT:        -:    5:int bar2 = 1; +// CHECK-NEXT:        -:    6: +// CHECK-NEXT:        -:    7:void bar(int n) { +// CHECK-NEXT:        1:    8:  if (n % 5 == 0) +// CHECK-NEXT:        1:    9:    bar1++; +// CHECK-NEXT:        -:   10:  else +// CHECK-NEXT:    #####:   11:    bar2++; +// CHECK-NEXT:        1:   12:} +// CHECK-NEXT:        -:   13: +// CHECK-NEXT:        -:   14:int main(int argc, char *argv[]) { +// CHECK-NEXT:        -:   15:#ifdef SHARED_CALL_BEFORE_GCOV_FLUSH +// CHECK-NEXT:        1:   16:  foo(1); +// CHECK-NEXT:        -:   17:#endif +// CHECK-NEXT:        -:   18: +// CHECK-NEXT:        1:   19:  bar(5); +// CHECK-NEXT:        -:   20: +// CHECK-NEXT:        1:   21:  __gcov_flush(); +// CHECK-NEXT:        -:   22: +// CHECK-NEXT:        1:   23:  bar(5); +// CHECK-NEXT:        -:   24: +// CHECK-NEXT:        -:   25:#ifdef SHARED_CALL_AFTER_GCOV_FLUSH +// CHECK-NEXT:        1:   26:  foo(1); +// CHECK-NEXT:        -:   27:#endif +// CHECK-NEXT:        -:   28: +// CHECK-NEXT:        -:   29:#ifdef EXIT_ABRUPTLY +// CHECK-NEXT:        1:   30:  _exit(0); +// CHECK-NEXT:        -:   31:#endif +// CHECK-NEXT:        -:   32: +// CHECK-NEXT:        -:   33:  bar(5); +// CHECK-NEXT:        -:   34: +// CHECK-NEXT:        -:   35:  return 0; +// CHECK-NEXT:    #####:   36:} diff --git a/test/profile/Inputs/instrprof-shared-main-gcov-flush_shared-call-after.c.gcov b/test/profile/Inputs/instrprof-shared-main-gcov-flush_shared-call-after.c.gcov new file mode 100644 index 0000000000000..f70e34e528944 --- /dev/null +++ b/test/profile/Inputs/instrprof-shared-main-gcov-flush_shared-call-after.c.gcov @@ -0,0 +1,41 @@ +// CHECK:        -:    0:Source:{{.*}}Inputs/instrprof-shared-main-gcov-flush.c +// CHECK-NEXT:        -:    0:Graph:instrprof-shared-main-gcov-flush.gcno +// CHECK-NEXT:        -:    0:Data:instrprof-shared-main-gcov-flush.gcda +// CHECK-NEXT:        -:    0:Runs:1 +// CHECK-NEXT:        -:    0:Programs:1 +// CHECK-NEXT:        -:    1:extern void foo(int n); +// CHECK-NEXT:        -:    2:extern void __gcov_flush(void); +// CHECK-NEXT:        -:    3: +// CHECK-NEXT:        -:    4:int bar1 = 0; +// CHECK-NEXT:        -:    5:int bar2 = 1; +// CHECK-NEXT:        -:    6: +// CHECK-NEXT:        -:    7:void bar(int n) { +// CHECK-NEXT:        3:    8:  if (n % 5 == 0) +// CHECK-NEXT:        3:    9:    bar1++; +// CHECK-NEXT:        -:   10:  else +// CHECK-NEXT:    #####:   11:    bar2++; +// CHECK-NEXT:        3:   12:} +// CHECK-NEXT:        -:   13: +// CHECK-NEXT:        -:   14:int main(int argc, char *argv[]) { +// CHECK-NEXT:        -:   15:#ifdef SHARED_CALL_BEFORE_GCOV_FLUSH +// CHECK-NEXT:        -:   16:  foo(1); +// CHECK-NEXT:        -:   17:#endif +// CHECK-NEXT:        -:   18: +// CHECK-NEXT:        1:   19:  bar(5); +// CHECK-NEXT:        -:   20: +// CHECK-NEXT:        1:   21:  __gcov_flush(); +// CHECK-NEXT:        -:   22: +// CHECK-NEXT:        1:   23:  bar(5); +// CHECK-NEXT:        -:   24: +// CHECK-NEXT:        -:   25:#ifdef SHARED_CALL_AFTER_GCOV_FLUSH +// CHECK-NEXT:        1:   26:  foo(1); +// CHECK-NEXT:        -:   27:#endif +// CHECK-NEXT:        -:   28: +// CHECK-NEXT:        -:   29:#ifdef EXIT_ABRUPTLY +// CHECK-NEXT:        -:   30:  _exit(0); +// CHECK-NEXT:        -:   31:#endif +// CHECK-NEXT:        -:   32: +// CHECK-NEXT:        1:   33:  bar(5); +// CHECK-NEXT:        -:   34: +// CHECK-NEXT:        1:   35:  return 0; +// CHECK-NEXT:        -:   36:} diff --git a/test/profile/Inputs/instrprof-shared-main-gcov-flush_shared-call-before-after.c.gcov b/test/profile/Inputs/instrprof-shared-main-gcov-flush_shared-call-before-after.c.gcov new file mode 100644 index 0000000000000..b9ecff6987229 --- /dev/null +++ b/test/profile/Inputs/instrprof-shared-main-gcov-flush_shared-call-before-after.c.gcov @@ -0,0 +1,41 @@ +// CHECK:        -:    0:Source:{{.*}}Inputs/instrprof-shared-main-gcov-flush.c +// CHECK-NEXT:        -:    0:Graph:instrprof-shared-main-gcov-flush.gcno +// CHECK-NEXT:        -:    0:Data:instrprof-shared-main-gcov-flush.gcda +// CHECK-NEXT:        -:    0:Runs:1 +// CHECK-NEXT:        -:    0:Programs:1 +// CHECK-NEXT:        -:    1:extern void foo(int n); +// CHECK-NEXT:        -:    2:extern void __gcov_flush(void); +// CHECK-NEXT:        -:    3: +// CHECK-NEXT:        -:    4:int bar1 = 0; +// CHECK-NEXT:        -:    5:int bar2 = 1; +// CHECK-NEXT:        -:    6: +// CHECK-NEXT:        -:    7:void bar(int n) { +// CHECK-NEXT:        3:    8:  if (n % 5 == 0) +// CHECK-NEXT:        3:    9:    bar1++; +// CHECK-NEXT:        -:   10:  else +// CHECK-NEXT:    #####:   11:    bar2++; +// CHECK-NEXT:        3:   12:} +// CHECK-NEXT:        -:   13: +// CHECK-NEXT:        -:   14:int main(int argc, char *argv[]) { +// CHECK-NEXT:        -:   15:#ifdef SHARED_CALL_BEFORE_GCOV_FLUSH +// CHECK-NEXT:        1:   16:  foo(1); +// CHECK-NEXT:        -:   17:#endif +// CHECK-NEXT:        -:   18: +// CHECK-NEXT:        1:   19:  bar(5); +// CHECK-NEXT:        -:   20: +// CHECK-NEXT:        1:   21:  __gcov_flush(); +// CHECK-NEXT:        -:   22: +// CHECK-NEXT:        1:   23:  bar(5); +// CHECK-NEXT:        -:   24: +// CHECK-NEXT:        -:   25:#ifdef SHARED_CALL_AFTER_GCOV_FLUSH +// CHECK-NEXT:        1:   26:  foo(1); +// CHECK-NEXT:        -:   27:#endif +// CHECK-NEXT:        -:   28: +// CHECK-NEXT:        -:   29:#ifdef EXIT_ABRUPTLY +// CHECK-NEXT:        -:   30:  _exit(0); +// CHECK-NEXT:        -:   31:#endif +// CHECK-NEXT:        -:   32: +// CHECK-NEXT:        1:   33:  bar(5); +// CHECK-NEXT:        -:   34: +// CHECK-NEXT:        1:   35:  return 0; +// CHECK-NEXT:        -:   36:} diff --git a/test/profile/Inputs/instrprof-shared-main-gcov-flush_shared-call-before.c.gcov b/test/profile/Inputs/instrprof-shared-main-gcov-flush_shared-call-before.c.gcov new file mode 100644 index 0000000000000..7c9e0afa11b21 --- /dev/null +++ b/test/profile/Inputs/instrprof-shared-main-gcov-flush_shared-call-before.c.gcov @@ -0,0 +1,41 @@ +// CHECK:        -:    0:Source:{{.*}}Inputs/instrprof-shared-main-gcov-flush.c +// CHECK-NEXT:        -:    0:Graph:instrprof-shared-main-gcov-flush.gcno +// CHECK-NEXT:        -:    0:Data:instrprof-shared-main-gcov-flush.gcda +// CHECK-NEXT:        -:    0:Runs:1 +// CHECK-NEXT:        -:    0:Programs:1 +// CHECK-NEXT:        -:    1:extern void foo(int n); +// CHECK-NEXT:        -:    2:extern void __gcov_flush(void); +// CHECK-NEXT:        -:    3: +// CHECK-NEXT:        -:    4:int bar1 = 0; +// CHECK-NEXT:        -:    5:int bar2 = 1; +// CHECK-NEXT:        -:    6: +// CHECK-NEXT:        -:    7:void bar(int n) { +// CHECK-NEXT:        3:    8:  if (n % 5 == 0) +// CHECK-NEXT:        3:    9:    bar1++; +// CHECK-NEXT:        -:   10:  else +// CHECK-NEXT:    #####:   11:    bar2++; +// CHECK-NEXT:        3:   12:} +// CHECK-NEXT:        -:   13: +// CHECK-NEXT:        -:   14:int main(int argc, char *argv[]) { +// CHECK-NEXT:        -:   15:#ifdef SHARED_CALL_BEFORE_GCOV_FLUSH +// CHECK-NEXT:        1:   16:  foo(1); +// CHECK-NEXT:        -:   17:#endif +// CHECK-NEXT:        -:   18: +// CHECK-NEXT:        1:   19:  bar(5); +// CHECK-NEXT:        -:   20: +// CHECK-NEXT:        1:   21:  __gcov_flush(); +// CHECK-NEXT:        -:   22: +// CHECK-NEXT:        1:   23:  bar(5); +// CHECK-NEXT:        -:   24: +// CHECK-NEXT:        -:   25:#ifdef SHARED_CALL_AFTER_GCOV_FLUSH +// CHECK-NEXT:        -:   26:  foo(1); +// CHECK-NEXT:        -:   27:#endif +// CHECK-NEXT:        -:   28: +// CHECK-NEXT:        -:   29:#ifdef EXIT_ABRUPTLY +// CHECK-NEXT:        -:   30:  _exit(0); +// CHECK-NEXT:        -:   31:#endif +// CHECK-NEXT:        -:   32: +// CHECK-NEXT:        1:   33:  bar(5); +// CHECK-NEXT:        -:   34: +// CHECK-NEXT:        1:   35:  return 0; +// CHECK-NEXT:        -:   36:} diff --git a/test/profile/Inputs/instrprof-shared-main.c.gcov b/test/profile/Inputs/instrprof-shared-main.c.gcov new file mode 100644 index 0000000000000..70be367507ff8 --- /dev/null +++ b/test/profile/Inputs/instrprof-shared-main.c.gcov @@ -0,0 +1,18 @@ +// CHECK:        -:    0:Source:{{.*}}Inputs/instrprof-shared-main.c +// CHECK-NEXT:        -:    0:Graph:instrprof-shared-main.gcno +// CHECK-NEXT:        -:    0:Data:instrprof-shared-main.gcda +// CHECK-NEXT:        -:    0:Runs:1 +// CHECK-NEXT:        -:    0:Programs:1 +// CHECK-NEXT:        -:    1:extern int g1, g2; +// CHECK-NEXT:        -:    2:extern void foo(int n); +// CHECK-NEXT:        -:    3: +// CHECK-NEXT:        -:    4:int main() { +// CHECK-NEXT:        -:    5:  int i, j; +// CHECK-NEXT:     2002:    6:  for (i = 0; i < 1000; i++) +// CHECK-NEXT:  2002000:    7:    for (j = 0; j < 1000; j++) +// CHECK-NEXT:  1001000:    8:      foo(i * j); +// CHECK-NEXT:        -:    9: +// CHECK-NEXT:        1:   10:  if (g2 - g1 == 280001) +// CHECK-NEXT:        1:   11:    return 0; +// CHECK-NEXT:    #####:   12:  return 1; +// CHECK-NEXT:        1:   13:} diff --git a/test/profile/Linux/counter_promo_nest.c b/test/profile/Linux/counter_promo_nest.c index 0792f0c76abbc..ebd52dda7f48b 100644 --- a/test/profile/Linux/counter_promo_nest.c +++ b/test/profile/Linux/counter_promo_nest.c @@ -25,6 +25,9 @@ int main()  // PROMO: load{{.*}}@__profc_main{{.*}}  // PROMO-NEXT: add  // PROMO-NEXT: store{{.*}}@__profc_main{{.*}} +// PROMO: load{{.*}}@__profc_main{{.*}} +// PROMO-NEXT: add +// PROMO-NEXT: store{{.*}}@__profc_main{{.*}}  // PROMO-NEXT: load{{.*}}@__profc_main{{.*}}  // PROMO-NEXT: add  // PROMO-NEXT: store{{.*}}@__profc_main{{.*}} diff --git a/test/profile/Linux/instrprof-value-merge.c b/test/profile/Linux/instrprof-value-merge.c new file mode 100644 index 0000000000000..902430a4a9686 --- /dev/null +++ b/test/profile/Linux/instrprof-value-merge.c @@ -0,0 +1,79 @@ +// RUN: %clang_pgogen -o %t -O3 %s +// RUN: rm -rf %t.profdir +// RUN: env LLVM_PROFILE_FILE=%t.profdir/default_%m.profraw %run %t +// RUN: env LLVM_PROFILE_FILE=%t.profdir/default_%m.profraw %run %t +// RUN: env LLVM_PROFILE_FILE=%t.profdir/default_%m.profraw %run %t +// RUN: env LLVM_PROFILE_FILE=%t.profdir/default_%m.profraw %run %t 1 +// RUN: env LLVM_PROFILE_FILE=%t.profdir/default_%m.profraw %run %t 1 +// RUN: llvm-profdata show -counts -function=main -ic-targets -memop-sizes %t.profdir/default_*.profraw | FileCheck %s + +#include <string.h> + +void (*f0)(); +void (*f1)(); +void (*f2)(); + +char dst[200]; +char src[200]; +volatile int n; + +__attribute__((noinline)) void foo() {} + +__attribute__((noinline)) void bar() { +  f0 = foo; +  f1 = foo; +  f2 = foo; +  n = 4; +} +int main(int argc, char *argv[]) { +  int i; +  bar(); +  if (argc == 1) { +    f0(); +    for (i = 0; i < 9; i++) +      f1(); +    for (i = 0; i < 99; i++) +      f2(); +  } else { +    memcpy((void *)dst, (void *)src, n); +    for (i = 0; i < 6; i++) +      memcpy((void *)(dst + 2), (void *)src, n + 1); +    for (i = 0; i < 66; i++) +      memcpy((void *)(dst + 9), (void *)src, n + 2); +  } +} + +// CHECK: Counters: +// CHECK:   main: +// CHECK:     Hash: 0x00030012a7ab6e87 +// CHECK:     Counters: 6 +// CHECK:     Indirect Call Site Count: 3 +// CHECK:     Number of Memory Intrinsics Calls: 3 +// CHECK:     Block counts: [27, 297, 12, 132, 3, 2] +// CHECK:     Indirect Target Results: +// CHECK:         [ 0, foo, 3 ] +// CHECK:         [ 1, foo, 27 ] +// CHECK:         [ 2, foo, 297 ] +// CHECK:     Memory Intrinsic Size Results: +// CHECK:         [ 0, 4, 2 ] +// CHECK:         [ 1, 5, 12 ] +// CHECK:         [ 2, 6, 132 ] +// CHECK: Instrumentation level: IR +// CHECK: Functions shown: 1 +// CHECK: Total functions: 3 +// CHECK: Maximum function count: 327 +// CHECK: Maximum internal block count: 297 +// CHECK: Statistics for indirect call sites profile: +// CHECK:   Total number of sites: 3 +// CHECK:   Total number of sites with values: 3 +// CHECK:   Total number of profiled values: 3 +// CHECK:   Value sites histogram: +// CHECK:         NumTargets, SiteCount +// CHECK:         1, 3 +// CHECK: Statistics for memory intrinsic calls sizes profile: +// CHECK:   Total number of sites: 3 +// CHECK:   Total number of sites with values: 3 +// CHECK:   Total number of profiled values: 3 +// CHECK:   Value sites histogram: +// CHECK:         NumTargets, SiteCount +// CHECK:         1, 3 diff --git a/test/profile/instrprof-darwin-dead-strip.c b/test/profile/instrprof-darwin-dead-strip.c index 03049335efda0..6a2bffc213a36 100644 --- a/test/profile/instrprof-darwin-dead-strip.c +++ b/test/profile/instrprof-darwin-dead-strip.c @@ -1,7 +1,7 @@  // REQUIRES: osx-ld64-live_support  // REQUIRES: lto -// RUN: %clang_profgen=%t.profraw -fcoverage-mapping -mllvm -enable-name-compression=false -Wl,-dead_strip -o %t %s +// RUN: %clang_profgen=%t.profraw -fcoverage-mapping -mllvm -enable-name-compression=false -DCODE=1 -Wl,-dead_strip -o %t %s  // RUN: %run %t  // RUN: llvm-profdata merge -o %t.profdata %t.profraw  // RUN: llvm-profdata show --all-functions %t.profdata | FileCheck %s -check-prefix=PROF @@ -10,7 +10,7 @@  // RUN: otool -s __DATA __llvm_prf_names %t | FileCheck %s -check-prefix=PRF_NAMES  // RUN: otool -s __DATA __llvm_prf_cnts %t | FileCheck %s -check-prefix=PRF_CNTS -// RUN: %clang_lto_profgen=%t.lto.profraw -fcoverage-mapping -mllvm -enable-name-compression=false -Wl,-dead_strip -flto -o %t.lto %s +// RUN: %clang_lto_profgen=%t.lto.profraw -fcoverage-mapping -mllvm -enable-name-compression=false -DCODE=1 -Wl,-dead_strip -flto -o %t.lto %s  // RUN: %run %t.lto  // RUN: llvm-profdata merge -o %t.lto.profdata %t.lto.profraw  // RUN: llvm-profdata show --all-functions %t.lto.profdata | FileCheck %s -check-prefix=PROF @@ -22,12 +22,24 @@  // Note: We expect foo() and some of the profiling data associated with it to  // be dead-stripped. +// Note: When there is no code in a program, we expect to see the exact same +// set of external functions provided by the profile runtime. + +// RUN: %clang_profgen -fcoverage-mapping -Wl,-dead_strip -dynamiclib -o %t.nocode.dylib %s +// RUN: nm -jgU %t.nocode.dylib > %t.nocode.syms +// RUN: nm -jgU %t | grep -vE "main|foo|mh_execute_header" > %t.code.syms +// RUN: diff %t.nocode.syms %t.code.syms + +#ifdef CODE +  // COV: [[@LINE+1]]{{ *}}|{{ *}}0|void foo()  void foo() {}  // COV: [[@LINE+1]]{{ *}}|{{ *}}1|int main  int main() { return 0; } +#endif // CODE +  // NM-NOT: foo  // PROF: Counters: diff --git a/test/profile/instrprof-darwin-exports.c b/test/profile/instrprof-darwin-exports.c new file mode 100644 index 0000000000000..6667cabdb2df4 --- /dev/null +++ b/test/profile/instrprof-darwin-exports.c @@ -0,0 +1,11 @@ +// REQUIRES: osx-ld64-live_support + +// Compiling with PGO/code coverage on Darwin should raise no warnings or errors +// when using an exports list. + +// RUN: echo "_main" > %t.exports +// RUN: %clang_pgogen -Werror -Wl,-exported_symbols_list,%t.exports -o %t %s 2>&1 | tee %t.log +// RUN: %clang_profgen -Werror -fcoverage-mapping -Wl,-exported_symbols_list,%t.exports -o %t %s 2>&1 | tee -a %t.log +// RUN: cat %t.log | count 0 + +int main() {} diff --git a/test/profile/instrprof-dlopen-dlclose-gcov.test b/test/profile/instrprof-dlopen-dlclose-gcov.test new file mode 100644 index 0000000000000..0444fca2692c3 --- /dev/null +++ b/test/profile/instrprof-dlopen-dlclose-gcov.test @@ -0,0 +1,30 @@ +RUN: mkdir -p %t.d +RUN: cd %t.d + +RUN: %clang --coverage -o func.shared -fPIC -shared %S/Inputs/instrprof-dlopen-func.c +RUN: %clang --coverage -o func2.shared -fPIC -shared %S/Inputs/instrprof-dlopen-func2.c +RUN: %clang --coverage -o func3.shared -fPIC -shared %S/Inputs/instrprof-dlopen-func3.c +RUN: %clang --coverage -o %t -fPIC -rpath %t.d %S/Inputs/instrprof-dlopen-dlclose-main.c + +# Test with two dlopened libraries. +RUN: %run %t +RUN: llvm-cov gcov instrprof-dlopen-dlclose-main.gcda +RUN: FileCheck --match-full-lines --strict-whitespace --input-file instrprof-dlopen-dlclose-main.c.gcov %S/Inputs/instrprof-dlopen-dlclose-main.c.gcov +RUN: llvm-cov gcov instrprof-dlopen-func.gcda +RUN: FileCheck --match-full-lines --strict-whitespace --input-file instrprof-dlopen-func.c.gcov %S/Inputs/instrprof-dlopen-func.c.gcov +RUN: llvm-cov gcov instrprof-dlopen-func2.gcda +RUN: FileCheck --match-full-lines --strict-whitespace --input-file instrprof-dlopen-func2.c.gcov %S/Inputs/instrprof-dlopen-func2.c.gcov +RUN: rm instrprof-dlopen-dlclose-main.gcda instrprof-dlopen-func.gcda instrprof-dlopen-func2.gcda + +# Test with three dlopened libraries. +RUN: %clang -DUSE_LIB3 --coverage -o %t -fPIC -rpath %t.d %S/Inputs/instrprof-dlopen-dlclose-main.c +RUN: %run %t +RUN: llvm-cov gcov instrprof-dlopen-dlclose-main.gcda +RUN: FileCheck --match-full-lines --strict-whitespace --input-file instrprof-dlopen-dlclose-main.c.gcov %S/Inputs/instrprof-dlopen-dlclose-main_three-libs.c.gcov +RUN: llvm-cov gcov instrprof-dlopen-func.gcda +RUN: FileCheck --match-full-lines --strict-whitespace --input-file instrprof-dlopen-func.c.gcov %S/Inputs/instrprof-dlopen-func.c.gcov +RUN: llvm-cov gcov instrprof-dlopen-func2.gcda +RUN: FileCheck --match-full-lines --strict-whitespace --input-file instrprof-dlopen-func2.c.gcov %S/Inputs/instrprof-dlopen-func2.c.gcov +RUN: llvm-cov gcov instrprof-dlopen-func3.gcda +RUN: FileCheck --match-full-lines --strict-whitespace --input-file instrprof-dlopen-func2.c.gcov %S/Inputs/instrprof-dlopen-func3.c.gcov +RUN: rm instrprof-dlopen-dlclose-main.gcda instrprof-dlopen-func.gcda instrprof-dlopen-func2.gcda instrprof-dlopen-func3.gcda diff --git a/test/profile/instrprof-gcov-__gcov_flush-terminate.test b/test/profile/instrprof-gcov-__gcov_flush-terminate.test new file mode 100644 index 0000000000000..aa51461a3bd08 --- /dev/null +++ b/test/profile/instrprof-gcov-__gcov_flush-terminate.test @@ -0,0 +1,12 @@ +XFAIL: * + +RUN: mkdir -p %t.d +RUN: cd %t.d + +RUN: %clang --coverage -o %t %S/Inputs/instrprof-gcov-__gcov_flush-terminate.c +RUN: test -f instrprof-gcov-__gcov_flush-terminate.gcno + +RUN: rm -f instrprof-gcov-__gcov_flush-terminate.gcda +RUN: %expect_crash %run %t +RUN: llvm-cov gcov instrprof-gcov-__gcov_flush-terminate.gcda +RUN: FileCheck --match-full-lines --strict-whitespace --input-file instrprof-gcov-__gcov_flush-terminate.c.gcov %S/Inputs/instrprof-gcov-__gcov_flush-terminate.c.gcov diff --git a/test/profile/instrprof-gcov-exceptions.test b/test/profile/instrprof-gcov-exceptions.test new file mode 100644 index 0000000000000..20ca47a9528bd --- /dev/null +++ b/test/profile/instrprof-gcov-exceptions.test @@ -0,0 +1,21 @@ +RUN: mkdir -p %t.d +RUN: cd %t.d + +# Test with exceptions disabled. +RUN: %clangxx --coverage -o %t %S/Inputs/instrprof-gcov-exceptions.cpp -fno-exceptions +RUN: test -f instrprof-gcov-exceptions.gcno + +RUN: rm -f instrprof-gcov-exceptions.gcda +RUN: %run %t +RUN: llvm-cov gcov instrprof-gcov-exceptions.gcda +RUN: FileCheck --match-full-lines --strict-whitespace --input-file instrprof-gcov-exceptions.cpp.gcov %S/Inputs/instrprof-gcov-exceptions.cpp.gcov + +# Test with exceptions enabled, the result in terms of line counts should be the same. +RUN: %clangxx --coverage -o %t %S/Inputs/instrprof-gcov-exceptions.cpp +RUN: test -f instrprof-gcov-exceptions.gcno + +RUN: rm -f instrprof-gcov-exceptions.gcda +RUN: %run %t +RUN: llvm-cov gcov instrprof-gcov-exceptions.gcda +# The result should be the same, not using XFAIL as only this part of the test is failing. +RUN: not FileCheck --match-full-lines --strict-whitespace --input-file instrprof-gcov-exceptions.cpp.gcov %S/Inputs/instrprof-gcov-exceptions.cpp.gcov diff --git a/test/profile/instrprof-gcov-multiple-bbs-single-line.test b/test/profile/instrprof-gcov-multiple-bbs-single-line.test new file mode 100644 index 0000000000000..8839455189eee --- /dev/null +++ b/test/profile/instrprof-gcov-multiple-bbs-single-line.test @@ -0,0 +1,13 @@ +XFAIL: * + +RUN: mkdir -p %t.d +RUN: cd %t.d + +RUN: %clang --coverage -o %t %S/Inputs/instrprof-gcov-multiple-bbs-single-line.c +RUN: test -f instrprof-gcov-multiple-bbs-single-line.gcno + +RUN: rm -f instrprof-gcov-multiple-bbs-single-line.gcda +RUN: %run %t +RUN: llvm-cov gcov -b -c instrprof-gcov-multiple-bbs-single-line.gcda +RUN: FileCheck --match-full-lines --strict-whitespace --input-file instrprof-gcov-multiple-bbs-single-line.c.gcov %S/Inputs/instrprof-gcov-multiple-bbs-single-line.c.gcov +RUN: rm instrprof-gcov-multiple-bbs-single-line.gcda diff --git a/test/profile/instrprof-gcov-two-objects.test b/test/profile/instrprof-gcov-two-objects.test new file mode 100644 index 0000000000000..a53d51dce8ede --- /dev/null +++ b/test/profile/instrprof-gcov-two-objects.test @@ -0,0 +1,18 @@ +RUN: mkdir -p %t.d +RUN: cd %t.d + +RUN: %clang --coverage -o instrprof-shared-lib.o -c %S/Inputs/instrprof-shared-lib.c +RUN: test -f instrprof-shared-lib.gcno + +RUN: %clang --coverage -o instrprof-shared-main.o -c %S/Inputs/instrprof-shared-main.c +RUN: test -f instrprof-shared-main.gcno + +RUN: %clang --coverage -o %t instrprof-shared-main.o instrprof-shared-lib.o +RUN: test -f %t + +RUN: %run %t +RUN: llvm-cov gcov instrprof-shared-main.gcda +RUN: FileCheck --match-full-lines --strict-whitespace --input-file instrprof-shared-main.c.gcov %S/Inputs/instrprof-shared-main.c.gcov +RUN: llvm-cov gcov instrprof-shared-lib.gcda +RUN: FileCheck --match-full-lines --strict-whitespace --input-file instrprof-shared-lib.c.gcov %S/Inputs/instrprof-shared-lib_in-loop.c.gcov +RUN: rm instrprof-shared-main.gcda instrprof-shared-lib.gcda diff --git a/test/profile/instrprof-get-filename.c b/test/profile/instrprof-get-filename.c new file mode 100644 index 0000000000000..031b75f12f3c2 --- /dev/null +++ b/test/profile/instrprof-get-filename.c @@ -0,0 +1,39 @@ +// Test __llvm_profile_get_filename. +// RUN: %clang_pgogen -O2 -o %t %s +// RUN: %run %t + +#include <stdio.h> +#include <string.h> + +const char *__llvm_profile_get_filename(); +void __llvm_profile_set_filename(const char *); + +int main(int argc, const char *argv[]) { +  int i; +  const char *filename; +  const char *new_filename = "/path/to/test.profraw"; + +  filename = __llvm_profile_get_filename(); +  if (strncmp(filename, "default_", 8)) { +    fprintf(stderr, +            "Error: got filename %s, expected it to start with 'default_'\n", +            filename); +    return 1; +  } +  if (strcmp(filename + strlen(filename) - strlen(".profraw"), ".profraw")) { +    fprintf(stderr, +            "Error: got filename %s, expected it to end with '.profraw'\n", +            filename); +    return 1; +  } + +  __llvm_profile_set_filename(new_filename); +  filename = __llvm_profile_get_filename(); +  if (strcmp(filename, new_filename)) { +    fprintf(stderr, "Error: got filename %s, expected '%s'\n", filename, +            new_filename); +    return 1; +  } + +  return 0; +} diff --git a/test/profile/instrprof-path.c b/test/profile/instrprof-path.c index 28ee8ad0a4843..90cb1df198f07 100644 --- a/test/profile/instrprof-path.c +++ b/test/profile/instrprof-path.c @@ -12,7 +12,7 @@  #include <string.h>  const char *__llvm_profile_get_path_prefix(); -void __llvm_profile_set_filanem(const char*); +void __llvm_profile_set_filename(const char*);  int main(int argc, const char *argv[]) {    int i; diff --git a/test/profile/instrprof-reset-counters.c b/test/profile/instrprof-reset-counters.c index e8892366bcfec..f15bc0d8e3a1a 100644 --- a/test/profile/instrprof-reset-counters.c +++ b/test/profile/instrprof-reset-counters.c @@ -12,7 +12,7 @@ int main(void) {    return 0;  }  void foo(int N) { -  // CHECK-LABEL: define void @foo( +  // CHECK-LABEL: define{{( dso_local)?}} void @foo(    // CHECK: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}, !prof ![[FOO:[0-9]+]]    if (N) {}  } diff --git a/test/profile/instrprof-shared-gcov-flush.test b/test/profile/instrprof-shared-gcov-flush.test new file mode 100644 index 0000000000000..50292b6336c43 --- /dev/null +++ b/test/profile/instrprof-shared-gcov-flush.test @@ -0,0 +1,52 @@ +# This test fails on Mac (https://bugs.llvm.org/show_bug.cgi?id=38134) +XFAIL: darwin + +RUN: mkdir -p %t.d +RUN: cd %t.d + +RUN: %clang --coverage -o libfunc.so -fPIC -shared %S/Inputs/instrprof-shared-lib.c +RUN: test -f instrprof-shared-lib.gcno + +# Test the case where we exit abruptly after calling __gcov_flush, which means we don't write out the counters at exit. +RUN: %clang -DEXIT_ABRUPTLY -DSHARED_CALL_BEFORE_GCOV_FLUSH -DSHARED_CALL_AFTER_GCOV_FLUSH --coverage -o %t -L%t.d -rpath %t.d -lfunc %S/Inputs/instrprof-shared-main-gcov-flush.c +RUN: test -f instrprof-shared-main-gcov-flush.gcno + +RUN: %run %t +RUN: llvm-cov gcov instrprof-shared-main-gcov-flush.gcda +RUN: FileCheck --match-full-lines --strict-whitespace --input-file instrprof-shared-main-gcov-flush.c.gcov %S/Inputs/instrprof-shared-main-gcov-flush_no-writeout.c.gcov +RUN: llvm-cov gcov instrprof-shared-lib.gcda +RUN: FileCheck --match-full-lines --strict-whitespace --input-file instrprof-shared-lib.c.gcov %S/Inputs/instrprof-shared-lib.c.gcov +RUN: rm instrprof-shared-main-gcov-flush.gcda instrprof-shared-lib.gcda + +# Test the case where we exit normally and we have a call to the shared library function before __gcov_flush. +RUN: %clang -DSHARED_CALL_BEFORE_GCOV_FLUSH --coverage -o %t -L%t.d -rpath %t.d -lfunc %S/Inputs/instrprof-shared-main-gcov-flush.c +RUN: test -f instrprof-shared-main-gcov-flush.gcno + +RUN: %run %t +RUN: llvm-cov gcov instrprof-shared-main-gcov-flush.gcda +RUN: FileCheck --match-full-lines --strict-whitespace --input-file instrprof-shared-main-gcov-flush.c.gcov %S/Inputs/instrprof-shared-main-gcov-flush_shared-call-before.c.gcov +RUN: llvm-cov gcov instrprof-shared-lib.gcda +RUN: FileCheck --match-full-lines --strict-whitespace --input-file instrprof-shared-lib.c.gcov %S/Inputs/instrprof-shared-lib.c.gcov +RUN: rm instrprof-shared-main-gcov-flush.gcda instrprof-shared-lib.gcda + +# Test the case where we exit normally and we have a call to the shared library function after __gcov_flush. +RUN: %clang -DSHARED_CALL_AFTER_GCOV_FLUSH --coverage -o %t -L%t.d -rpath %t.d -lfunc %S/Inputs/instrprof-shared-main-gcov-flush.c +RUN: test -f instrprof-shared-main-gcov-flush.gcno + +RUN: %run %t +RUN: llvm-cov gcov instrprof-shared-main-gcov-flush.gcda +RUN: FileCheck --match-full-lines --strict-whitespace --input-file instrprof-shared-main-gcov-flush.c.gcov %S/Inputs/instrprof-shared-main-gcov-flush_shared-call-after.c.gcov +RUN: llvm-cov gcov instrprof-shared-lib.gcda +RUN: FileCheck --match-full-lines --strict-whitespace --input-file instrprof-shared-lib.c.gcov %S/Inputs/instrprof-shared-lib.c.gcov +RUN: rm instrprof-shared-main-gcov-flush.gcda instrprof-shared-lib.gcda + +# Test the case where we exit normally and we have calls to the shared library function before and after __gcov_flush. +RUN: %clang -DSHARED_CALL_BEFORE_GCOV_FLUSH -DSHARED_CALL_AFTER_GCOV_FLUSH --coverage -o %t -L%t.d -rpath %t.d -lfunc %S/Inputs/instrprof-shared-main-gcov-flush.c +RUN: test -f instrprof-shared-main-gcov-flush.gcno + +RUN: %run %t +RUN: llvm-cov gcov instrprof-shared-main-gcov-flush.gcda +RUN: FileCheck --match-full-lines --strict-whitespace --input-file instrprof-shared-main-gcov-flush.c.gcov %S/Inputs/instrprof-shared-main-gcov-flush_shared-call-before-after.c.gcov +RUN: llvm-cov gcov instrprof-shared-lib.gcda +RUN: FileCheck --match-full-lines --strict-whitespace --input-file instrprof-shared-lib.c.gcov %S/Inputs/instrprof-shared-lib_called-twice.c.gcov +RUN: rm instrprof-shared-main-gcov-flush.gcda instrprof-shared-lib.gcda diff --git a/test/profile/instrprof-visibility.cpp b/test/profile/instrprof-visibility.cpp index 6fbba9defc565..bb533050e0592 100644 --- a/test/profile/instrprof-visibility.cpp +++ b/test/profile/instrprof-visibility.cpp @@ -1,8 +1,8 @@  // RUN: %clangxx_profgen -fcoverage-mapping %S/Inputs/instrprof-visibility-helper.cpp -o %t %s  // RUN: env LLVM_PROFILE_FILE=%t.profraw %run %t  // RUN: llvm-profdata merge %t.profraw -o %t.profdata -// RUN: llvm-profdata show --all-functions %t.profraw | FileCheck %s --check-prefix=PROFILE -// RUN: llvm-cov show %t -instr-profile=%t.profdata | FileCheck %s --check-prefix=COV +// RUN: llvm-profdata show --all-functions %t.profraw | FileCheck -allow-deprecated-dag-overlap %s --check-prefix=PROFILE +// RUN: llvm-cov show %t -instr-profile=%t.profdata | FileCheck -allow-deprecated-dag-overlap %s --check-prefix=COV  namespace {  #define NO_WEAK diff --git a/test/sanitizer_common/CMakeLists.txt b/test/sanitizer_common/CMakeLists.txt index 8b210a08aa570..4e2c80390f716 100644 --- a/test/sanitizer_common/CMakeLists.txt +++ b/test/sanitizer_common/CMakeLists.txt @@ -4,15 +4,17 @@ set(SANITIZER_COMMON_TEST_DEPS ${SANITIZER_COMMON_LIT_TEST_DEPS})  set(SANITIZER_COMMON_TESTSUITES)  set(SUPPORTED_TOOLS) -if(CMAKE_SYSTEM_NAME MATCHES "Darwin|Linux|FreeBSD|NetBSD") +if(CMAKE_SYSTEM_NAME MATCHES "Darwin|Linux|FreeBSD|NetBSD|SunOS")    list(APPEND SUPPORTED_TOOLS asan)  endif() -if(CMAKE_SYSTEM_NAME MATCHES "Linux" AND NOT ANDROID) +if(CMAKE_SYSTEM_NAME MATCHES "NetBSD" OR (CMAKE_SYSTEM_NAME MATCHES "Linux" AND NOT ANDROID))    list(APPEND SUPPORTED_TOOLS tsan)    list(APPEND SUPPORTED_TOOLS msan) -  list(APPEND SUPPORTED_TOOLS lsan)    list(APPEND SUPPORTED_TOOLS ubsan)  endif() +if(CMAKE_SYSTEM_NAME MATCHES "Linux" AND NOT ANDROID) +  list(APPEND SUPPORTED_TOOLS lsan) +endif()  # Create a separate config for each tool we support.  foreach(tool ${SUPPORTED_TOOLS}) diff --git a/test/sanitizer_common/TestCases/Linux/aligned_alloc-alignment.cc b/test/sanitizer_common/TestCases/Linux/aligned_alloc-alignment.cc new file mode 100644 index 0000000000000..1a340edecdbe7 --- /dev/null +++ b/test/sanitizer_common/TestCases/Linux/aligned_alloc-alignment.cc @@ -0,0 +1,43 @@ +// RUN: %clangxx %collect_stack_traces -O0 %s -o %t + +// Alignment is not a power of 2: +// RUN: %env_tool_opts=allocator_may_return_null=0 not %run %t 17 2>&1 | FileCheck %s +// Size is not a multiple of alignment: +// RUN: %env_tool_opts=allocator_may_return_null=0 not %run %t 8 2>&1 | FileCheck %s +// Alignment is 0: +// RUN: %env_tool_opts=allocator_may_return_null=0 not %run %t 0 2>&1 | FileCheck %s + +// The same for allocator_may_return_null=1: +// RUN: %env_tool_opts=allocator_may_return_null=1 %run %t 17 2>&1 | FileCheck %s --check-prefix=CHECK-NULL +// RUN: %env_tool_opts=allocator_may_return_null=1 %run %t 8 2>&1 | FileCheck %s --check-prefix=CHECK-NULL +// RUN: %env_tool_opts=allocator_may_return_null=1 %run %t 0 2>&1 | FileCheck %s --check-prefix=CHECK-NULL + +// REQUIRES: stable-runtime + +// UNSUPPORTED: android, ubsan + +#include <assert.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> + +extern void *aligned_alloc(size_t alignment, size_t size); + +int main(int argc, char **argv) { +  assert(argc == 2); +  const int alignment = atoi(argv[1]); + +  void *p = aligned_alloc(alignment, 100); +  // CHECK: {{ERROR: .*Sanitizer: invalid alignment requested in aligned_alloc}} +  // Handle a case when aligned_alloc is aliased by memalign. +  // CHECK: {{#0 .*}}{{aligned_alloc|memalign}} +  // CHECK: {{#1 .*main .*aligned_alloc-alignment.cc:}}[[@LINE-4]] +  // CHECK: {{SUMMARY: .*Sanitizer: invalid-aligned-alloc-alignment}} + +  // The NULL pointer is printed differently on different systems, while (long)0 +  // is always the same. +  fprintf(stderr, "errno: %d, p: %lx\n", errno, (long)p); +  // CHECK-NULL: errno: 22, p: 0 + +  return 0; +} diff --git a/test/sanitizer_common/TestCases/Linux/hard_rss_limit_mb_test.cc b/test/sanitizer_common/TestCases/Linux/hard_rss_limit_mb_test.cc index 3c875c1793dff..3013a3c3fd7db 100644 --- a/test/sanitizer_common/TestCases/Linux/hard_rss_limit_mb_test.cc +++ b/test/sanitizer_common/TestCases/Linux/hard_rss_limit_mb_test.cc @@ -16,6 +16,9 @@  // XFAIL: msan  // XFAIL: ubsan +// https://github.com/google/sanitizers/issues/981 +// UNSUPPORTED: android-26 +  #include <string.h>  #include <stdio.h>  #include <unistd.h> diff --git a/test/sanitizer_common/TestCases/Linux/mmap64_test.c b/test/sanitizer_common/TestCases/Linux/mmap64_test.c new file mode 100644 index 0000000000000..f4c009d846afb --- /dev/null +++ b/test/sanitizer_common/TestCases/Linux/mmap64_test.c @@ -0,0 +1,13 @@ +// RUN: %clang %s -o %t && %run %t + +#define _LARGEFILE64_SOURCE 1 + +#include <assert.h> +#include <sys/mman.h> + +int main() { +  char *buf = (char *)mmap64(0, 100000, PROT_READ | PROT_WRITE, +                             MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); +  assert(buf); +  munmap(buf, 100000); +} diff --git a/test/sanitizer_common/TestCases/Linux/mmap_write_exec.cpp b/test/sanitizer_common/TestCases/Linux/mmap_write_exec.cpp new file mode 100644 index 0000000000000..49495403c5a11 --- /dev/null +++ b/test/sanitizer_common/TestCases/Linux/mmap_write_exec.cpp @@ -0,0 +1,37 @@ +// RUN: %clangxx %s -o %t +// RUN: %env_tool_opts=detect_write_exec=1 %run %t 2>&1 | FileCheck %s +// RUN: %env_tool_opts=detect_write_exec=0 %run %t 2>&1 | FileCheck %s \ +// RUN:   --check-prefix=CHECK-DISABLED +// ubsan and lsan do not install mmap interceptors UNSUPPORTED: ubsan, lsan + +// TODO: Fix option on Android, it hangs there for unknown reasons. +// XFAIL: android + +#include <stdio.h> +#include <sys/mman.h> + +int main(int argc, char **argv) { +  char *p = (char *)mmap(0, 1024, PROT_READ | PROT_WRITE | PROT_EXEC, +                         MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); +  // CHECK: WARNING: {{.*}}Sanitizer: writable-executable page usage +  // CHECK: #{{[0-9]+.*}}main{{.*}}mmap_write_exec.cpp:[[@LINE-3]] +  // CHECK: SUMMARY: {{.*}}Sanitizer: w-and-x-usage + +  char *q = (char *)mmap(p, 64, PROT_READ | PROT_WRITE, +                         MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0); +  (void)mprotect(q, 64, PROT_WRITE | PROT_EXEC); +  // CHECK: WARNING: {{.*}}Sanitizer: writable-executable page usage +  // CHECK: #{{[0-9]+.*}}main{{.*}}mmap_write_exec.cpp:[[@LINE-2]] +  // CHECK: SUMMARY: {{.*}}Sanitizer: w-and-x-usage + +  char *a = (char *)mmap(0, 1024, PROT_READ | PROT_WRITE, +                         MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); +  char *b = (char *)mmap(a, 64, PROT_READ | PROT_WRITE, +                         MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0); +  (void)mprotect(q, 64, PROT_READ | PROT_EXEC); +  // CHECK-NOT: Sanitizer + +  printf("done\n"); +  // CHECK-DISABLED-NOT: Sanitizer +  // CHECK-DISABLED: done +} diff --git a/test/sanitizer_common/TestCases/Linux/name_to_handle_at.cc b/test/sanitizer_common/TestCases/Linux/name_to_handle_at.cc new file mode 100644 index 0000000000000..47c6a18627a6f --- /dev/null +++ b/test/sanitizer_common/TestCases/Linux/name_to_handle_at.cc @@ -0,0 +1,21 @@ +// RUN: %clangxx -O0 %s -o %t && %run %t +// UNSUPPORTED: android + +#include <assert.h> +#include <fcntl.h> +#include <stdlib.h> +#include <sys/stat.h> +#include <sys/types.h> + +int main(int argc, char **argv) { +  int mount_id; +  struct file_handle *handle = reinterpret_cast<struct file_handle *>( +      malloc(sizeof(*handle) + MAX_HANDLE_SZ)); + +  handle->handle_bytes = MAX_HANDLE_SZ; +  int res = name_to_handle_at(AT_FDCWD, argv[0], handle, &mount_id, 0); +  assert(!res); + +  free(handle); +  return 0; +} diff --git a/test/sanitizer_common/TestCases/Linux/pthread_mutex.cc b/test/sanitizer_common/TestCases/Linux/pthread_mutex.cc new file mode 100644 index 0000000000000..610958143b472 --- /dev/null +++ b/test/sanitizer_common/TestCases/Linux/pthread_mutex.cc @@ -0,0 +1,34 @@ +// RUN: %clangxx -O1 %s -o %t && %run %t +// RUN: %clangxx -O1 -DUSE_GLIBC %s -o %t && %run %t +// UNSUPPORTED: android + +#include <pthread.h> + +#ifdef USE_GLIBC +extern "C" int __pthread_mutex_lock(pthread_mutex_t *__mutex); +extern "C" int __pthread_mutex_unlock(pthread_mutex_t *__mutex); +#define LOCK __pthread_mutex_lock +#define UNLOCK __pthread_mutex_unlock +#else +#define LOCK pthread_mutex_lock +#define UNLOCK pthread_mutex_unlock +#endif + +pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER; +int x; + +static void *Start(void *arg) { +  LOCK(&m); +  ++x; +  UNLOCK(&m); +  return nullptr; +} + +int main() { +  pthread_t threads[2] = {}; +  for (pthread_t &t : threads) +    pthread_create(&t, 0, &Start, 0); +  for (pthread_t &t : threads) +    pthread_join(t, 0); +  return 0; +} diff --git a/test/sanitizer_common/TestCases/Linux/pvalloc-overflow.cc b/test/sanitizer_common/TestCases/Linux/pvalloc-overflow.cc new file mode 100644 index 0000000000000..537c57e1a69f0 --- /dev/null +++ b/test/sanitizer_common/TestCases/Linux/pvalloc-overflow.cc @@ -0,0 +1,47 @@ +// RUN: %clangxx %collect_stack_traces -O0 %s -o %t +// RUN: %env_tool_opts=allocator_may_return_null=0 not %run %t m1 2>&1 | FileCheck %s +// RUN: %env_tool_opts=allocator_may_return_null=1     %run %t m1 2>&1 | FileCheck %s --check-prefix=CHECK-NULL +// RUN: %env_tool_opts=allocator_may_return_null=0 not %run %t psm1 2>&1 | FileCheck %s +// RUN: %env_tool_opts=allocator_may_return_null=1     %run %t psm1 2>&1 | FileCheck %s --check-prefix=CHECK-NULL + +// REQUIRES: stable-runtime + +// UNSUPPORTED: android, freebsd, netbsd, ubsan + +// Checks that pvalloc overflows are caught. If the allocator is allowed to +// return null, the errno should be set to ENOMEM. + +#include <assert.h> +#include <errno.h> +#include <malloc.h> +#include <stdio.h> +#include <stdint.h> +#include <string.h> +#include <unistd.h> + +int main(int argc, char *argv[]) { +  assert(argc == 2); +  const char *action = argv[1]; + +  const size_t page_size = sysconf(_SC_PAGESIZE); + +  void *p = nullptr; +  if (!strcmp(action, "m1")) { +    p = pvalloc((uintptr_t)-1); +  } else if (!strcmp(action, "psm1")) { +    p = pvalloc((uintptr_t)-(page_size - 1)); +  } else { +    assert(0); +  } +  // CHECK: {{ERROR: .*Sanitizer: pvalloc parameters overflow: size .* rounded up to system page size .* cannot be represented in type size_t}} +  // CHECK: {{#0 .*pvalloc}} +  // CHECK: {{#1 .*main .*pvalloc-overflow.cc:}} +  // CHECK: {{SUMMARY: .*Sanitizer: pvalloc-overflow}} + +  // The NULL pointer is printed differently on different systems, while (long)0 +  // is always the same. +  fprintf(stderr, "errno: %d, p: %lx\n", errno, (long)p); +  // CHECK-NULL: errno: 12, p: 0 + +  return 0; +} diff --git a/test/sanitizer_common/TestCases/Linux/soft_rss_limit_mb_test.cc b/test/sanitizer_common/TestCases/Linux/soft_rss_limit_mb_test.cc index 2ee809547530f..f7d8b4d64016a 100644 --- a/test/sanitizer_common/TestCases/Linux/soft_rss_limit_mb_test.cc +++ b/test/sanitizer_common/TestCases/Linux/soft_rss_limit_mb_test.cc @@ -15,6 +15,10 @@  // XFAIL: tsan  // XFAIL: msan  // XFAIL: ubsan + +// https://github.com/google/sanitizers/issues/981 +// UNSUPPORTED: android-26 +  #include <stdlib.h>  #include <stdio.h>  #include <string.h> @@ -65,4 +69,4 @@ int main() {  // CHECK_MAY_RETURN_0: allocating 128 times  // CHECK_MAY_RETURN_0: Some of the malloc calls returned non-null: 128  // CHECK_MAY_RETURN_0: allocating 256 times -// CHECK_MAY_RETURN_0: allocator is terminating the process instead of returning +// CHECK_MAY_RETURN_0: {{SUMMARY: .*Sanitizer: rss-limit-exceeded}} diff --git a/test/sanitizer_common/TestCases/Linux/sysconf_interceptor_bypass_test.cc b/test/sanitizer_common/TestCases/Linux/sysconf_interceptor_bypass_test.cc index c3a6560228972..0ffb346ebb450 100644 --- a/test/sanitizer_common/TestCases/Linux/sysconf_interceptor_bypass_test.cc +++ b/test/sanitizer_common/TestCases/Linux/sysconf_interceptor_bypass_test.cc @@ -1,12 +1,14 @@  // RUN: %clangxx -O2 %s -o %t && %run %t 2>&1 | FileCheck %s -// XFAIL: android -  #include <stdio.h> +#if !defined(__GLIBC_PREREQ) +#define __GLIBC_PREREQ(a, b) 0 +#endif +  // getauxval() used instead of sysconf() in GetPageSize() is defined starting  // glbc version 2.16. -#if defined(__GLIBC_PREREQ) && __GLIBC_PREREQ(2, 16) +#if __GLIBC_PREREQ(2, 16)  extern "C" long sysconf(int name) {    fprintf(stderr, "sysconf wrapper called\n");    return 0; diff --git a/test/sanitizer_common/TestCases/NetBSD/faccessat.cc b/test/sanitizer_common/TestCases/NetBSD/faccessat.cc new file mode 100644 index 0000000000000..ae8be1962b8c2 --- /dev/null +++ b/test/sanitizer_common/TestCases/NetBSD/faccessat.cc @@ -0,0 +1,6 @@ +// RUN: %clangxx -O0 -g %s -o %t && %run %t + +#include <fcntl.h> +#include <unistd.h> + +int main(void) { return faccessat(AT_FDCWD, "/root", F_OK, 0); } diff --git a/test/sanitizer_common/TestCases/NetBSD/getgrouplist.cc b/test/sanitizer_common/TestCases/NetBSD/getgrouplist.cc new file mode 100644 index 0000000000000..49655542ec6dc --- /dev/null +++ b/test/sanitizer_common/TestCases/NetBSD/getgrouplist.cc @@ -0,0 +1,29 @@ +// RUN: %clangxx -O0 -g %s -o %t && %run %t + +#include <stdlib.h> +#include <unistd.h> +#include <grp.h> + +int main(void) { +  gid_t *groups; +  gid_t nobody; +  int ngroups; + +  ngroups = sysconf(_SC_NGROUPS_MAX); +  groups = (gid_t *)malloc(ngroups * sizeof(gid_t)); +  if (!groups) +    exit(1); + +  if (gid_from_group("nobody", &nobody) == -1) +    exit(1); + +  if (getgrouplist("nobody", nobody, groups, &ngroups)) +    exit(1); + +  if (groups && ngroups) { +    free(groups); +    exit(0); +  } + +  return -1; +} diff --git a/test/sanitizer_common/TestCases/NetBSD/getgroupmembership.cc b/test/sanitizer_common/TestCases/NetBSD/getgroupmembership.cc new file mode 100644 index 0000000000000..ee27ad6cf365a --- /dev/null +++ b/test/sanitizer_common/TestCases/NetBSD/getgroupmembership.cc @@ -0,0 +1,30 @@ +// RUN: %clangxx -O0 -g %s -o %t && %run %t + +#include <stdlib.h> +#include <unistd.h> +#include <grp.h> + +int main(void) { +  gid_t *groups; +  gid_t nobody; +  int ngroups; +  int maxgrp; + +  maxgrp = sysconf(_SC_NGROUPS_MAX); +  groups = (gid_t *)malloc(maxgrp * sizeof(gid_t)); +  if (!groups) +    exit(1); + +  if (gid_from_group("nobody", &nobody) == -1) +    exit(1); + +  if (getgroupmembership("nobody", nobody, groups, maxgrp, &ngroups)) +    exit(1); + +  if (groups && ngroups) { +    free(groups); +    exit(0); +  } + +  return -1; +} diff --git a/test/sanitizer_common/TestCases/NetBSD/gid_from_group.cc b/test/sanitizer_common/TestCases/NetBSD/gid_from_group.cc new file mode 100644 index 0000000000000..c6a9bc97c1e80 --- /dev/null +++ b/test/sanitizer_common/TestCases/NetBSD/gid_from_group.cc @@ -0,0 +1,16 @@ +// RUN: %clangxx -O0 -g %s -o %t && %run %t + +#include <grp.h> +#include <stdlib.h> + +int main(void) { +  gid_t nobody; + +  if (gid_from_group("nobody", &nobody) == -1) +    exit(1); + +  if (nobody) +    exit(0); + +  return 0; +} diff --git a/test/sanitizer_common/TestCases/NetBSD/group_from_gid.cc b/test/sanitizer_common/TestCases/NetBSD/group_from_gid.cc new file mode 100644 index 0000000000000..eb39da7b2b504 --- /dev/null +++ b/test/sanitizer_common/TestCases/NetBSD/group_from_gid.cc @@ -0,0 +1,17 @@ +// RUN: %clangxx -O0 -g %s -o %t && %run %t + +#include <grp.h> +#include <stdlib.h> +#include <string.h> + +int main(void) { +  const char *nobody; + +  if (!(nobody = group_from_gid(0, 0))) +    exit(1); + +  if (strlen(nobody)) +    exit(0); + +  return 0; +} diff --git a/test/sanitizer_common/TestCases/NetBSD/lit.local.cfg b/test/sanitizer_common/TestCases/NetBSD/lit.local.cfg new file mode 100644 index 0000000000000..94023561ffe30 --- /dev/null +++ b/test/sanitizer_common/TestCases/NetBSD/lit.local.cfg @@ -0,0 +1,9 @@ +def getRoot(config): +  if not config.parent: +    return config +  return getRoot(config.parent) + +root = getRoot(config) + +if root.host_os not in ['NetBSD']: +  config.unsupported = True diff --git a/test/sanitizer_common/TestCases/NetBSD/netent.cc b/test/sanitizer_common/TestCases/NetBSD/netent.cc new file mode 100644 index 0000000000000..b574a931082c4 --- /dev/null +++ b/test/sanitizer_common/TestCases/NetBSD/netent.cc @@ -0,0 +1,84 @@ +// RUN: %clangxx -O0 -g %s -o %t && %run %t 2>&1 | FileCheck %s + +#include <inttypes.h> +#include <netdb.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> + +#define STRING_OR_NULL(x) ((x) ? (x) : "null") + +void test1() { +  struct netent *ntp = getnetent(); + +  printf("%s ", ntp->n_name); + +  for (char **cp = ntp->n_aliases; *cp != NULL; cp++) +    printf("%s ", STRING_OR_NULL(*cp)); + +  printf("%d ", ntp->n_addrtype); +  printf("%" PRIu32 "\n", ntp->n_net); + +  endnetent(); +} + +void test2() { +  struct netent *ntp = getnetbyname("loopback"); + +  printf("%s ", ntp->n_name); + +  for (char **cp = ntp->n_aliases; *cp != NULL; cp++) +    printf("%s ", STRING_OR_NULL(*cp)); + +  printf("%d ", ntp->n_addrtype); +  printf("%" PRIu32 "\n", ntp->n_net); + +  endnetent(); +} + +void test3() { +  struct netent *ntp = getnetbyaddr(127, 2); + +  printf("%s ", ntp->n_name); + +  for (char **cp = ntp->n_aliases; *cp != NULL; cp++) +    printf("%s ", STRING_OR_NULL(*cp)); + +  printf("%d ", ntp->n_addrtype); +  printf("%" PRIu32 "\n", ntp->n_net); + +  endnetent(); +} + +void test4() { +  setnetent(1); + +  struct netent *ntp = getnetent(); + +  printf("%s ", ntp->n_name); + +  for (char **cp = ntp->n_aliases; *cp != NULL; cp++) +    printf("%s ", STRING_OR_NULL(*cp)); + +  printf("%d ", ntp->n_addrtype); +  printf("%" PRIu32 "\n", ntp->n_net); + +  endnetent(); +} + +int main(void) { +  printf("netent\n"); + +  test1(); +  test2(); +  test3(); +  test4(); + +  // CHECK: netent +  // CHECK: loopback 2 127 +  // CHECK: loopback 2 127 +  // CHECK: loopback 2 127 +  // CHECK: loopback 2 127 + +  return 0; +} diff --git a/test/sanitizer_common/TestCases/NetBSD/paccept.cc b/test/sanitizer_common/TestCases/NetBSD/paccept.cc new file mode 100644 index 0000000000000..7d2eb4e85596f --- /dev/null +++ b/test/sanitizer_common/TestCases/NetBSD/paccept.cc @@ -0,0 +1,74 @@ +// RUN: %clangxx -O0 -g %s -o %t && %run %t + +#include <netinet/in.h> +#include <sys/socket.h> +#include <sys/wait.h> +#include <signal.h> +#include <stdlib.h> +#include <unistd.h> + +int main(void) { +  int child; +  int fd, sfd; +  socklen_t len; +  struct sockaddr_in server = {}, client = {}; +  sigset_t set; + +  child = fork(); +  if (child == 0) { +    fd = socket(AF_INET, SOCK_STREAM, 0); +    if (fd == -1) +      _exit(1); + +    server.sin_family = AF_INET; +    server.sin_addr.s_addr = INADDR_ANY; +    server.sin_port = htons(2222); + +    if (connect(fd, (struct sockaddr *)&server, sizeof(server)) == -1) +      _exit(1); + +    close(fd); + +    _exit(0); +  } + +  fd = socket(AF_INET, SOCK_STREAM, 0); +  if (fd == -1) { +    kill(child, SIGKILL); +    wait(NULL); +    exit(1); +  } + +  server.sin_family = AF_INET; +  server.sin_addr.s_addr = INADDR_ANY; +  server.sin_port = htons(2222); + +  if (bind(fd, (const struct sockaddr *)&server, sizeof(server)) == -1) { +    kill(child, SIGKILL); +    wait(NULL); +    exit(1); +  } + +  listen(fd, 3); + +  if (sigemptyset(&set) == -1) { +    kill(child, SIGKILL); +    wait(NULL); +    exit(1); +  } + +  len = sizeof(client); +  sfd = paccept(fd, (struct sockaddr *)&client, &len, &set, SOCK_NONBLOCK); +  if (sfd == -1) { +    kill(child, SIGKILL); +    wait(NULL); +    exit(1); +  } + +  wait(NULL); + +  close(sfd); +  close(fd); + +  return 0; +} diff --git a/test/sanitizer_common/TestCases/NetBSD/protoent.cc b/test/sanitizer_common/TestCases/NetBSD/protoent.cc new file mode 100644 index 0000000000000..c88c6f904a499 --- /dev/null +++ b/test/sanitizer_common/TestCases/NetBSD/protoent.cc @@ -0,0 +1,89 @@ +// RUN: %clangxx -O0 -g %s -o %t && %run %t 2>&1 | FileCheck %s + +#include <netdb.h> +#include <stdio.h> +#include <stdlib.h> + +#define STRING_OR_NULL(x) ((x) ? (x) : "null") + +void test1() { +  struct protoent *ptp = getprotoent(); + +  printf("%s ", STRING_OR_NULL(ptp->p_name)); + +  for (char **cp = ptp->p_aliases; *cp != NULL; cp++) +    printf("%s ", STRING_OR_NULL(*cp)); + +  printf("%d\n", ptp->p_proto); +  endprotoent(); +} + +void test2() { +  struct protoent *ptp = getprotobyname("icmp"); + +  printf("%s ", STRING_OR_NULL(ptp->p_name)); + +  for (char **cp = ptp->p_aliases; *cp != NULL; cp++) +    printf("%s ", STRING_OR_NULL(*cp)); + +  printf("%d\n", ptp->p_proto); +  endprotoent(); +} + +void test3() { +  struct protoent *ptp = getprotobynumber(1); + +  printf("%s ", STRING_OR_NULL(ptp->p_name)); + +  for (char **cp = ptp->p_aliases; *cp != NULL; cp++) +    printf("%s ", STRING_OR_NULL(*cp)); + +  printf("%d\n", ptp->p_proto); +  endprotoent(); +} + +void test4() { +  setprotoent(1); +  struct protoent *ptp = getprotobynumber(1); + +  ptp = getprotobynumber(2); + +  printf("%s ", STRING_OR_NULL(ptp->p_name)); + +  for (char **cp = ptp->p_aliases; *cp != NULL; cp++) +    printf("%s ", STRING_OR_NULL(*cp)); + +  printf("%d\n", ptp->p_proto); +  endprotoent(); +} + +void test5() { +  struct protoent *ptp = getprotobyname("ttp"); + +  printf("%s ", STRING_OR_NULL(ptp->p_name)); + +  for (char **cp = ptp->p_aliases; *cp != NULL; cp++) +    printf("%s ", STRING_OR_NULL(*cp)); + +  printf("%d\n", ptp->p_proto); +  endprotoent(); +} + +int main(void) { +  printf("protoent\n"); + +  test1(); +  test2(); +  test3(); +  test4(); +  test5(); + +  // CHECK: protoent +  // CHECK: hopopt HOPOPT 0 +  // CHECK: icmp ICMP 1 +  // CHECK: icmp ICMP 1 +  // CHECK: igmp IGMP 2 +  // CHECK: ttp TTP iptm IPTM 84 + +  return 0; +} diff --git a/test/sanitizer_common/TestCases/NetBSD/strmode.cc b/test/sanitizer_common/TestCases/NetBSD/strmode.cc new file mode 100644 index 0000000000000..b8d7d8ccf5a20 --- /dev/null +++ b/test/sanitizer_common/TestCases/NetBSD/strmode.cc @@ -0,0 +1,20 @@ +// RUN: %clangxx -O0 -g %s -o %t && %run %t + +#include <stdio.h> +#include <stdlib.h> +#include <sys/stat.h> +#include <unistd.h> + +int main(void) { +  struct stat st; +  char modep[15]; + +  if (stat("/etc/hosts", &st)) +    exit(1); + +  strmode(st.st_mode, modep); + +  printf("%s\n", modep); + +  return 0; +} diff --git a/test/sanitizer_common/TestCases/NetBSD/ttyent.cc b/test/sanitizer_common/TestCases/NetBSD/ttyent.cc new file mode 100644 index 0000000000000..73bc0a5da56b5 --- /dev/null +++ b/test/sanitizer_common/TestCases/NetBSD/ttyent.cc @@ -0,0 +1,70 @@ +// RUN: %clangxx -O0 -g %s -o %t && %run %t 2>&1 | FileCheck %s + +#include <stdio.h> +#include <stdlib.h> +#include <ttyent.h> + +#define STRING_OR_NULL(x) ((x) ? (x) : "null") + +void test1() { +  struct ttyent *typ = getttyent(); + +  printf("%s %s %s %d %s %s %s\n", STRING_OR_NULL(typ->ty_name), +         STRING_OR_NULL(typ->ty_getty), STRING_OR_NULL(typ->ty_type), +         typ->ty_status, STRING_OR_NULL(typ->ty_window), +         STRING_OR_NULL(typ->ty_comment), STRING_OR_NULL(typ->ty_class)); + +  endttyent(); +} + +void test2() { +  struct ttyent *typ = getttynam("console"); + +  printf("%s %s %s %d %s %s %s\n", STRING_OR_NULL(typ->ty_name), +         STRING_OR_NULL(typ->ty_getty), STRING_OR_NULL(typ->ty_type), +         typ->ty_status, STRING_OR_NULL(typ->ty_window), +         STRING_OR_NULL(typ->ty_comment), STRING_OR_NULL(typ->ty_class)); + +  endttyent(); +} + +void test3() { +  if (!setttyent()) +    exit(1); + +  struct ttyent *typ = getttyent(); + +  printf("%s %s %s %d %s %s %s\n", STRING_OR_NULL(typ->ty_name), +         STRING_OR_NULL(typ->ty_getty), STRING_OR_NULL(typ->ty_type), +         typ->ty_status, STRING_OR_NULL(typ->ty_window), +         STRING_OR_NULL(typ->ty_comment), STRING_OR_NULL(typ->ty_class)); + +  endttyent(); +} + +void test4() { +  if (!setttyentpath(_PATH_TTYS)) +    exit(1); + +  struct ttyent *typ = getttyent(); + +  printf("%s %s %s %d %s %s %s\n", STRING_OR_NULL(typ->ty_name), +         STRING_OR_NULL(typ->ty_getty), STRING_OR_NULL(typ->ty_type), +         typ->ty_status, STRING_OR_NULL(typ->ty_window), +         STRING_OR_NULL(typ->ty_comment), STRING_OR_NULL(typ->ty_class)); + +  endttyent(); +} + +int main(void) { +  printf("ttyent\n"); + +  test1(); +  test2(); +  test3(); +  test4(); + +  // CHECK: ttyent + +  return 0; +} diff --git a/test/sanitizer_common/TestCases/NetBSD/uid_from_user.cc b/test/sanitizer_common/TestCases/NetBSD/uid_from_user.cc new file mode 100644 index 0000000000000..4cc1366aad4b0 --- /dev/null +++ b/test/sanitizer_common/TestCases/NetBSD/uid_from_user.cc @@ -0,0 +1,16 @@ +// RUN: %clangxx -O0 -g %s -o %t && %run %t + +#include <pwd.h> +#include <stdlib.h> + +int main(void) { +  uid_t nobody; + +  if (uid_from_user("nobody", &nobody) == -1) +    exit(1); + +  if (nobody) +    exit(0); + +  return 0; +} diff --git a/test/sanitizer_common/TestCases/NetBSD/user_from_uid.cc b/test/sanitizer_common/TestCases/NetBSD/user_from_uid.cc new file mode 100644 index 0000000000000..bb098525a4762 --- /dev/null +++ b/test/sanitizer_common/TestCases/NetBSD/user_from_uid.cc @@ -0,0 +1,17 @@ +// RUN: %clangxx -O0 -g %s -o %t && %run %t + +#include <pwd.h> +#include <stdlib.h> +#include <string.h> + +int main(void) { +  const char *nobody; + +  if (!(nobody = user_from_uid(0, 0))) +    exit(1); + +  if (strlen(nobody)) +    exit(0); + +  return 0; +} diff --git a/test/sanitizer_common/TestCases/Posix/access.cc b/test/sanitizer_common/TestCases/Posix/access.cc new file mode 100644 index 0000000000000..8623645f8bdfa --- /dev/null +++ b/test/sanitizer_common/TestCases/Posix/access.cc @@ -0,0 +1,5 @@ +// RUN: %clangxx -O0 -g %s -o %t && %run %t + +#include <unistd.h> + +int main(void) { return access("/dev/null", F_OK); } diff --git a/test/sanitizer_common/TestCases/Posix/devname.cc b/test/sanitizer_common/TestCases/Posix/devname.cc new file mode 100644 index 0000000000000..da4bb8853a128 --- /dev/null +++ b/test/sanitizer_common/TestCases/Posix/devname.cc @@ -0,0 +1,23 @@ +// RUN: %clangxx -O0 -g %s -o %t && %run %t 2>&1 | FileCheck %s +// UNSUPPORTED: linux, solaris + +#include <stdio.h> +#include <stdlib.h> +#include <sys/stat.h> + +int main(void) { +  struct stat st; +  char *name; + +  if (stat("/dev/null", &st)) +    exit(1); + +  if (!(name = devname(st.st_rdev, S_ISCHR(st.st_mode) ? S_IFCHR : S_IFBLK))) +    exit(1); + +  printf("%s\n", name); + +  // CHECK: null + +  return 0; +} diff --git a/test/sanitizer_common/TestCases/Posix/devname_r.cc b/test/sanitizer_common/TestCases/Posix/devname_r.cc new file mode 100644 index 0000000000000..826b7c92ef2fa --- /dev/null +++ b/test/sanitizer_common/TestCases/Posix/devname_r.cc @@ -0,0 +1,28 @@ +// RUN: %clangxx -O0 -g %s -o %t && %run %t 2>&1 | FileCheck %s +// UNSUPPORTED: linux, solaris + +#include <sys/cdefs.h> +#include <sys/stat.h> + +#include <stdio.h> +#include <stdlib.h> + +int main(void) { +  struct stat st; +  char name[100]; +  mode_t type; + +  if (stat("/dev/null", &st)) +    exit(1); + +  type = S_ISCHR(st.st_mode) ? S_IFCHR : S_IFBLK; + +  if (!devname_r(st.st_rdev, type, name, sizeof(name))) +    exit(1); + +  printf("%s\n", name); + +  // CHECK: null + +  return 0; +} diff --git a/test/sanitizer_common/TestCases/Posix/fgetln.cc b/test/sanitizer_common/TestCases/Posix/fgetln.cc new file mode 100644 index 0000000000000..e98cf449a2724 --- /dev/null +++ b/test/sanitizer_common/TestCases/Posix/fgetln.cc @@ -0,0 +1,24 @@ +// RUN: %clangxx -O0 -g %s -o %t && %run %t +// UNSUPPORTED: linux + +#include <stdio.h> +#include <stdlib.h> + +int main(void) { +  FILE *fp; +  size_t len; +  char *s; + +  fp = fopen("/etc/hosts", "r"); +  if (!fp) +    exit(1); + +  s = fgetln(fp, &len); + +  printf("%.*s\n", (int)len, s); + +  if (fclose(fp) == EOF) +    exit(1); + +  return 0; +} diff --git a/test/sanitizer_common/TestCases/Posix/fgets.cc b/test/sanitizer_common/TestCases/Posix/fgets.cc new file mode 100644 index 0000000000000..8dde5cd1a84fb --- /dev/null +++ b/test/sanitizer_common/TestCases/Posix/fgets.cc @@ -0,0 +1,20 @@ +// RUN: %clangxx -g %s -o %t && %run %t + +#include <stdio.h> + +int main(int argc, char **argv) { +  FILE *fp; +  char buf[2]; +  char *s; + +  fp = fopen(argv[0], "r"); +  if (!fp) +    return 1; + +  s = fgets(buf, sizeof(buf), fp); +  if (!s) +    return 2; + +  fclose(fp); +  return 0; +} diff --git a/test/sanitizer_common/TestCases/Posix/fputs_puts.cc b/test/sanitizer_common/TestCases/Posix/fputs_puts.cc new file mode 100644 index 0000000000000..8e8f7d384e8c8 --- /dev/null +++ b/test/sanitizer_common/TestCases/Posix/fputs_puts.cc @@ -0,0 +1,18 @@ +// RUN: %clangxx -g %s -o %t && %run %t | FileCheck %s +// CHECK: {{^foobar$}} + +#include <stdio.h> + +int main(void) { +  int r; + +  r = fputs("foo", stdout); +  if (r < 0) +    return 1; + +  r = puts("bar"); +  if (r < 0) +    return 1; + +  return 0; +} diff --git a/test/sanitizer_common/TestCases/Posix/getpass.cc b/test/sanitizer_common/TestCases/Posix/getpass.cc index b91a3d7d5264f..bf198eff91d29 100644 --- a/test/sanitizer_common/TestCases/Posix/getpass.cc +++ b/test/sanitizer_common/TestCases/Posix/getpass.cc @@ -5,13 +5,19 @@  #include <assert.h>  #include <stdio.h> -#include <unistd.h>  #include <string.h>  #if __linux__  #include <pty.h> +#elif defined(__FreeBSD__) +#include <libutil.h> +#include <pwd.h> +#include <sys/ioctl.h> +#include <sys/termios.h> +#include <sys/types.h>  #else  #include <util.h>  #endif +#include <unistd.h>  int  main (int argc, char** argv) diff --git a/test/sanitizer_common/TestCases/Posix/illegal_read_test.cc b/test/sanitizer_common/TestCases/Posix/illegal_read_test.cc new file mode 100644 index 0000000000000..9615d7132da5e --- /dev/null +++ b/test/sanitizer_common/TestCases/Posix/illegal_read_test.cc @@ -0,0 +1,15 @@ +// Test that there was an illegal READ memory access. +// RUN: %clangxx -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s + +// REQUIRES: stable-runtime +// XFAIL: powerpc64, s390x + +volatile int *null = 0; +volatile int a; + +int main(int argc, char **argv) { +  a = *null; +  return 0; +} + +// CHECK: The signal is caused by a READ memory access. diff --git a/test/sanitizer_common/TestCases/Posix/illegal_write_test.cc b/test/sanitizer_common/TestCases/Posix/illegal_write_test.cc new file mode 100644 index 0000000000000..13d1c6a06905a --- /dev/null +++ b/test/sanitizer_common/TestCases/Posix/illegal_write_test.cc @@ -0,0 +1,14 @@ +// Test that there was an illegal WRITE memory access. +// RUN: %clangxx -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s + +// REQUIRES: stable-runtime +// XFAIL: powerpc64, s390x + +volatile int *null = 0; + +int main(int argc, char **argv) { +  *null = 0; +  return 0; +} + +// CHECK: The signal is caused by a WRITE memory access. diff --git a/test/sanitizer_common/TestCases/Posix/lstat.cc b/test/sanitizer_common/TestCases/Posix/lstat.cc new file mode 100644 index 0000000000000..37237d82102cd --- /dev/null +++ b/test/sanitizer_common/TestCases/Posix/lstat.cc @@ -0,0 +1,16 @@ +// RUN: %clangxx -O0 -g %s -o %t && %run %t + +#include <stdlib.h> +#include <sys/stat.h> + +int main(void) { +  struct stat st; + +  if (lstat("/dev/null", &st)) +    exit(1); + +  if (!S_ISCHR(st.st_mode)) +    exit(1); + +  return 0; +} diff --git a/test/sanitizer_common/TestCases/Posix/mmap_test.c b/test/sanitizer_common/TestCases/Posix/mmap_test.c new file mode 100644 index 0000000000000..3c272f95a015c --- /dev/null +++ b/test/sanitizer_common/TestCases/Posix/mmap_test.c @@ -0,0 +1,11 @@ +// RUN: %clang %s -o %t && %run %t + +#include <assert.h> +#include <sys/mman.h> + +int main() { +  char *buf = (char *)mmap(0, 100000, PROT_READ | PROT_WRITE, +                           MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); +  assert(buf); +  munmap(buf, 100000); +} diff --git a/test/sanitizer_common/TestCases/Posix/posix_memalign-alignment.cc b/test/sanitizer_common/TestCases/Posix/posix_memalign-alignment.cc new file mode 100644 index 0000000000000..7729057d2deb7 --- /dev/null +++ b/test/sanitizer_common/TestCases/Posix/posix_memalign-alignment.cc @@ -0,0 +1,47 @@ +// RUN: %clangxx %collect_stack_traces -O0 %s -o %t + +// Alignment is not a power of two: +// RUN: %env_tool_opts=allocator_may_return_null=0 not %run %t 17 2>&1 | FileCheck %s +// Alignment is not a power of two, although is a multiple of sizeof(void*): +// RUN: %env_tool_opts=allocator_may_return_null=0 not %run %t 24 2>&1 | FileCheck %s +// Alignment is not a multiple of sizeof(void*), although is a power of 2: +// RUN: %env_tool_opts=allocator_may_return_null=0 not %run %t 2 2>&1 | FileCheck %s +// Alignment is 0: +// RUN: %env_tool_opts=allocator_may_return_null=0 not %run %t 0 2>&1 | FileCheck %s + +// The same for allocator_may_return_null=1: +// RUN: %env_tool_opts=allocator_may_return_null=1 %run %t 17 2>&1 | FileCheck %s --check-prefix=CHECK-NULL +// RUN: %env_tool_opts=allocator_may_return_null=1 %run %t 24 2>&1 | FileCheck %s --check-prefix=CHECK-NULL +// RUN: %env_tool_opts=allocator_may_return_null=1 %run %t 2 2>&1 | FileCheck %s --check-prefix=CHECK-NULL +// RUN: %env_tool_opts=allocator_may_return_null=1 %run %t 0 2>&1 | FileCheck %s --check-prefix=CHECK-NULL + +// REQUIRES: stable-runtime + +// UNSUPPORTED: ubsan + +#include <assert.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> + +int main(int argc, char **argv) { +  assert(argc == 2); +  const int alignment = atoi(argv[1]); + +  void* const kInitialPtrValue = reinterpret_cast<void*>(0x2a); +  void *p = kInitialPtrValue; + +  errno = 0; +  int res = posix_memalign(&p, alignment, 100); +  // CHECK: {{ERROR: .*Sanitizer: invalid alignment requested in posix_memalign}} +  // CHECK: {{#0 .*posix_memalign}} +  // CHECK: {{#1 .*main .*posix_memalign-alignment.cc:}}[[@LINE-3]] +  // CHECK: {{SUMMARY: .*Sanitizer: invalid-posix-memalign-alignment}} + +  // The NULL pointer is printed differently on different systems, while (long)0 +  // is always the same. +  fprintf(stderr, "errno: %d, res: %d, p: %lx\n", errno, res, (long)p); +  // CHECK-NULL: errno: 0, res: 22, p: 2a + +  return 0; +} diff --git a/test/sanitizer_common/TestCases/Posix/readlink.c b/test/sanitizer_common/TestCases/Posix/readlink.c new file mode 100644 index 0000000000000..ef0a4fe358b01 --- /dev/null +++ b/test/sanitizer_common/TestCases/Posix/readlink.c @@ -0,0 +1,26 @@ +// RUN: %clang -O0 %s -o %t && %run %t + +#include <assert.h> +#include <fcntl.h> +#include <limits.h> +#include <stdio.h> +#include <string.h> +#include <sys/types.h> +#include <unistd.h> + +int main(int argc, char **argv) { +  char symlink_path[PATH_MAX]; +  snprintf(symlink_path, sizeof(symlink_path), "%s_%d.symlink", argv[0], +           getpid()); +  remove(symlink_path); +  int res = symlink(argv[0], symlink_path); +  assert(!res); + +  char readlink_path[PATH_MAX]; +  ssize_t res2 = readlink(symlink_path, readlink_path, sizeof(readlink_path)); +  assert(res2 >= 0); +  readlink_path[res2] = '\0'; +  assert(!strcmp(readlink_path, argv[0])); + +  return 0; +} diff --git a/test/sanitizer_common/TestCases/Posix/readlinkat.c b/test/sanitizer_common/TestCases/Posix/readlinkat.c new file mode 100644 index 0000000000000..0afb5efe6b5f8 --- /dev/null +++ b/test/sanitizer_common/TestCases/Posix/readlinkat.c @@ -0,0 +1,26 @@ +// RUN: %clang -O0 %s -o %t && %run %t + +#include <assert.h> +#include <fcntl.h> +#include <limits.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> + +int main(int argc, char **argv) { +  char symlink_path[PATH_MAX]; +  snprintf(symlink_path, sizeof(symlink_path), "%s_%d.symlink", argv[0], +           getpid()); +  remove(symlink_path); +  int res = symlink(argv[0], symlink_path); +  assert(!res); + +  char readlinkat_path[PATH_MAX]; +  int res2 = readlinkat(AT_FDCWD, symlink_path, readlinkat_path, +                        sizeof(readlinkat_path)); +  assert(res2 >= 0); +  readlinkat_path[res2] = '\0'; +  assert(!strcmp(readlinkat_path, argv[0])); + +  return 0; +} diff --git a/test/sanitizer_common/TestCases/Posix/sanitizer_set_death_callback_test.cc b/test/sanitizer_common/TestCases/Posix/sanitizer_set_death_callback_test.cc index 8d2db364114ac..54272b0175043 100644 --- a/test/sanitizer_common/TestCases/Posix/sanitizer_set_death_callback_test.cc +++ b/test/sanitizer_common/TestCases/Posix/sanitizer_set_death_callback_test.cc @@ -2,12 +2,6 @@  // REQUIRES: stable-runtime -// For standalone LSan on x86 we have a problem: compiler spills the address -// of allocated at line 42 memory thus memory block allocated in Leak() function -// ends up to be classified as reachable despite the fact we zero out 'sink' at -// the last line of main function. The problem doesn't reproduce with ASan because -// quarantine prohibits memory block reuse for different allocations. -// XFAIL: lsan-x86  // XFAIL: ubsan  #include <sanitizer/common_interface_defs.h> @@ -31,7 +25,10 @@ void MaybeInit(int *uninitialized) {  __attribute__((noinline))  void Leak() { -  sink = new char[100];  // trigger lsan report. +  // Trigger lsan report. Two attempts in case the address of the first +  // allocation remained on the stack. +  sink = new char[100]; +  sink = new char[100];  }  int main(int argc, char **argv) { diff --git a/test/sanitizer_common/TestCases/Posix/strlcat.cc b/test/sanitizer_common/TestCases/Posix/strlcat.cc new file mode 100644 index 0000000000000..bdabada76aa77 --- /dev/null +++ b/test/sanitizer_common/TestCases/Posix/strlcat.cc @@ -0,0 +1,54 @@ +// RUN: %clangxx -O0 -g %s -o %t && %run %t + +// UNSUPPORTED: linux + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +void test1() { +  const char src[] = "abc"; +  char dst[7] = {'x', 'y', 'z', 0}; +  size_t len; + +  len = strlcat(dst, src, sizeof(dst)); +  printf("%s %zu ", dst, len); +} + +void test2() { +  const char src[] = "abc"; +  char dst[7] = {0}; +  size_t len; + +  len = strlcat(dst, src, sizeof(dst)); +  printf("%s %zu ", dst, len); +} + +void test3() { +  const char src[] = "abc"; +  char dst[4] = {'x', 'y', 'z', 0}; +  size_t len; + +  len = strlcat(dst, src, sizeof(dst)); +  printf("%s %zu ", dst, len); +} + +void test4() { +  const char src[] = ""; +  char dst[4] = {'x', 'y', 'z', 0}; +  size_t len; + +  len = strlcat(dst, src, sizeof(dst)); +  printf("%s %zu\n", dst, len); +} + +int main(void) { +  test1(); +  test2(); +  test3(); +  test4(); + +  // CHECK: xyzabc 6 abc 3 xyz 3 xyz 3 + +  return 0; +} diff --git a/test/sanitizer_common/TestCases/Posix/strlcpy.cc b/test/sanitizer_common/TestCases/Posix/strlcpy.cc new file mode 100644 index 0000000000000..83053911d965a --- /dev/null +++ b/test/sanitizer_common/TestCases/Posix/strlcpy.cc @@ -0,0 +1,54 @@ +// RUN: %clangxx -O0 -g %s -o %t && %run %t + +// UNSUPPORTED: linux + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +void test1() { +  const char src[] = "abc"; +  char dst[7] = {'x', 'y', 'z', 0}; +  size_t len; + +  len = strlcpy(dst, src, sizeof(dst)); +  printf("%s %zu ", dst, len); +} + +void test2() { +  const char src[] = "abc"; +  char dst[7] = {0}; +  size_t len; + +  len = strlcat(dst, src, sizeof(dst)); +  printf("%s %zu ", dst, len); +} + +void test3() { +  const char src[] = "abc"; +  char dst[4] = {'x', 'y', 'z', 0}; +  size_t len; + +  len = strlcat(dst, src, sizeof(dst)); +  printf("%s %zu ", dst, len); +} + +void test4() { +  const char src[] = ""; +  char dst[4] = {'x', 'y', 'z', 0}; +  size_t len; + +  len = strlcat(dst, src, sizeof(dst)); +  printf("%s %zu\n", dst, len); +} + +int main(void) { +  test1(); +  test2(); +  test3(); +  test4(); + +  // CHECK: abc 3 abc 3 xyz 3  0 + +  return 0; +} diff --git a/test/sanitizer_common/TestCases/Posix/strxfrm.c b/test/sanitizer_common/TestCases/Posix/strxfrm.c new file mode 100644 index 0000000000000..c28eb65b7d4f0 --- /dev/null +++ b/test/sanitizer_common/TestCases/Posix/strxfrm.c @@ -0,0 +1,20 @@ +// RUN: %clang -O0 %s -o %t && %run %t +// UNSUPPORTED: darwin + +#include <assert.h> +#include <locale.h> +#include <wchar.h> + +int main(int argc, char **argv) { +  char q[10]; +  size_t n = strxfrm(q, "abcdef", sizeof(q)); +  assert(n < sizeof(q)); + +  char q2[10]; +  locale_t loc = newlocale(LC_ALL_MASK, "", (locale_t)0); +  n = strxfrm_l(q2, L"qwerty", sizeof(q), loc); +  assert(n < sizeof(q2)); + +  freelocale(loc); +  return 0; +} diff --git a/test/sanitizer_common/TestCases/Posix/wcsxfrm.c b/test/sanitizer_common/TestCases/Posix/wcsxfrm.c new file mode 100644 index 0000000000000..3e349c75f4090 --- /dev/null +++ b/test/sanitizer_common/TestCases/Posix/wcsxfrm.c @@ -0,0 +1,20 @@ +// RUN: %clang -O0 %s -o %t && %run %t +// UNSUPPORTED: darwin + +#include <assert.h> +#include <locale.h> +#include <wchar.h> + +int main(int argc, char **argv) { +  wchar_t q[10]; +  size_t n = wcsxfrm(q, L"abcdef", sizeof(q) / sizeof(wchar_t)); +  assert(n < sizeof(q)); + +  wchar_t q2[10]; +  locale_t loc = newlocale(LC_ALL_MASK, "", (locale_t)0); +  n = wcsxfrm_l(q2, L"qwerty", sizeof(q) / sizeof(wchar_t), loc); +  assert(n < sizeof(q2)); + +  freelocale(loc); +  return 0; +} diff --git a/test/sanitizer_common/TestCases/allocator_returns_null.cc b/test/sanitizer_common/TestCases/allocator_returns_null.cc new file mode 100644 index 0000000000000..9ecdfef9ffcd4 --- /dev/null +++ b/test/sanitizer_common/TestCases/allocator_returns_null.cc @@ -0,0 +1,114 @@ +// Test the behavior of malloc/calloc/realloc/new when the allocation size +// exceeds the sanitizer's allocator max allowed one. +// By default (allocator_may_return_null=0) the process should crash. With +// allocator_may_return_null=1 the allocator should return nullptr and set errno +// to the appropriate error code. +// +// RUN: %clangxx -O0 %s -o %t +// RUN: not %run %t malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mCRASH +// RUN: %env_tool_opts=allocator_may_return_null=0 not %run %t malloc 2>&1 \ +// RUN:   | FileCheck %s --check-prefix=CHECK-mCRASH +// RUN: %env_tool_opts=allocator_may_return_null=1     %run %t malloc 2>&1 \ +// RUN:   | FileCheck %s --check-prefix=CHECK-NULL +// RUN: %env_tool_opts=allocator_may_return_null=0 not %run %t calloc 2>&1 \ +// RUN:   | FileCheck %s --check-prefix=CHECK-cCRASH +// RUN: %env_tool_opts=allocator_may_return_null=1     %run %t calloc 2>&1 \ +// RUN:   | FileCheck %s --check-prefix=CHECK-NULL +// RUN: %env_tool_opts=allocator_may_return_null=0 not %run %t calloc-overflow 2>&1 \ +// RUN:   | FileCheck %s --check-prefix=CHECK-coCRASH +// RUN: %env_tool_opts=allocator_may_return_null=1     %run %t calloc-overflow 2>&1 \ +// RUN:   | FileCheck %s --check-prefix=CHECK-NULL +// RUN: %env_tool_opts=allocator_may_return_null=0 not %run %t realloc 2>&1 \ +// RUN:   | FileCheck %s --check-prefix=CHECK-rCRASH +// RUN: %env_tool_opts=allocator_may_return_null=1     %run %t realloc 2>&1 \ +// RUN:   | FileCheck %s --check-prefix=CHECK-NULL +// RUN: %env_tool_opts=allocator_may_return_null=0 not %run %t realloc-after-malloc 2>&1 \ +// RUN:   | FileCheck %s --check-prefix=CHECK-mrCRASH +// RUN: %env_tool_opts=allocator_may_return_null=1     %run %t realloc-after-malloc 2>&1 \ +// RUN:   | FileCheck %s --check-prefix=CHECK-NULL +// RUN: %env_tool_opts=allocator_may_return_null=0 not %run %t new 2>&1 \ +// RUN:   | FileCheck %s --check-prefix=CHECK-nCRASH +// RUN: %env_tool_opts=allocator_may_return_null=1 not %run %t new 2>&1 \ +// RUN:   | FileCheck %s --check-prefix=CHECK-nCRASH-OOM +// RUN: %env_tool_opts=allocator_may_return_null=0 not %run %t new-nothrow 2>&1 \ +// RUN:   | FileCheck %s --check-prefix=CHECK-nnCRASH +// RUN: %env_tool_opts=allocator_may_return_null=1     %run %t new-nothrow 2>&1 \ +// RUN:   | FileCheck %s --check-prefix=CHECK-NULL + +// TODO(alekseyshl): win32 is disabled due to failing errno tests, fix it there. +// UNSUPPORTED: ubsan, win32 + +#include <assert.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <limits> +#include <new> + +int main(int argc, char **argv) { +  assert(argc == 2); +  const char *action = argv[1]; +  fprintf(stderr, "%s:\n", action); + +  // The maximum value of all supported sanitizers (search for +  // kMaxAllowedMallocSize). For ASan + LSan, ASan limit is used. +  static const size_t kMaxAllowedMallocSizePlusOne = +#if __LP64__ || defined(_WIN64) +      (1ULL << 40) + 1; +#else +      (3UL << 30) + 1; +#endif + +  void *x = nullptr; +  if (!strcmp(action, "malloc")) { +    x = malloc(kMaxAllowedMallocSizePlusOne); +  } else if (!strcmp(action, "calloc")) { +    x = calloc((kMaxAllowedMallocSizePlusOne / 4) + 1, 4); +  } else if (!strcmp(action, "calloc-overflow")) { +    volatile size_t kMaxSizeT = std::numeric_limits<size_t>::max(); +    size_t kArraySize = 4096; +    volatile size_t kArraySize2 = kMaxSizeT / kArraySize + 10; +    x = calloc(kArraySize, kArraySize2); +  } else if (!strcmp(action, "realloc")) { +    x = realloc(0, kMaxAllowedMallocSizePlusOne); +  } else if (!strcmp(action, "realloc-after-malloc")) { +    char *t = (char*)malloc(100); +    *t = 42; +    x = realloc(t, kMaxAllowedMallocSizePlusOne); +    assert(*t == 42); +    free(t); +  } else if (!strcmp(action, "new")) { +    x = operator new(kMaxAllowedMallocSizePlusOne); +  } else if (!strcmp(action, "new-nothrow")) { +    x = operator new(kMaxAllowedMallocSizePlusOne, std::nothrow); +  } else { +    assert(0); +  } + +  // The NULL pointer is printed differently on different systems, while (long)0 +  // is always the same. +  fprintf(stderr, "errno: %d, x: %lx\n", errno, (long)x); + +  return 0; +} + +// CHECK-mCRASH: malloc: +// CHECK-mCRASH: {{SUMMARY: .*Sanitizer: allocation-size-too-big}} +// CHECK-cCRASH: calloc: +// CHECK-cCRASH: {{SUMMARY: .*Sanitizer: allocation-size-too-big}} +// CHECK-coCRASH: calloc-overflow: +// CHECK-coCRASH: {{SUMMARY: .*Sanitizer: calloc-overflow}} +// CHECK-rCRASH: realloc: +// CHECK-rCRASH: {{SUMMARY: .*Sanitizer: allocation-size-too-big}} +// CHECK-mrCRASH: realloc-after-malloc: +// CHECK-mrCRASH: {{SUMMARY: .*Sanitizer: allocation-size-too-big}} +// CHECK-nCRASH: new: +// CHECK-nCRASH: {{SUMMARY: .*Sanitizer: allocation-size-too-big}} +// CHECK-nCRASH-OOM: new: +// CHECK-nCRASH-OOM: {{SUMMARY: .*Sanitizer: out-of-memory}} +// CHECK-nnCRASH: new-nothrow: +// CHECK-nnCRASH: {{SUMMARY: .*Sanitizer: allocation-size-too-big}} + +// CHECK-NULL: {{malloc|calloc|calloc-overflow|realloc|realloc-after-malloc|new-nothrow}} +// CHECK-NULL: errno: 12, x: 0 diff --git a/test/sanitizer_common/TestCases/ctype.c b/test/sanitizer_common/TestCases/ctype.c new file mode 100644 index 0000000000000..37e0af89be6d1 --- /dev/null +++ b/test/sanitizer_common/TestCases/ctype.c @@ -0,0 +1,89 @@ +// RUN: %clang %s -o %t && %run %t 2>&1 | FileCheck %s + +#include <ctype.h> +#include <limits.h> +#include <locale.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> + +void check_ctype(void) { +  unsigned char c; +  volatile size_t i = 0; /* a dummy variable to prevent optimizing code out */ + +  for (c = 0; c < UCHAR_MAX; c++) +    i += !!isalpha(c); +  for (c = 0; c < UCHAR_MAX; c++) +    i += !!isascii(c); +  for (c = 0; c < UCHAR_MAX; c++) +    i += !!isblank(c); +  for (c = 0; c < UCHAR_MAX; c++) +    i += !!iscntrl(c); +  for (c = 0; c < UCHAR_MAX; c++) +    i += !!isdigit(c); +  for (c = 0; c < UCHAR_MAX; c++) +    i += !!isgraph(c); +  for (c = 0; c < UCHAR_MAX; c++) +    i += !!islower(c); +  for (c = 0; c < UCHAR_MAX; c++) +    i += !!isprint(c); +  for (c = 0; c < UCHAR_MAX; c++) +    i += !!ispunct(c); +  for (c = 0; c < UCHAR_MAX; c++) +    i += !!isspace(c); +  for (c = 0; c < UCHAR_MAX; c++) +    i += !!isupper(c); +  for (c = 0; c < UCHAR_MAX; c++) +    i += !!isxdigit(c); +  for (c = 0; c < UCHAR_MAX; c++) +    i += !!isalnum(c); + +  for (c = 0; c < UCHAR_MAX; c++) +    i += !!tolower(c); +  for (c = 0; c < UCHAR_MAX; c++) +    i += !!toupper(c); + +  i += !!isalpha(EOF); +  i += !!isascii(EOF); +  i += !!isblank(EOF); +  i += !!iscntrl(EOF); +  i += !!isdigit(EOF); +  i += !!isgraph(EOF); +  i += !!islower(EOF); +  i += !!isprint(EOF); +  i += !!ispunct(EOF); +  i += !!isspace(EOF); +  i += !!isupper(EOF); +  i += !!isxdigit(EOF); +  i += !!isalnum(EOF); + +  i += !!tolower(EOF); +  i += !!toupper(EOF); + +  if (i) +    return; +  else +    return; +} + +int main(int argc, char **argv) { +  check_ctype(); + +  setlocale(LC_ALL, ""); + +  check_ctype(); + +  setlocale(LC_ALL, "en_US.UTF-8"); + +  check_ctype(); + +  setlocale(LC_CTYPE, "pl_PL.UTF-8"); + +  check_ctype(); + +  printf("OK\n"); + +  // CHECK: OK + +  return 0; +} diff --git a/test/sanitizer_common/TestCases/get_module_and_offset_for_pc.cc b/test/sanitizer_common/TestCases/get_module_and_offset_for_pc.cc index 69ccb7234fabc..0591d356f1361 100644 --- a/test/sanitizer_common/TestCases/get_module_and_offset_for_pc.cc +++ b/test/sanitizer_common/TestCases/get_module_and_offset_for_pc.cc @@ -1,5 +1,6 @@ -// RUN: %clangxx -DSHARED %s -shared -o %T/get_module_and_offset_for_pc.so -fPIC -// RUN: %clangxx -DSO_DIR=\"%T\" -O0 %s -ldl -o %t +// RUN: mkdir -p %t-dir +// RUN: %clangxx -DSHARED %s -shared -o %t-dir/get_module_and_offset_for_pc.so -fPIC +// RUN: %clangxx -DSO_DIR=\"%t-dir\" -O0 %s -ldl -o %t  // RUN: %run %t 2>&1 | FileCheck %s  // UNSUPPORTED: i386-darwin diff --git a/test/sanitizer_common/ios_commands/iossim_prepare.py b/test/sanitizer_common/ios_commands/iossim_prepare.py new file mode 100755 index 0000000000000..4b618fe9de8ab --- /dev/null +++ b/test/sanitizer_common/ios_commands/iossim_prepare.py @@ -0,0 +1,5 @@ +#!/usr/bin/python + +import os, sys, subprocess, json + +print(json.dumps({"env": {}})) diff --git a/test/sanitizer_common/lit.common.cfg b/test/sanitizer_common/lit.common.cfg index c7a1682f74042..1b347bf2bbac0 100644 --- a/test/sanitizer_common/lit.common.cfg +++ b/test/sanitizer_common/lit.common.cfg @@ -6,6 +6,7 @@ config.test_source_root = os.path.join(os.path.dirname(__file__), "TestCases")  config.name = "SanitizerCommon-" + config.name_suffix  default_tool_options = [] +collect_stack_traces = ""  if config.tool_name == "asan":    tool_cflags = ["-fsanitize=address"]    tool_options = "ASAN_OPTIONS" @@ -15,6 +16,7 @@ elif config.tool_name == "tsan":  elif config.tool_name == "msan":    tool_cflags = ["-fsanitize=memory"]    tool_options = "MSAN_OPTIONS" +  collect_stack_traces = "-fsanitize-memory-track-origins"  elif config.tool_name == "lsan":    tool_cflags = ["-fsanitize=leak"]    tool_options = "LSAN_OPTIONS" @@ -52,6 +54,7 @@ def build_invocation(compile_flags):  config.substitutions.append( ("%clang ", build_invocation(clang_cflags)) )  config.substitutions.append( ("%clangxx ", build_invocation(clang_cxxflags)) ) +config.substitutions.append( ("%collect_stack_traces", collect_stack_traces) )  config.substitutions.append( ("%tool_name", config.tool_name) )  config.substitutions.append( ("%tool_options", tool_options) )  config.substitutions.append( ('%env_tool_opts=', @@ -59,5 +62,5 @@ config.substitutions.append( ('%env_tool_opts=',  config.suffixes = ['.c', '.cc', '.cpp'] -if config.host_os not in ['Linux', 'Darwin']: +if config.host_os not in ['Linux', 'Darwin', 'NetBSD', 'FreeBSD']:    config.unsupported = True diff --git a/test/scudo/aligned-new.cpp b/test/scudo/aligned-new.cpp new file mode 100644 index 0000000000000..0a10ae188c922 --- /dev/null +++ b/test/scudo/aligned-new.cpp @@ -0,0 +1,86 @@ +// RUN: %clangxx_scudo -std=c++1z -faligned-allocation %s -o %t +// RUN:                                                 %run %t valid   2>&1 +// RUN: %env_scudo_opts=allocator_may_return_null=1     %run %t invalid 2>&1 +// RUN: %env_scudo_opts=allocator_may_return_null=0 not %run %t invalid 2>&1 | FileCheck %s + +// Tests that the C++17 aligned new/delete operators are working as expected. +// Currently we do not check the consistency of the alignment on deallocation, +// so this just tests that the APIs work. + +#include <assert.h> +#include <stdio.h> +#include <stdint.h> +#include <string.h> + +// Define all new/delete to not depend on the version provided by the platform. + +namespace std { +struct nothrow_t {}; +static const nothrow_t nothrow; +enum class align_val_t : size_t {}; +}  // namespace std + +void *operator new(size_t); +void *operator new[](size_t); +void *operator new(size_t, std::nothrow_t const&); +void *operator new[](size_t, std::nothrow_t const&); +void *operator new(size_t, std::align_val_t); +void *operator new[](size_t, std::align_val_t); +void *operator new(size_t, std::align_val_t, std::nothrow_t const&); +void *operator new[](size_t, std::align_val_t, std::nothrow_t const&); + +void operator delete(void*) throw(); +void operator delete[](void*) throw(); +void operator delete(void*, std::nothrow_t const&); +void operator delete[](void*, std::nothrow_t const&); +void operator delete(void*, size_t) throw(); +void operator delete[](void*, size_t) throw(); +void operator delete(void*, std::align_val_t) throw(); +void operator delete[](void*, std::align_val_t) throw(); +void operator delete(void*, std::align_val_t, std::nothrow_t const&); +void operator delete[](void*, std::align_val_t, std::nothrow_t const&); +void operator delete(void*, size_t, std::align_val_t) throw(); +void operator delete[](void*, size_t, std::align_val_t) throw(); + +template<typename T> +inline T* break_optimization(T *arg) { +  __asm__ __volatile__("" : : "r" (arg) : "memory"); +  return arg; +} + +struct S12 { int a, b, c; }; +struct alignas(128) S12_128 { int a, b, c; }; +struct alignas(256) S12_256 { int a, b, c; }; +struct alignas(512) S1024_512 { char a[1024]; }; +struct alignas(1024) S1024_1024 { char a[1024]; }; + +int main(int argc, char **argv) { +  assert(argc == 2); + +  if (!strcmp(argv[1], "valid")) { +    // Standard use case. +    delete break_optimization(new S12); +    delete break_optimization(new S12_128); +    delete[] break_optimization(new S12_128[4]); +    delete break_optimization(new S12_256); +    delete break_optimization(new S1024_512); +    delete[] break_optimization(new S1024_512[4]); +    delete break_optimization(new S1024_1024); + +    // Call directly the aligned versions of the operators. +    const size_t alignment = 1U << 8; +    void *p = operator new(1, static_cast<std::align_val_t>(alignment)); +    assert((reinterpret_cast<uintptr_t>(p) & (alignment - 1)) == 0); +    operator delete(p, static_cast<std::align_val_t>(alignment)); +  } +  if (!strcmp(argv[1], "invalid")) { +    // Alignment must be a power of 2. +    const size_t alignment = (1U << 8) - 1; +    void *p = operator new(1, static_cast<std::align_val_t>(alignment), +                           std::nothrow); +    // CHECK: Scudo ERROR: invalid allocation alignment +    assert(!p); +  } + +  return 0; +} diff --git a/test/scudo/alignment.c b/test/scudo/alignment.c index 6235d50608db2..4e2dc1af03b14 100644 --- a/test/scudo/alignment.c +++ b/test/scudo/alignment.c @@ -20,4 +20,4 @@ int main(int argc, char **argv)    return 0;  } -// CHECK: ERROR: attempted to deallocate a chunk not properly aligned +// CHECK: ERROR: misaligned pointer when deallocating address diff --git a/test/scudo/double-free.cpp b/test/scudo/double-free.cpp index 56118038cf1f3..de6c90f1cced1 100644 --- a/test/scudo/double-free.cpp +++ b/test/scudo/double-free.cpp @@ -2,7 +2,6 @@  // RUN: not %run %t malloc   2>&1 | FileCheck %s  // RUN: not %run %t new      2>&1 | FileCheck %s  // RUN: not %run %t newarray 2>&1 | FileCheck %s -// RUN: not %run %t memalign 2>&1 | FileCheck %s  // Tests double-free error on pointers allocated with different allocation  // functions. @@ -32,13 +31,6 @@ int main(int argc, char **argv)      delete[] p;      delete[] p;    } -  if (!strcmp(argv[1], "memalign")) { -    void *p = nullptr; -    posix_memalign(&p, 0x100, sizeof(int)); -    assert(p); -    free(p); -    free(p); -  }    return 0;  } diff --git a/test/scudo/fsanitize.c b/test/scudo/fsanitize.c new file mode 100644 index 0000000000000..7e5d5451f7263 --- /dev/null +++ b/test/scudo/fsanitize.c @@ -0,0 +1,28 @@ +// Test various -fsanitize= additional flags combinations. + +// RUN: %clang_scudo %s -o %t +// RUN: not %run %t 2>&1 | FileCheck %s + +// RUN: %clang_scudo -shared-libsan %s -o %t +// RUN: env LD_LIBRARY_PATH=`dirname %shared_libscudo`:$LD_LIBRARY_PATH not %run %t 2>&1 | FileCheck %s +// RUN: %clang_scudo -shared-libsan -fsanitize-minimal-runtime %s -o %t +// RUN: env LD_LIBRARY_PATH=`dirname %shared_minlibscudo`:$LD_LIBRARY_PATH not %run %t 2>&1 | FileCheck %s + +// RUN: %clang_scudo -static-libsan %s -o %t +// RUN: not %run %t 2>&1 | FileCheck %s +// RUN: %clang_scudo -static-libsan -fsanitize-minimal-runtime %s -o %t +// RUN: not %run %t 2>&1 | FileCheck %s + +#include <assert.h> +#include <stdlib.h> + +int main(int argc, char *argv[]) { +  unsigned long *p = (unsigned long *)malloc(sizeof(unsigned long)); +  assert(p); +  *p = 0; +  free(p); +  free(p); +  return 0; +} + +// CHECK: ERROR: invalid chunk state diff --git a/test/scudo/interface.cpp b/test/scudo/interface.cpp index 73ea0a738e43f..ec7375193e12b 100644 --- a/test/scudo/interface.cpp +++ b/test/scudo/interface.cpp @@ -4,7 +4,6 @@  // RUN:                                                   %run %t heap-size          2>&1  // RUN: %env_scudo_opts="allocator_may_return_null=1"     %run %t soft-limit         2>&1  // RUN: %env_scudo_opts="allocator_may_return_null=1" not %run %t hard-limit         2>&1 -// UNSUPPORTED: armhf-linux  // Tests that the sanitizer interface functions behave appropriately. @@ -51,8 +50,11 @@ int main(int argc, char **argv)      // Verifies that setting the soft RSS limit at runtime works as expected.      std::vector<void *> pointers;      size_t size = 1 << 19;  // 512Kb -    for (int i = 0; i < 5; i++) -      pointers.push_back(malloc(size)); +    for (int i = 0; i < 5; i++) { +      void *p = malloc(size); +      memset(p, 0, size); +      pointers.push_back(p); +    }      // Set the soft RSS limit to 1Mb.      __scudo_set_rss_limit(1, 0);      usleep(20000); @@ -74,8 +76,11 @@ int main(int argc, char **argv)      // Verifies that setting the hard RSS limit at runtime works as expected.      std::vector<void *> pointers;      size_t size = 1 << 19;  // 512Kb -    for (int i = 0; i < 5; i++) -      pointers.push_back(malloc(size)); +    for (int i = 0; i < 5; i++) { +      void *p = malloc(size); +      memset(p, 0, size); +      pointers.push_back(p); +    }      // Set the hard RSS limit to 1Mb      __scudo_set_rss_limit(1, 1);      usleep(20000); diff --git a/test/scudo/lit.cfg b/test/scudo/lit.cfg index 028bf721b89e9..df78d5f9d6adb 100644 --- a/test/scudo/lit.cfg +++ b/test/scudo/lit.cfg @@ -8,16 +8,12 @@ config.name = 'Scudo' + config.name_suffix  # Setup source root.  config.test_source_root = os.path.dirname(__file__) -# Path to the shared & static libraries -shared_libscudo = os.path.join(config.compiler_rt_libdir, "libclang_rt.scudo-%s.so" % config.target_arch) -static_libscudo = os.path.join(config.compiler_rt_libdir, "libclang_rt.scudo-%s.a" % config.target_arch) -static_libscudo_cxx = os.path.join(config.compiler_rt_libdir, "libclang_rt.scudo_cxx-%s.a" % config.target_arch) - -whole_archive = "-Wl,-whole-archive %s -Wl,-no-whole-archive " % static_libscudo -whole_archive_cxx = "-Wl,-whole-archive %s -Wl,-no-whole-archive " % static_libscudo_cxx +# Path to the shared library +shared_libscudo = os.path.join(config.compiler_rt_libdir, "libclang_rt.scudo%s.so" % config.target_suffix) +shared_minlibscudo = os.path.join(config.compiler_rt_libdir, "libclang_rt.scudo_minimal-%s.so" % config.target_arch)  # Test suffixes. -config.suffixes = ['.c', '.cc', '.cpp'] +config.suffixes = ['.c', '.cc', '.cpp', '.test']  # C & CXX flags.  c_flags = ([config.target_cflags] + @@ -35,14 +31,17 @@ if not config.android:  cxx_flags = (c_flags + config.cxx_mode_flags + ["-std=c++11"]) -def build_invocation(compile_flags):                                             +scudo_flags = ["-fsanitize=scudo"] + +def build_invocation(compile_flags):    return " " + " ".join([config.clang] + compile_flags) + " " -# Add clang substitutions. +# Add substitutions.  config.substitutions.append(("%clang ", build_invocation(c_flags))) -config.substitutions.append(("%clang_scudo ", build_invocation(c_flags) + whole_archive)) -config.substitutions.append(("%clangxx_scudo ", build_invocation(cxx_flags) + whole_archive + whole_archive_cxx)) +config.substitutions.append(("%clang_scudo ", build_invocation(c_flags + scudo_flags))) +config.substitutions.append(("%clangxx_scudo ", build_invocation(cxx_flags + scudo_flags)))  config.substitutions.append(("%shared_libscudo", shared_libscudo)) +config.substitutions.append(("%shared_minlibscudo", shared_minlibscudo))  # Platform-specific default SCUDO_OPTIONS for lit tests.  default_scudo_opts = '' diff --git a/test/scudo/memalign.c b/test/scudo/memalign.c index 1fe6e3ec7eed5..675f534151938 100644 --- a/test/scudo/memalign.c +++ b/test/scudo/memalign.c @@ -1,7 +1,10 @@  // RUN: %clang_scudo %s -o %t -// RUN:                                                 %run %t valid   2>&1 -// RUN:                                             not %run %t invalid 2>&1 -// RUN: %env_scudo_opts=allocator_may_return_null=1     %run %t invalid 2>&1 +// RUN:                                                 %run %t valid       2>&1 +// RUN:                                             not %run %t invalid     2>&1 | FileCheck --check-prefix=CHECK-align %s +// RUN: %env_scudo_opts=allocator_may_return_null=1     %run %t invalid     2>&1 +// RUN:                                             not %run %t double-free 2>&1 | FileCheck --check-prefix=CHECK-double-free %s +// RUN: %env_scudo_opts=DeallocationTypeMismatch=1  not %run %t realloc     2>&1 | FileCheck --check-prefix=CHECK-realloc %s +// RUN: %env_scudo_opts=DeallocationTypeMismatch=0      %run %t realloc     2>&1  // Tests that the various aligned allocation functions work as intended. Also  // tests for the condition where the alignment is not a power of 2. @@ -51,6 +54,7 @@ int main(int argc, char **argv)      // For larger alignment, reduce the number of allocations to avoid running      // out of potential addresses (on 32-bit).      for (int i = 19; i <= 24; i++) { +      alignment = 1U << i;        for (int k = 0; k < 3; k++) {          p = memalign(alignment, 0x1000 - (2 * sizeof(void *) * k));          assert(p); @@ -62,6 +66,7 @@ int main(int argc, char **argv)    if (!strcmp(argv[1], "invalid")) {      // Alignment is not a power of 2.      p = memalign(alignment - 1, size); +    // CHECK-align: Scudo ERROR: invalid allocation alignment      assert(!p);      // Size is not a multiple of alignment.      p = aligned_alloc(alignment, size >> 1); @@ -77,5 +82,22 @@ int main(int argc, char **argv)      assert(p == p_unchanged);      assert(err == EINVAL);    } +  if (!strcmp(argv[1], "double-free")) { +    void *p = NULL; +    posix_memalign(&p, 0x100, sizeof(int)); +    assert(p); +    free(p); +    free(p); +  } +  if (!strcmp(argv[1], "realloc")) { +    // We cannot reallocate a memalign'd chunk. +    void *p = memalign(16, 16); +    assert(p); +    p = realloc(p, 32); +    free(p); +  }    return 0;  } + +// CHECK-double-free: ERROR: invalid chunk state +// CHECK-realloc: ERROR: allocation type mismatch when reallocating address diff --git a/test/scudo/mismatch.cpp b/test/scudo/mismatch.cpp index b49e0ea46f12e..b794f66d8a4ea 100644 --- a/test/scudo/mismatch.cpp +++ b/test/scudo/mismatch.cpp @@ -1,18 +1,13 @@  // RUN: %clangxx_scudo %s -o %t -// RUN: %env_scudo_opts=DeallocationTypeMismatch=1 not %run %t mallocdel       2>&1 | FileCheck --check-prefix=CHECK-dealloc %s -// RUN: %env_scudo_opts=DeallocationTypeMismatch=0     %run %t mallocdel       2>&1 -// RUN: %env_scudo_opts=DeallocationTypeMismatch=1 not %run %t newfree         2>&1 | FileCheck --check-prefix=CHECK-dealloc %s -// RUN: %env_scudo_opts=DeallocationTypeMismatch=0     %run %t newfree         2>&1 -// RUN: %env_scudo_opts=DeallocationTypeMismatch=1 not %run %t memaligndel     2>&1 | FileCheck --check-prefix=CHECK-dealloc %s -// RUN: %env_scudo_opts=DeallocationTypeMismatch=0     %run %t memaligndel     2>&1 -// RUN: %env_scudo_opts=DeallocationTypeMismatch=1 not %run %t memalignrealloc 2>&1 | FileCheck --check-prefix=CHECK-realloc %s -// RUN: %env_scudo_opts=DeallocationTypeMismatch=0     %run %t memalignrealloc 2>&1 +// RUN: %env_scudo_opts=DeallocationTypeMismatch=1 not %run %t mallocdel 2>&1 | FileCheck --check-prefix=CHECK-dealloc %s +// RUN: %env_scudo_opts=DeallocationTypeMismatch=0     %run %t mallocdel 2>&1 +// RUN: %env_scudo_opts=DeallocationTypeMismatch=1 not %run %t newfree   2>&1 | FileCheck --check-prefix=CHECK-dealloc %s +// RUN: %env_scudo_opts=DeallocationTypeMismatch=0     %run %t newfree   2>&1  // Tests that type mismatches between allocation and deallocation functions are  // caught when the related option is set.  #include <assert.h> -#include <malloc.h>  #include <stdlib.h>  #include <string.h> @@ -29,17 +24,6 @@ int main(int argc, char **argv)      assert(p);      free((void *)p);    } -  if (!strcmp(argv[1], "memaligndel")) { -    int *p = (int *)memalign(16, 16); -    assert(p); -    delete p; -  } -  if (!strcmp(argv[1], "memalignrealloc")) { -    void *p = memalign(16, 16); -    assert(p); -    p = realloc(p, 32); -    free(p); -  }    return 0;  } diff --git a/test/scudo/preload.cpp b/test/scudo/preload.cpp index b41a70e472b3e..7fa8df4c69314 100644 --- a/test/scudo/preload.cpp +++ b/test/scudo/preload.cpp @@ -1,7 +1,8 @@  // Test that the preloaded runtime works without linking the static library.  // RUN: %clang %s -lstdc++ -o %t -// RUN: env LD_PRELOAD=%shared_libscudo not %run %t 2>&1 | FileCheck %s +// RUN: env LD_PRELOAD=%shared_libscudo    not %run %t 2>&1 | FileCheck %s +// RUN: env LD_PRELOAD=%shared_minlibscudo not %run %t 2>&1 | FileCheck %s  // This way of setting LD_PRELOAD does not work with Android test runner.  // REQUIRES: !android diff --git a/test/scudo/random_shuffle.cpp b/test/scudo/random_shuffle.cpp index f886cb1504e15..b493a292944c3 100644 --- a/test/scudo/random_shuffle.cpp +++ b/test/scudo/random_shuffle.cpp @@ -1,12 +1,12 @@  // RUN: %clangxx_scudo %s -o %t -// RUN: rm -rf %T/random_shuffle_tmp_dir -// RUN: mkdir %T/random_shuffle_tmp_dir -// RUN: %run %t 100 > %T/random_shuffle_tmp_dir/out1 -// RUN: %run %t 100 > %T/random_shuffle_tmp_dir/out2 -// RUN: %run %t 10000 > %T/random_shuffle_tmp_dir/out1 -// RUN: %run %t 10000 > %T/random_shuffle_tmp_dir/out2 -// RUN: not diff %T/random_shuffle_tmp_dir/out? -// RUN: rm -rf %T/random_shuffle_tmp_dir +// RUN: rm -rf %t-dir/random_shuffle_tmp_dir +// RUN: mkdir -p %t-dir/random_shuffle_tmp_dir +// RUN: %run %t 100 > %t-dir/random_shuffle_tmp_dir/out1 +// RUN: %run %t 100 > %t-dir/random_shuffle_tmp_dir/out2 +// RUN: %run %t 10000 > %t-dir/random_shuffle_tmp_dir/out1 +// RUN: %run %t 10000 > %t-dir/random_shuffle_tmp_dir/out2 +// RUN: not diff %t-dir/random_shuffle_tmp_dir/out? +// RUN: rm -rf %t-dir/random_shuffle_tmp_dir  // Tests that the allocator shuffles the chunks before returning to the user. diff --git a/test/scudo/realloc.cpp b/test/scudo/realloc.cpp index 254c67a2cca4f..26f6373b918e8 100644 --- a/test/scudo/realloc.cpp +++ b/test/scudo/realloc.cpp @@ -1,6 +1,6 @@  // RUN: %clangxx_scudo %s -lstdc++ -o %t -// RUN: %run %t pointers 2>&1 -// RUN: %run %t contents 2>&1 +// RUN: %run %t pointers   2>&1 +// RUN: %run %t contents   2>&1  // RUN: %run %t usablesize 2>&1  // Tests that our reallocation function returns the same pointer when the @@ -15,6 +15,8 @@  #include <vector> +#include <sanitizer/allocator_interface.h> +  int main(int argc, char **argv)  {    void *p, *old_p; @@ -35,7 +37,7 @@ int main(int argc, char **argv)        if (p) free(p);        size += 16;        p = malloc(size); -      usable_size = malloc_usable_size(p); +      usable_size = __sanitizer_get_allocated_size(p);        assert(usable_size >= size);      } while (usable_size == size);      for (int i = 0; i < usable_size; i++) @@ -56,7 +58,7 @@ int main(int argc, char **argv)        if (!strcmp(argv[1], "pointers")) {          old_p = p = realloc(nullptr, size);          assert(p); -        size = malloc_usable_size(p); +        size = __sanitizer_get_allocated_size(p);          // Our realloc implementation will return the same pointer if the size          // requested is lower than or equal to the usable size of the associated          // chunk. diff --git a/test/scudo/sized-delete.cpp b/test/scudo/sized-delete.cpp index 85df05e2f809c..81151b0974813 100644 --- a/test/scudo/sized-delete.cpp +++ b/test/scudo/sized-delete.cpp @@ -38,4 +38,4 @@ int main(int argc, char **argv)    return 0;  } -// CHECK: ERROR: invalid sized delete on chunk at address +// CHECK: ERROR: invalid sized delete when deallocating address diff --git a/test/scudo/sizes.cpp b/test/scudo/sizes.cpp index 73fc71f25c541..f7ccbebedc300 100644 --- a/test/scudo/sizes.cpp +++ b/test/scudo/sizes.cpp @@ -1,11 +1,11 @@  // RUN: %clangxx_scudo %s -lstdc++ -o %t -// RUN: %env_scudo_opts=allocator_may_return_null=0 not %run %t malloc 2>&1 | FileCheck %s +// RUN: %env_scudo_opts=allocator_may_return_null=0 not %run %t malloc 2>&1      | FileCheck %s --check-prefix=CHECK-max  // RUN: %env_scudo_opts=allocator_may_return_null=1     %run %t malloc 2>&1 -// RUN: %env_scudo_opts=allocator_may_return_null=0 not %run %t calloc 2>&1 | FileCheck %s +// RUN: %env_scudo_opts=allocator_may_return_null=0 not %run %t calloc 2>&1      | FileCheck %s --check-prefix=CHECK-calloc  // RUN: %env_scudo_opts=allocator_may_return_null=1     %run %t calloc 2>&1 -// RUN: %env_scudo_opts=allocator_may_return_null=0 not %run %t new 2>&1 | FileCheck %s -// RUN: %env_scudo_opts=allocator_may_return_null=1 not %run %t new 2>&1 | FileCheck %s -// RUN: %env_scudo_opts=allocator_may_return_null=0 not %run %t new-nothrow 2>&1 | FileCheck %s +// RUN: %env_scudo_opts=allocator_may_return_null=0 not %run %t new 2>&1         | FileCheck %s --check-prefix=CHECK-max +// RUN: %env_scudo_opts=allocator_may_return_null=1 not %run %t new 2>&1         | FileCheck %s --check-prefix=CHECK-oom +// RUN: %env_scudo_opts=allocator_may_return_null=0 not %run %t new-nothrow 2>&1 | FileCheck %s --check-prefix=CHECK-max  // RUN: %env_scudo_opts=allocator_may_return_null=1     %run %t new-nothrow 2>&1  // RUN:                                                 %run %t usable 2>&1 @@ -21,10 +21,10 @@  #include <limits>  #include <new> +#include <sanitizer/allocator_interface.h> +  int main(int argc, char **argv) {    assert(argc == 2); -  const char *action = argv[1]; -  fprintf(stderr, "%s:\n", action);  #if __LP64__ || defined(_WIN64)    static const size_t kMaxAllowedMallocSize = 1ULL << 40; @@ -34,32 +34,32 @@ int main(int argc, char **argv) {    static const size_t kChunkHeaderSize = 8;  #endif -  if (!strcmp(action, "malloc")) { +  if (!strcmp(argv[1], "malloc")) {      void *p = malloc(kMaxAllowedMallocSize);      assert(!p);      p = malloc(kMaxAllowedMallocSize - kChunkHeaderSize);      assert(!p); -  } else if (!strcmp(action, "calloc")) { +  } else if (!strcmp(argv[1], "calloc")) {      // Trigger an overflow in calloc.      size_t size = std::numeric_limits<size_t>::max();      void *p = calloc((size / 0x1000) + 1, 0x1000);      assert(!p); -  } else if (!strcmp(action, "new")) { +  } else if (!strcmp(argv[1], "new")) {      void *p = operator new(kMaxAllowedMallocSize);      assert(!p); -  } else if (!strcmp(action, "new-nothrow")) { +  } else if (!strcmp(argv[1], "new-nothrow")) {      void *p = operator new(kMaxAllowedMallocSize, std::nothrow);      assert(!p); -  } else if (!strcmp(action, "usable")) { +  } else if (!strcmp(argv[1], "usable")) {      // Playing with the actual usable size of a chunk.      void *p = malloc(1007);      assert(p); -    size_t size = malloc_usable_size(p); +    size_t size = __sanitizer_get_allocated_size(p);      assert(size >= 1007);      memset(p, 'A', size);      p = realloc(p, 2014);      assert(p); -    size = malloc_usable_size(p); +    size = __sanitizer_get_allocated_size(p);      assert(size >= 2014);      memset(p, 'B', size);      free(p); @@ -70,4 +70,6 @@ int main(int argc, char **argv) {    return 0;  } -// CHECK: allocator is terminating the process +// CHECK-max: {{Scudo ERROR: requested allocation size .* exceeds maximum supported size}} +// CHECK-oom: Scudo ERROR: allocator is out of memory +// CHECK-calloc: Scudo ERROR: calloc parameters overflow diff --git a/test/scudo/stats.c b/test/scudo/stats.c new file mode 100644 index 0000000000000..e7cc78ff0d492 --- /dev/null +++ b/test/scudo/stats.c @@ -0,0 +1,21 @@ +// RUN: %clang_scudo %s -o %t +// RUN: %run %t 2>&1 | FileCheck %s + +// Tests that the allocator stats printing function exists and outputs +// "something". Currently that "something" is fairly nebulous, as the 32-bit +// primary doesn't output anything, and for the 64-bit one it's highly dependent +// on the size class map and potential library allocations. So keep it very +// generic for now. + +#include <stdlib.h> + +#include <sanitizer/scudo_interface.h> + +int main(int argc, char **argv) +{ +  free(malloc(1U)); +  __scudo_print_stats(); +  return 0; +} + +// CHECK: Stats: diff --git a/test/scudo/symbols.test b/test/scudo/symbols.test new file mode 100644 index 0000000000000..0425e62ba6af6 --- /dev/null +++ b/test/scudo/symbols.test @@ -0,0 +1,8 @@ +UNSUPPORTED: android + +Verify that various functions are *not* present in the minimal binary. Presence +of those symbols in the minimal runtime would mean that the split code made it +back into the core Sanitizer runtime library. + +RUN: nm %shared_minlibscudo | not grep Symbolizer +RUN: nm %shared_minlibscudo | not grep Coverage diff --git a/test/scudo/valloc.c b/test/scudo/valloc.c index 132c4f2802204..605b9c4d4b9d9 100644 --- a/test/scudo/valloc.c +++ b/test/scudo/valloc.c @@ -1,8 +1,8 @@  // RUN: %clang_scudo %s -o %t  // RUN:                                                 %run %t valid   2>&1 -// RUN:                                             not %run %t invalid 2>&1 +// RUN:                                             not %run %t invalid 2>&1 | FileCheck %s  // RUN: %env_scudo_opts=allocator_may_return_null=1     %run %t invalid 2>&1 -// UNSUPPORTED: android, armhf-linux +// UNSUPPORTED: android  // Tests that valloc and pvalloc work as intended. @@ -54,6 +54,7 @@ int main(int argc, char **argv)    if (!strcmp(argv[1], "invalid")) {      // Size passed to pvalloc overflows when rounded up.      p = pvalloc((size_t)-1); +    // CHECK: Scudo ERROR: pvalloc parameters overflow      assert(!p);      assert(errno == ENOMEM);      errno = 0; diff --git a/test/shadowcallstack/CMakeLists.txt b/test/shadowcallstack/CMakeLists.txt new file mode 100644 index 0000000000000..ab2b18819d495 --- /dev/null +++ b/test/shadowcallstack/CMakeLists.txt @@ -0,0 +1,21 @@ +set(TEST_ARCH ${SHADOWCALLSTACK_SUPPORTED_ARCH}) + +set(SHADOWCALLSTACK_LIT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) +set(SHADOWCALLSTACK_LIT_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}) + +set(SHADOWCALLSTACK_TEST_DEPS ${SANITIZER_COMMON_LIT_TEST_DEPS}) + +foreach(arch ${SHADOWCALLSTACK_SUPPORTED_ARCH}) +  set(SANITIZER_COMMON_TEST_TARGET_ARCH ${arch}) +  get_test_cc_for_arch(${arch} +    SHADOWSTACK_TEST_TARGET_CC SHADOWSTACK_TEST_TARGET_CFLAGS) +  configure_lit_site_cfg( +    ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in +    ${CMAKE_CURRENT_BINARY_DIR}/${arch}/lit.site.cfg) +  list(APPEND SHADOWCALLSTACK_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/${arch}) +endforeach() + +add_lit_testsuite(check-shadowcallstack "Running the ShadowCallStack tests" +  ${SHADOWCALLSTACK_TESTSUITES} +  DEPENDS ${SANITIZER_COMMON_LIT_TEST_DEPS}) +set_target_properties(check-shadowcallstack PROPERTIES FOLDER "Compiler-RT Misc") diff --git a/test/shadowcallstack/init.c b/test/shadowcallstack/init.c new file mode 100644 index 0000000000000..a406e1b140fcd --- /dev/null +++ b/test/shadowcallstack/init.c @@ -0,0 +1,12 @@ +// RUN: %clang_scs %s -o %t +// RUN: %run %t + +// Basic smoke test for the runtime + +#include "libc_support.h" +#include "minimal_runtime.h" + +int scs_main(void) { +  scs_fputs_stdout("In main.\n"); +  return 0; +} diff --git a/test/shadowcallstack/libc_support.h b/test/shadowcallstack/libc_support.h new file mode 100644 index 0000000000000..5d89aab645a9e --- /dev/null +++ b/test/shadowcallstack/libc_support.h @@ -0,0 +1,41 @@ +// This header provides replacements for certain libc functions. It is necessary +// in order to safely run the tests on aarch64, because the system libc might +// not have been compiled with -ffixed-x18. + +#pragma once + +#include <stddef.h> +#include <stdint.h> +#include <stdio.h> + +#ifdef __aarch64__ + +size_t scs_strlen(const char *p) { +  size_t retval = 0; +  while (*p++) +    retval++; +  return retval; +} + +// We mark this function as noinline to make sure that its callers do not +// become leaf functions as a result of inlining. This is because we want to +// make sure that we generate the correct code for non-leaf functions. + +__attribute__((noinline)) void scs_fputs_stdout(const char *p) { +  __asm__ __volatile__( +      "mov x0, #1\n"  // stdout +      "mov x1, %0\n" +      "mov x2, %1\n" +      "mov x8, #64\n"  // write +      "svc #0\n" ::"r"(p), +      "r"(scs_strlen(p)) +      : "x0", "x1", "x2", "x8"); +} + +#else + +__attribute__((noinline)) void scs_fputs_stdout(const char *p) { +  fputs(p, stdout); +} + +#endif diff --git a/test/shadowcallstack/lit.cfg b/test/shadowcallstack/lit.cfg new file mode 100644 index 0000000000000..313cd2b8eff38 --- /dev/null +++ b/test/shadowcallstack/lit.cfg @@ -0,0 +1,23 @@ +# -*- Python -*- + +import os + +# Setup config name. +config.name = 'ShadowCallStack' + +# Setup source root. +config.test_source_root = os.path.dirname(__file__) + +# Test suffixes. +config.suffixes = ['.c', '.cc', '.cpp', '.m', '.mm', '.ll', '.test'] + +# Add clang substitutions. +config.substitutions.append( ("%clang_noscs ", config.clang + ' -O0 -fno-sanitize=shadow-call-stack ' + config.target_cflags + ' ') ) + +scs_arch_cflags = config.target_cflags +if config.target_arch == 'aarch64': +  scs_arch_cflags += ' -ffixed-x18 ' +config.substitutions.append( ("%clang_scs ", config.clang + ' -O0 -fsanitize=shadow-call-stack ' + scs_arch_cflags + ' ') ) + +if config.host_os not in ['Linux'] or config.target_arch not in ['x86_64', 'aarch64']: +   config.unsupported = True diff --git a/test/shadowcallstack/lit.site.cfg.in b/test/shadowcallstack/lit.site.cfg.in new file mode 100644 index 0000000000000..aa8913e84cb8e --- /dev/null +++ b/test/shadowcallstack/lit.site.cfg.in @@ -0,0 +1,12 @@ +@LIT_SITE_CFG_IN_HEADER@ + +# Tool-specific config options. +config.name_suffix = "@SHADOWCALLSTACK_TEST_CONFIG_SUFFIX@" +config.target_cflags = "@SHADOWCALLSTACK_TEST_TARGET_CFLAGS@" +config.target_arch = "@SHADOWCALLSTACK_TEST_TARGET_ARCH@" + +# Load common config for all compiler-rt lit tests. +lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/test/lit.common.configured") + +# Load tool-specific config that would do the real work. +lit_config.load_config(config, "@SHADOWCALLSTACK_LIT_SOURCE_DIR@/lit.cfg") diff --git a/test/shadowcallstack/minimal_runtime.h b/test/shadowcallstack/minimal_runtime.h new file mode 100644 index 0000000000000..f36fa5a7d245a --- /dev/null +++ b/test/shadowcallstack/minimal_runtime.h @@ -0,0 +1,43 @@ +// A shadow call stack runtime is not yet included with compiler-rt, provide a +// minimal runtime to allocate a shadow call stack and assign an +// architecture-specific register to point at it. + +#pragma once + +#ifdef __x86_64__ +#include <asm/prctl.h> +int arch_prctl(int code, void *addr); +#endif +#include <stdlib.h> +#include <sys/mman.h> +#include <sys/prctl.h> + +#include "libc_support.h" + +__attribute__((no_sanitize("shadow-call-stack"))) +static void __shadowcallstack_init() { +  void *stack = mmap(NULL, 8192, PROT_READ | PROT_WRITE, +                     MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); +  if (stack == MAP_FAILED) +    abort(); + +#if defined(__x86_64__) +  if (arch_prctl(ARCH_SET_GS, stack)) +    abort(); +#elif defined(__aarch64__) +  __asm__ __volatile__("mov x18, %0" ::"r"(stack)); +#else +#error Unsupported platform +#endif +} + +int scs_main(void); + +__attribute__((no_sanitize("shadow-call-stack"))) int main(void) { +  __shadowcallstack_init(); + +  // We can't simply return scs_main() because scs_main might have corrupted our +  // return address for testing purposes (see overflow.c), so we need to exit +  // ourselves. +  exit(scs_main()); +} diff --git a/test/shadowcallstack/overflow-aarch64.c b/test/shadowcallstack/overflow-aarch64.c new file mode 100644 index 0000000000000..8da798164fe71 --- /dev/null +++ b/test/shadowcallstack/overflow-aarch64.c @@ -0,0 +1,5 @@ +// See overflow.c for a description. + +// REQUIRES: aarch64-target-arch +// RUN: %clang_scs %S/overflow.c -o %t -DITERATIONS=12 +// RUN: %run %t | FileCheck %S/overflow.c diff --git a/test/shadowcallstack/overflow-x86_64.c b/test/shadowcallstack/overflow-x86_64.c new file mode 100644 index 0000000000000..38bb13a969a3f --- /dev/null +++ b/test/shadowcallstack/overflow-x86_64.c @@ -0,0 +1,5 @@ +// See overflow.c for a description. + +// REQUIRES: x86_64-target-arch +// RUN: %clang_scs %S/overflow.c -o %t -DITERATIONS=12 +// RUN: not --crash %run %t diff --git a/test/shadowcallstack/overflow.c b/test/shadowcallstack/overflow.c new file mode 100644 index 0000000000000..8c3d50c5917f0 --- /dev/null +++ b/test/shadowcallstack/overflow.c @@ -0,0 +1,39 @@ +// Test that a stack overflow fails as expected + +// RUN: %clang_noscs %s -o %t -DITERATIONS=3 +// RUN: %run %t | FileCheck %s +// RUN: %clang_noscs %s -o %t -DITERATIONS=12 +// RUN: %run %t | FileCheck -check-prefix=OVERFLOW_SUCCESS %s + +// RUN: %clang_scs %s -o %t -DITERATIONS=3 +// RUN: %run %t | FileCheck %s + +// The behavioral check for SCS + overflow lives in the tests overflow-x86_64.c +// and overflow-aarch64.c. This is because the expected behavior is different +// between the two platforms. On x86_64 we crash because the comparison between +// the shadow call stack and the regular stack fails. On aarch64 there is no +// comparison, we just load the return address from the shadow call stack. So we +// just expect not to see the output from print_and_exit. + +#include <stdio.h> +#include <stdlib.h> + +#include "minimal_runtime.h" + +void print_and_exit(void) { +// CHECK-NOT: Stack overflow successful. +// OVERFLOW_SUCCESS: Stack overflow successful. +  scs_fputs_stdout("Stack overflow successful.\n"); +  exit(0); +} + +int scs_main(void) +{ +  void *addrs[4]; +  for (int i = 0; i < ITERATIONS; i++) +    addrs[i] = &print_and_exit; + +  scs_fputs_stdout("Returning.\n"); + +  return 0; +} diff --git a/test/tsan/CMakeLists.txt b/test/tsan/CMakeLists.txt index 2b1d3004b1def..ba0fd9f23a33c 100644 --- a/test/tsan/CMakeLists.txt +++ b/test/tsan/CMakeLists.txt @@ -24,10 +24,7 @@ if(APPLE)  endif()  foreach(arch ${TSAN_TEST_ARCH}) -  set(TSAN_TEST_IOS "0") -  pythonize_bool(TSAN_TEST_IOS) -  set(TSAN_TEST_IOSSIM "0") -  pythonize_bool(TSAN_TEST_IOSSIM) +  set(TSAN_TEST_APPLE_PLATFORM "osx")    set(TSAN_TEST_TARGET_ARCH ${arch})    string(TOLOWER "-${arch}" TSAN_TEST_CONFIG_SUFFIX) @@ -51,15 +48,12 @@ if(APPLE)    set(EXCLUDE_FROM_ALL ON)    set(TSAN_TEST_TARGET_CC ${COMPILER_RT_TEST_COMPILER}) -  set(TSAN_TEST_IOS "1") -  pythonize_bool(TSAN_TEST_IOS) +  set(TSAN_TEST_APPLE_PLATFORM "iossim")    set(arch "x86_64") -  set(TSAN_TEST_IOSSIM "1") -  pythonize_bool(TSAN_TEST_IOSSIM)    set(TSAN_TEST_TARGET_ARCH ${arch})    set(TSAN_TEST_TARGET_CFLAGS "-arch ${arch} -isysroot ${DARWIN_iossim_SYSROOT} ${COMPILER_RT_TEST_COMPILER_CFLAGS}") -  set(TSAN_TEST_CONFIG_SUFFIX "-${arch}-iossim") +  set(TSAN_TEST_CONFIG_SUFFIX "-${arch}-${TSAN_TEST_APPLE_PLATFORM}")    string(TOUPPER ${arch} ARCH_UPPER_CASE)    set(CONFIG_NAME "IOSSim${ARCH_UPPER_CASE}Config")    configure_lit_site_cfg( @@ -70,12 +64,11 @@ if(APPLE)      ${CMAKE_CURRENT_BINARY_DIR}/${CONFIG_NAME}/      DEPENDS ${TSAN_TEST_DEPS}) +  set(TSAN_TEST_APPLE_PLATFORM "ios")    set(arch "arm64") -  set(TSAN_TEST_IOSSIM "0") -  pythonize_bool(TSAN_TEST_IOSSIM)    set(TSAN_TEST_TARGET_ARCH ${arch})    set(TSAN_TEST_TARGET_CFLAGS "-arch ${arch} -isysroot ${DARWIN_ios_SYSROOT} ${COMPILER_RT_TEST_COMPILER_CFLAGS}") -  set(TSAN_TEST_CONFIG_SUFFIX "-${arch}-ios") +  set(TSAN_TEST_CONFIG_SUFFIX "-${arch}-${TSAN_TEST_APPLE_PLATFORM}")    string(TOUPPER ${arch} ARCH_UPPER_CASE)    set(CONFIG_NAME "IOS${ARCH_UPPER_CASE}Config")    configure_lit_site_cfg( diff --git a/test/tsan/Darwin/external-swift-debugging.cc b/test/tsan/Darwin/external-swift-debugging.cc new file mode 100644 index 0000000000000..603734e5d0355 --- /dev/null +++ b/test/tsan/Darwin/external-swift-debugging.cc @@ -0,0 +1,68 @@ +// RUN: %clangxx_tsan %s -o %t +// RUN: %deflake %run %t 2>&1 | FileCheck %s + +#include <thread> + +#import "../test.h" + + +extern "C" { +int __tsan_get_report_data(void *report, const char **description, int *count, +                           int *stack_count, int *mop_count, int *loc_count, +                           int *mutex_count, int *thread_count, +                           int *unique_tid_count, void **sleep_trace, +                           unsigned long trace_size); +int __tsan_get_report_tag(void *report, unsigned long *tag); +} + +__attribute__((no_sanitize("thread"), noinline)) +void ExternalWrite(void *addr) { +  void *kSwiftAccessRaceTag = (void *)0x1; +  __tsan_external_write(addr, nullptr, kSwiftAccessRaceTag); +} + +int main(int argc, char *argv[]) { +  barrier_init(&barrier, 2); +  fprintf(stderr, "Start.\n"); +  // CHECK: Start. +   +  void *opaque_object = malloc(16); +  std::thread t1([opaque_object] { +    ExternalWrite(opaque_object); +    barrier_wait(&barrier); +  }); +  std::thread t2([opaque_object] { +    barrier_wait(&barrier); +    ExternalWrite(opaque_object); +  }); +  // CHECK: WARNING: ThreadSanitizer: Swift access race +  // CHECK: Modifying access of Swift variable at {{.*}} by thread {{.*}} +  // CHECK: Previous modifying access of Swift variable at {{.*}} by thread {{.*}} +  // CHECK: SUMMARY: ThreadSanitizer: Swift access race +  t1.join(); +  t2.join(); + +  fprintf(stderr, "Done.\n"); +} + +extern "C" +void __tsan_on_report(void *report) { +  const char *description; +  int count; +  int stack_count, mop_count, loc_count, mutex_count, thread_count, +      unique_tid_count; +  void *sleep_trace[16] = {0}; +  __tsan_get_report_data(report, &description, &count, &stack_count, &mop_count, +                         &loc_count, &mutex_count, &thread_count, +                         &unique_tid_count, sleep_trace, 16); +  fprintf(stderr, "report type = '%s', count = %d\n", description, count); +  // CHECK: report type = 'external-race', count = 0 + +  unsigned long tag; +  __tsan_get_report_tag(report, &tag); +  fprintf(stderr, "tag = %ld\n", tag); +  // CHECK: tag = 1 +} + +// CHECK: Done. +// CHECK: ThreadSanitizer: reported 1 warnings diff --git a/test/tsan/Darwin/gcd-after-null.mm b/test/tsan/Darwin/gcd-after-null.mm deleted file mode 100644 index 7c9913c0fb17e..0000000000000 --- a/test/tsan/Darwin/gcd-after-null.mm +++ /dev/null @@ -1,23 +0,0 @@ -// Regression test to make sure we don't crash when dispatch_after is called with a NULL queue. - -// RUN: %clang_tsan %s -o %t -framework Foundation -// RUN: %run %t 2>&1 | FileCheck %s - -#import <Foundation/Foundation.h> - -int main(int argc, const char *argv[]) { -  fprintf(stderr, "start\n"); - -  dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(10 * NSEC_PER_MSEC)), NULL, ^{ -    dispatch_async(dispatch_get_main_queue(), ^{ -      CFRunLoopStop(CFRunLoopGetMain()); -    }); -  }); -  CFRunLoopRun(); - -  fprintf(stderr, "done\n"); -  return 0; -} - -// CHECK: start -// CHECK: done diff --git a/test/tsan/Darwin/norace-objcxx-run-time.mm b/test/tsan/Darwin/norace-objcxx-run-time.mm index 1de431a076c78..ee76ec155cb42 100644 --- a/test/tsan/Darwin/norace-objcxx-run-time.mm +++ b/test/tsan/Darwin/norace-objcxx-run-time.mm @@ -1,4 +1,4 @@ -// RUN: %clang_tsan %s -lc++ -fobjc-arc -lobjc -o %t -framework Foundation +// RUN: %clang_tsan %s -lc++ -fobjc-arc -lobjc -o %t -framework Foundation %darwin_min_target_with_full_runtime_arc_support  // RUN: %run %t 2>&1 | FileCheck %s  // Check that we do not report races between: diff --git a/test/tsan/Darwin/objc-synchronize-tagged.mm b/test/tsan/Darwin/objc-synchronize-tagged.mm new file mode 100644 index 0000000000000..ab0af46ec4af8 --- /dev/null +++ b/test/tsan/Darwin/objc-synchronize-tagged.mm @@ -0,0 +1,62 @@ +// RUN: %clangxx_tsan %s -o %t -framework Foundation -fobjc-arc %darwin_min_target_with_full_runtime_arc_support +// RUN: %run %t 2>&1 | FileCheck %s + +#import <Foundation/Foundation.h> + +NSString *tagged_string = nil; + +@interface MyClass : NSObject { +  long field; +} +@property(nonatomic, readonly) long value; +@end + +dispatch_group_t group; + +@implementation MyClass + +- (void)start { +  dispatch_queue_t q = dispatch_queue_create(NULL, NULL); +  dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ +    for (int i = 0; i < 10; i++) { +      dispatch_async(q, ^{ +        @synchronized(tagged_string) { +          self->field = i; +        } +      }); +    } +  }); +} + +- (long)value { +  @synchronized(tagged_string) { +    return self->field; +  } +} + +- (void)dealloc { +  dispatch_group_leave(group); +} + +@end + +int main() { +  tagged_string = [NSString stringWithFormat:@"%s", "abc"]; +  uintptr_t tagged_string_bits = (uintptr_t)tagged_string; +  assert((tagged_string_bits & 0x8000000000000001ull) != 0); +  group = dispatch_group_create(); +  @autoreleasepool { +    for (int j = 0; j < 100; ++j) { +      dispatch_group_enter(group); +      MyClass *obj = [[MyClass alloc] init]; +      [obj start]; +      long x = obj.value; +      (void)x; +    } +  } +  dispatch_group_wait(group, DISPATCH_TIME_FOREVER); +  NSLog(@"Hello world"); +} + +// CHECK: Hello world +// CHECK-NOT: WARNING: ThreadSanitizer diff --git a/test/tsan/Darwin/objc-synchronize.mm b/test/tsan/Darwin/objc-synchronize.mm new file mode 100644 index 0000000000000..0bf06370a9b89 --- /dev/null +++ b/test/tsan/Darwin/objc-synchronize.mm @@ -0,0 +1,57 @@ +// RUN: %clangxx_tsan %s -o %t -framework Foundation -fobjc-arc %darwin_min_target_with_full_runtime_arc_support +// RUN: %run %t 2>&1 | FileCheck %s + +#import <Foundation/Foundation.h> + +@interface MyClass : NSObject { +  long field; +} +@property (nonatomic, readonly) long value; +@end + +dispatch_group_t group; + +@implementation MyClass + +- (void) start { +  dispatch_queue_t q = dispatch_queue_create(NULL, NULL); +  dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ +    for (int i = 0; i < 1000; i++) { +      dispatch_async(q, ^{ +        @synchronized(self) { +          self->field = i; +        } +      }); +    } +  }); +} + +- (long) value { +  @synchronized(self) { +    return self->field; +  } +} + +- (void)dealloc { +  dispatch_group_leave(group); +} + +@end + +int main() { +  group = dispatch_group_create(); +  @autoreleasepool { +    for (int j = 0; j < 100; ++j) { +      dispatch_group_enter(group); +      MyClass *obj = [[MyClass alloc] init]; +      [obj start]; +      long x = obj.value; +      (void)x; +    } +  } +  dispatch_group_wait(group, DISPATCH_TIME_FOREVER); +  NSLog(@"Hello world"); +} + +// CHECK: Hello world +// CHECK-NOT: WARNING: ThreadSanitizer diff --git a/test/tsan/allocator_returns_null.cc b/test/tsan/allocator_returns_null.cc deleted file mode 100644 index 5e2e2e9a53c73..0000000000000 --- a/test/tsan/allocator_returns_null.cc +++ /dev/null @@ -1,124 +0,0 @@ -// Test the behavior of malloc/calloc/realloc/new when the allocation size is -// more than TSan allocator's max allowed one. -// By default (allocator_may_return_null=0) the process should crash. -// With allocator_may_return_null=1 the allocator should return 0, except the -// operator new(), which should crash anyway (operator new(std::nothrow) should -// return nullptr, indeed). -// -// RUN: %clangxx_tsan -O0 %s -o %t -// RUN: not %run %t malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mCRASH -// RUN: %env_tsan_opts=allocator_may_return_null=0 not %run %t malloc 2>&1 \ -// RUN:   | FileCheck %s --check-prefix=CHECK-mCRASH -// RUN: %env_tsan_opts=allocator_may_return_null=1     %run %t malloc 2>&1 \ -// RUN:   | FileCheck %s --check-prefix=CHECK-mNULL -// RUN: %env_tsan_opts=allocator_may_return_null=0 not %run %t calloc 2>&1 \ -// RUN:   | FileCheck %s --check-prefix=CHECK-cCRASH -// RUN: %env_tsan_opts=allocator_may_return_null=1     %run %t calloc 2>&1 \ -// RUN:   | FileCheck %s --check-prefix=CHECK-cNULL -// RUN: %env_tsan_opts=allocator_may_return_null=0 not %run %t calloc-overflow 2>&1 \ -// RUN:   | FileCheck %s --check-prefix=CHECK-coCRASH -// RUN: %env_tsan_opts=allocator_may_return_null=1     %run %t calloc-overflow 2>&1 \ -// RUN:   | FileCheck %s --check-prefix=CHECK-coNULL -// RUN: %env_tsan_opts=allocator_may_return_null=0 not %run %t realloc 2>&1 \ -// RUN:   | FileCheck %s --check-prefix=CHECK-rCRASH -// RUN: %env_tsan_opts=allocator_may_return_null=1     %run %t realloc 2>&1 \ -// RUN:   | FileCheck %s --check-prefix=CHECK-rNULL -// RUN: %env_tsan_opts=allocator_may_return_null=0 not %run %t realloc-after-malloc 2>&1 \ -// RUN:   | FileCheck %s --check-prefix=CHECK-mrCRASH -// RUN: %env_tsan_opts=allocator_may_return_null=1     %run %t realloc-after-malloc 2>&1 \ -// RUN:   | FileCheck %s --check-prefix=CHECK-mrNULL -// RUN: %env_tsan_opts=allocator_may_return_null=0 not %run %t new 2>&1 \ -// RUN:   | FileCheck %s --check-prefix=CHECK-nCRASH -// RUN: %env_tsan_opts=allocator_may_return_null=1 not %run %t new 2>&1 \ -// RUN:   | FileCheck %s --check-prefix=CHECK-nCRASH -// RUN: %env_tsan_opts=allocator_may_return_null=0 not %run %t new-nothrow 2>&1 \ -// RUN:   | FileCheck %s --check-prefix=CHECK-nnCRASH -// RUN: %env_tsan_opts=allocator_may_return_null=1     %run %t new-nothrow 2>&1 \ -// RUN:   | FileCheck %s --check-prefix=CHECK-nnNULL - -#include <assert.h> -#include <errno.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <limits> -#include <new> - -int main(int argc, char **argv) { -  // Disable stderr buffering. Needed on Windows. -  setvbuf(stderr, NULL, _IONBF, 0); - -  assert(argc == 2); -  const char *action = argv[1]; -  fprintf(stderr, "%s:\n", action); - -  // The limit enforced in tsan_mman.cc, user_alloc_internal function. -  static const size_t kMaxAllowedMallocSizePlusOne = (1ULL << 40) + 1; - -  void *x = 0; -  if (!strcmp(action, "malloc")) { -    x = malloc(kMaxAllowedMallocSizePlusOne); -  } else if (!strcmp(action, "calloc")) { -    x = calloc((kMaxAllowedMallocSizePlusOne / 4) + 1, 4); -  } else if (!strcmp(action, "calloc-overflow")) { -    volatile size_t kMaxSizeT = std::numeric_limits<size_t>::max(); -    size_t kArraySize = 4096; -    volatile size_t kArraySize2 = kMaxSizeT / kArraySize + 10; -    x = calloc(kArraySize, kArraySize2); -  } else if (!strcmp(action, "realloc")) { -    x = realloc(0, kMaxAllowedMallocSizePlusOne); -  } else if (!strcmp(action, "realloc-after-malloc")) { -    char *t = (char*)malloc(100); -    *t = 42; -    x = realloc(t, kMaxAllowedMallocSizePlusOne); -    assert(*t == 42); -  } else if (!strcmp(action, "new")) { -    x = operator new(kMaxAllowedMallocSizePlusOne); -  } else if (!strcmp(action, "new-nothrow")) { -    x = operator new(kMaxAllowedMallocSizePlusOne, std::nothrow); -  } else { -    assert(0); -  } - -  fprintf(stderr, "errno: %d\n", errno); - -  // The NULL pointer is printed differently on different systems, while (long)0 -  // is always the same. -  fprintf(stderr, "x: %lx\n", (long)x); -  free(x); - -  return x != 0; -} - -// CHECK-mCRASH: malloc: -// CHECK-mCRASH: ThreadSanitizer's allocator is terminating the process -// CHECK-cCRASH: calloc: -// CHECK-cCRASH: ThreadSanitizer's allocator is terminating the process -// CHECK-coCRASH: calloc-overflow: -// CHECK-coCRASH: ThreadSanitizer's allocator is terminating the process -// CHECK-rCRASH: realloc: -// CHECK-rCRASH: ThreadSanitizer's allocator is terminating the process -// CHECK-mrCRASH: realloc-after-malloc: -// CHECK-mrCRASH: ThreadSanitizer's allocator is terminating the process -// CHECK-nCRASH: new: -// CHECK-nCRASH: ThreadSanitizer's allocator is terminating the process -// CHECK-nnCRASH: new-nothrow: -// CHECK-nnCRASH: ThreadSanitizer's allocator is terminating the process - -// CHECK-mNULL: malloc: -// CHECK-mNULL: errno: 12 -// CHECK-mNULL: x: 0 -// CHECK-cNULL: calloc: -// CHECK-cNULL: errno: 12 -// CHECK-cNULL: x: 0 -// CHECK-coNULL: calloc-overflow: -// CHECK-coNULL: errno: 12 -// CHECK-coNULL: x: 0 -// CHECK-rNULL: realloc: -// CHECK-rNULL: errno: 12 -// CHECK-rNULL: x: 0 -// CHECK-mrNULL: realloc-after-malloc: -// CHECK-mrNULL: errno: 12 -// CHECK-mrNULL: x: 0 -// CHECK-nnNULL: new-nothrow: -// CHECK-nnNULL: x: 0 diff --git a/test/tsan/global_race.cc b/test/tsan/global_race.cc index ec26b06f5c1ca..01df3b6de9c3e 100644 --- a/test/tsan/global_race.cc +++ b/test/tsan/global_race.cc @@ -1,12 +1,15 @@ -// RUN: %clangxx_tsan -O1 %s -o %T/global_race.cc.exe && %deflake %run %T/global_race.cc.exe 2>&1 \ +// RUN: rm -rf %t-dir +// RUN: mkdir %t-dir + +// RUN: %clangxx_tsan -O1 %s -o %t-dir/global_race.cc.exe && %deflake %run %t-dir/global_race.cc.exe 2>&1 \  // RUN:   | FileCheck %s  // Also check that memory access instrumentation can be configured by either  // driver or legacy flags: -// RUN: %clangxx_tsan -O1 %s -o %T/global_race.cc.exe -fno-sanitize-thread-memory-access && not %deflake %run %T/global_race.cc.exe 2>&1 \ +// RUN: %clangxx_tsan -O1 %s -o %t-dir/global_race.cc.exe -fno-sanitize-thread-memory-access && not %deflake %run %t-dir/global_race.cc.exe 2>&1 \  // RUN:   | FileCheck --allow-empty --check-prefix=CHECK-MEMORY-ACCESS-OFF %s -// RUN: %clangxx_tsan -O1 %s -o %T/global_race.cc.exe -mllvm -tsan-instrument-memory-accesses=0 && not %deflake %run %T/global_race.cc.exe 2>&1 \ +// RUN: %clangxx_tsan -O1 %s -o %t-dir/global_race.cc.exe -mllvm -tsan-instrument-memory-accesses=0 && not %deflake %run %t-dir/global_race.cc.exe 2>&1 \  // RUN:   | FileCheck --allow-empty --check-prefix=CHECK-MEMORY-ACCESS-OFF %s  #include "test.h" diff --git a/test/tsan/ignore_lib0.cc b/test/tsan/ignore_lib0.cc index 84632019fccb8..2b217f21ff561 100644 --- a/test/tsan/ignore_lib0.cc +++ b/test/tsan/ignore_lib0.cc @@ -1,9 +1,12 @@ -// RUN: %clangxx_tsan -O1 %s -DLIB -fPIC -fno-sanitize=thread -shared -o %T/libignore_lib0.so -// RUN: %clangxx_tsan -O1 %s -L%T -lignore_lib0 -o %t +// RUN: rm -rf %t-dir +// RUN: mkdir %t-dir + +// RUN: %clangxx_tsan -O1 %s -DLIB -fPIC -fno-sanitize=thread -shared -o %t-dir/libignore_lib0.so +// RUN: %clangxx_tsan -O1 %s -L%t-dir -lignore_lib0 -o %t  // RUN: echo running w/o suppressions: -// RUN: env LD_LIBRARY_PATH=%T${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH} %deflake %run %t | FileCheck %s --check-prefix=CHECK-NOSUPP +// RUN: env LD_LIBRARY_PATH=%t-dir${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH} %deflake %run %t | FileCheck %s --check-prefix=CHECK-NOSUPP  // RUN: echo running with suppressions: -// RUN: env LD_LIBRARY_PATH=%T${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH} %env_tsan_opts=suppressions='%s.supp' %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-WITHSUPP +// RUN: env LD_LIBRARY_PATH=%t-dir${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH} %env_tsan_opts=suppressions='%s.supp' %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-WITHSUPP  // Tests that interceptors coming from a library specified in called_from_lib  // suppression are ignored. diff --git a/test/tsan/ignore_lib1.cc b/test/tsan/ignore_lib1.cc index 5949d811ed44e..1660cf3e41f99 100644 --- a/test/tsan/ignore_lib1.cc +++ b/test/tsan/ignore_lib1.cc @@ -1,9 +1,12 @@ -// RUN: %clangxx_tsan -O1 %s -DLIB -fPIC -fno-sanitize=thread -shared -o %T/libignore_lib1.so -// RUN: %clangxx_tsan -O1 %s -o %t +// RUN: rm -rf %t-dir +// RUN: mkdir %t-dir + +// RUN: %clangxx_tsan -O1 %s -DLIB -fPIC -fno-sanitize=thread -shared -o %t-dir/libignore_lib1.so +// RUN: %clangxx_tsan -O1 %s -o %t-dir/executable  // RUN: echo running w/o suppressions: -// RUN: %deflake %run %t | FileCheck %s --check-prefix=CHECK-NOSUPP +// RUN: %deflake %run %t-dir/executable | FileCheck %s --check-prefix=CHECK-NOSUPP  // RUN: echo running with suppressions: -// RUN: %env_tsan_opts=suppressions='%s.supp' %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-WITHSUPP +// RUN: %env_tsan_opts=suppressions='%s.supp' %run %t-dir/executable 2>&1 | FileCheck %s --check-prefix=CHECK-WITHSUPP  // Tests that interceptors coming from a dynamically loaded library specified  // in called_from_lib suppression are ignored. diff --git a/test/tsan/ignore_lib2.cc b/test/tsan/ignore_lib2.cc index 4f584b14664ac..e0dac56701223 100644 --- a/test/tsan/ignore_lib2.cc +++ b/test/tsan/ignore_lib2.cc @@ -1,7 +1,10 @@ -// RUN: %clangxx_tsan -O1 %s -DLIB -fPIC -fno-sanitize=thread -shared -o %T/libignore_lib2_0.so -// RUN: %clangxx_tsan -O1 %s -DLIB -fPIC -fno-sanitize=thread -shared -o %T/libignore_lib2_1.so -// RUN: %clangxx_tsan -O1 %s -o %t -// RUN: %env_tsan_opts=suppressions='%s.supp' %deflake %run %t | FileCheck %s +// RUN: rm -rf %t-dir +// RUN: mkdir %t-dir + +// RUN: %clangxx_tsan -O1 %s -DLIB -fPIC -fno-sanitize=thread -shared -o %t-dir/libignore_lib2_0.so +// RUN: %clangxx_tsan -O1 %s -DLIB -fPIC -fno-sanitize=thread -shared -o %t-dir/libignore_lib2_1.so +// RUN: %clangxx_tsan -O1 %s -o %t-dir/executable +// RUN: %env_tsan_opts=suppressions='%s.supp' %deflake %run %t-dir/executable | FileCheck %s  // Tests that called_from_lib suppression matched against 2 libraries  // causes program crash (this is not supported). diff --git a/test/tsan/ignore_lib3.cc b/test/tsan/ignore_lib3.cc index 3f7be5cf82331..a5af07fdd112e 100644 --- a/test/tsan/ignore_lib3.cc +++ b/test/tsan/ignore_lib3.cc @@ -1,6 +1,9 @@ -// RUN: %clangxx_tsan -O1 %s -DLIB -fPIC -fno-sanitize=thread -shared -o %T/libignore_lib3.so -// RUN: %clangxx_tsan -O1 %s -o %t -// RUN: %env_tsan_opts=suppressions='%s.supp' %deflake %run %t | FileCheck %s +// RUN: rm -rf %t-dir +// RUN: mkdir %t-dir + +// RUN: %clangxx_tsan -O1 %s -DLIB -fPIC -fno-sanitize=thread -shared -o %t-dir/libignore_lib3.so +// RUN: %clangxx_tsan -O1 %s -o %t-dir/executable +// RUN: %env_tsan_opts=suppressions='%s.supp' %deflake %run %t-dir/executable | FileCheck %s  // Tests that unloading of a library matched against called_from_lib suppression  // causes program crash (this is not supported). diff --git a/test/tsan/ignore_lib4.cc b/test/tsan/ignore_lib4.cc index 84d8b2768a94d..da636ae3bf371 100644 --- a/test/tsan/ignore_lib4.cc +++ b/test/tsan/ignore_lib4.cc @@ -1,7 +1,10 @@ -// RUN: %clangxx_tsan -O1 %s -DLIB -fPIC -shared -o %T/libignore_lib4.so -// RUN: %clangxx_tsan -O1 %s -o %t -// RUN: echo "called_from_lib:libignore_lib4.so" > %t.supp -// RUN: %env_tsan_opts=suppressions='%t.supp' %run %t 2>&1 | FileCheck %s +// RUN: rm -rf %t-dir +// RUN: mkdir %t-dir + +// RUN: %clangxx_tsan -O1 %s -DLIB -fPIC -shared -o %t-dir/libignore_lib4.so +// RUN: %clangxx_tsan -O1 %s -o %t-dir/executable +// RUN: echo "called_from_lib:libignore_lib4.so" > %t-dir/executable.supp +// RUN: %env_tsan_opts=suppressions='%t-dir/executable.supp' %run %t-dir/executable 2>&1 | FileCheck %s  // powerpc64 big endian bots failed with "FileCheck error: '-' is empty" due  // to a segmentation fault. diff --git a/test/tsan/ignore_lib5.cc b/test/tsan/ignore_lib5.cc index 54630d534c344..d6c3f870e49b7 100644 --- a/test/tsan/ignore_lib5.cc +++ b/test/tsan/ignore_lib5.cc @@ -1,9 +1,12 @@ -// RUN: %clangxx_tsan -O1 %s -DLIB -fPIC -fno-sanitize=thread -shared -o %T/libignore_lib1.so -// RUN: %clangxx_tsan -O1 %s -o %t +// RUN: rm -rf %t-dir +// RUN: mkdir %t-dir + +// RUN: %clangxx_tsan -O1 %s -DLIB -fPIC -fno-sanitize=thread -shared -o %t-dir/libignore_lib1.so +// RUN: %clangxx_tsan -O1 %s -o %t-dir/executable  // RUN: echo running w/o suppressions: -// RUN: %deflake %run %t | FileCheck %s --check-prefix=CHECK-NOSUPP +// RUN: %deflake %run %t-dir/executable | FileCheck %s --check-prefix=CHECK-NOSUPP  // RUN: echo running with suppressions: -// RUN: %env_tsan_opts=suppressions='%s.supp' %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-WITHSUPP +// RUN: %env_tsan_opts=suppressions='%s.supp' %run %t-dir/executable 2>&1 | FileCheck %s --check-prefix=CHECK-WITHSUPP  // REQUIRES: stable-runtime  // UNSUPPORTED: powerpc64le diff --git a/test/tsan/ignored-interceptors-mmap.cc b/test/tsan/ignored-interceptors-mmap.cc index 8715883238e26..796ea9323345d 100644 --- a/test/tsan/ignored-interceptors-mmap.cc +++ b/test/tsan/ignored-interceptors-mmap.cc @@ -1,6 +1,7 @@  // RUN: %clangxx_tsan -O0 %s -o %t  // RUN: not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-NORMAL  // RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-IGNORE +// XFAIL: freebsd  #include <errno.h>  #include <sys/mman.h> diff --git a/test/tsan/java_symbolization.cc b/test/tsan/java_symbolization.cc index aa5ec0c37558b..f82bd5ead48e7 100644 --- a/test/tsan/java_symbolization.cc +++ b/test/tsan/java_symbolization.cc @@ -2,18 +2,13 @@  #include "java.h"  #include <memory.h> -extern "C" bool __tsan_symbolize_external(jptr pc, -                                          char *func_buf, jptr func_siz, -                                          char *file_buf, jptr file_siz, -                                          int *line, int *col) { +extern "C" void __tsan_symbolize_external_ex( +    jptr pc, void (*add_frame)(void *, const char *, const char *, int, int), +    void *ctx) {    if (pc == (1234 | kExternalPCBit)) { -    memcpy(func_buf, "MyFunc", sizeof("MyFunc")); -    memcpy(file_buf, "MyFile.java", sizeof("MyFile.java")); -    *line = 1234; -    *col = 56; -    return true; +    add_frame(ctx, "MyInnerFunc", "MyInnerFile.java", 1234, 56); +    add_frame(ctx, "MyOuterFunc", "MyOuterFile.java", 4321, 65);    } -  return false;  }  void *Thread(void *p) { @@ -40,5 +35,6 @@ int main() {  }  // CHECK: WARNING: ThreadSanitizer: data race -// CHECK:     #0 MyFunc MyFile.java:1234:56 +// CHECK:     #0 MyInnerFunc MyInnerFile.java:1234:56 +// CHECK:     #1 MyOuterFunc MyOuterFile.java:4321:65  // CHECK: DONE diff --git a/test/tsan/java_symbolization_legacy.cc b/test/tsan/java_symbolization_legacy.cc new file mode 100644 index 0000000000000..aa5ec0c37558b --- /dev/null +++ b/test/tsan/java_symbolization_legacy.cc @@ -0,0 +1,44 @@ +// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s +#include "java.h" +#include <memory.h> + +extern "C" bool __tsan_symbolize_external(jptr pc, +                                          char *func_buf, jptr func_siz, +                                          char *file_buf, jptr file_siz, +                                          int *line, int *col) { +  if (pc == (1234 | kExternalPCBit)) { +    memcpy(func_buf, "MyFunc", sizeof("MyFunc")); +    memcpy(file_buf, "MyFile.java", sizeof("MyFile.java")); +    *line = 1234; +    *col = 56; +    return true; +  } +  return false; +} + +void *Thread(void *p) { +  barrier_wait(&barrier); +  __tsan_write1_pc((jptr)p, 1234 | kExternalPCBit); +  return 0; +} + +int main() { +  barrier_init(&barrier, 2); +  int const kHeapSize = 1024 * 1024; +  jptr jheap = (jptr)malloc(kHeapSize + 8) + 8; +  __tsan_java_init(jheap, kHeapSize); +  const int kBlockSize = 16; +  __tsan_java_alloc(jheap, kBlockSize); +  pthread_t th; +  pthread_create(&th, 0, Thread, (void*)jheap); +  __tsan_write1_pc((jptr)jheap, 1234 | kExternalPCBit); +  barrier_wait(&barrier); +  pthread_join(th, 0); +  __tsan_java_free(jheap, kBlockSize); +  fprintf(stderr, "DONE\n"); +  return __tsan_java_fini(); +} + +// CHECK: WARNING: ThreadSanitizer: data race +// CHECK:     #0 MyFunc MyFile.java:1234:56 +// CHECK: DONE diff --git a/test/tsan/lit.cfg b/test/tsan/lit.cfg index fdbafefbc66fd..233d273f3130a 100644 --- a/test/tsan/lit.cfg +++ b/test/tsan/lit.cfg @@ -56,7 +56,7 @@ clang_tsan_cxxflags = config.cxx_mode_flags + clang_tsan_cflags + ["-std=c++11"]  if config.has_libcxx and config.host_os != 'Darwin':    # FIXME: Dehardcode this path somehow.    libcxx_path = os.path.join(config.compiler_rt_obj_root, "lib", -                             "tsan", "libcxx_tsan_" + config.target_arch) +                             "tsan", "libcxx_tsan_%s" % config.target_arch)    libcxx_incdir = os.path.join(libcxx_path, "include", "c++", "v1")    libcxx_libdir = os.path.join(libcxx_path, "lib")    libcxx_so = os.path.join(libcxx_libdir, "libc++.so") @@ -85,5 +85,8 @@ if config.host_os not in ['FreeBSD', 'Linux', 'Darwin', 'NetBSD']:  if config.android:    config.unsupported = True -if config.host_os == 'Darwin' and config.target_arch in ["x86_64", "x86_64h"]: -  config.parallelism_group = "darwin-64bit-sanitizer" +if config.host_os == 'Darwin': +  if config.target_arch in ["x86_64", "x86_64h"]: +    config.parallelism_group = "darwin-64bit-sanitizer" +  elif config.apple_platform != "osx" and not config.apple_platform.endswith("sim"): +    config.parallelism_group = "darwin-ios-device-sanitizer" diff --git a/test/tsan/lit.site.cfg.in b/test/tsan/lit.site.cfg.in index a215e664a5b40..6dec5f92b271f 100644 --- a/test/tsan/lit.site.cfg.in +++ b/test/tsan/lit.site.cfg.in @@ -3,8 +3,7 @@  config.name_suffix = "@TSAN_TEST_CONFIG_SUFFIX@"  config.tsan_lit_source_dir = "@TSAN_LIT_SOURCE_DIR@"  config.has_libcxx = @TSAN_HAS_LIBCXX@ -config.ios = @TSAN_TEST_IOS_PYBOOL@ -config.iossim = @TSAN_TEST_IOSSIM_PYBOOL@ +config.apple_platform = "@TSAN_TEST_APPLE_PLATFORM@"  config.target_cflags = "@TSAN_TEST_TARGET_CFLAGS@"  config.target_arch = "@TSAN_TEST_TARGET_ARCH@" diff --git a/test/tsan/mutex_destroy_locked2.cc b/test/tsan/mutex_destroy_locked2.cc new file mode 100644 index 0000000000000..e29c96138a8e4 --- /dev/null +++ b/test/tsan/mutex_destroy_locked2.cc @@ -0,0 +1,29 @@ +// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s +#include <pthread.h> +#include <unistd.h> + +void *thread(void *arg) { +  pthread_mutex_t m; +  pthread_mutex_init(&m, 0); +  pthread_mutex_lock(&m); +  pthread_mutex_destroy(&m); +  return 0; +} + +int main() { +  pthread_t th; +  pthread_create(&th, 0, thread, 0); +  pthread_join(th, 0); +  return 0; +} + +// CHECK: WARNING: ThreadSanitizer: destroy of a locked mutex +// CHECK:     #0 pthread_mutex_destroy +// CHECK:     #1 thread +// CHECK:   and: +// CHECK:     #0 pthread_mutex_lock +// CHECK:     #1 thread +// CHECK:   Mutex {{.*}} created at: +// CHECK:     #0 pthread_mutex_init +// CHECK:     #1 thread +// CHECK: SUMMARY: ThreadSanitizer: destroy of a locked mutex {{.*}} in thread diff --git a/test/tsan/race_on_fputs.cc b/test/tsan/race_on_fputs.cc new file mode 100644 index 0000000000000..53042e3d36bca --- /dev/null +++ b/test/tsan/race_on_fputs.cc @@ -0,0 +1,29 @@ +// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s +#include "test.h" + +char s[] = "abracadabra"; + +void *Thread0(void *p) { +  fputs(s, stdout); +  barrier_wait(&barrier); +  return 0; +} + +void *Thread1(void *p) { +  barrier_wait(&barrier); +  s[3] = 'z'; +  return 0; +} + +int main() { +  barrier_init(&barrier, 2); +  pthread_t th[2]; +  pthread_create(&th[0], 0, Thread0, 0); +  pthread_create(&th[1], 0, Thread1, 0); +  pthread_join(th[0], 0); +  pthread_join(th[1], 0); +  fprintf(stderr, "DONE"); +} + +// CHECK: WARNING: ThreadSanitizer: data race +// CHECK: DONE diff --git a/test/tsan/simple_stack2.cc b/test/tsan/simple_stack2.cc index 12ee0da310906..bbea713077497 100644 --- a/test/tsan/simple_stack2.cc +++ b/test/tsan/simple_stack2.cc @@ -1,4 +1,4 @@ -// RUN: %clangxx_tsan -O1 %s -o %T/simple_stack2.cc.exe && %deflake %run %T/simple_stack2.cc.exe | FileCheck %s +// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s  #include "test.h"  int Global; @@ -44,10 +44,10 @@ int main() {  // CHECK:      WARNING: ThreadSanitizer: data race  // CHECK-NEXT:   Write of size 4 at {{.*}} by thread T1: -// CHECK-NEXT:     #0 foo1{{.*}} {{.*}}simple_stack2.cc:7{{(:10)?}} ({{.*}}) -// CHECK-NEXT:     #1 bar1{{.*}} {{.*}}simple_stack2.cc:14{{(:3)?}} ({{.*}}) -// CHECK-NEXT:     #2 Thread1{{.*}} {{.*}}simple_stack2.cc:32{{(:3)?}} ({{.*}}) +// CHECK-NEXT:     #0 foo1{{.*}} {{.*}}simple_stack2.cc:[[@LINE-40]]{{(:10)?}} ({{.*}}) +// CHECK-NEXT:     #1 bar1{{.*}} {{.*}}simple_stack2.cc:[[@LINE-34]]{{(:3)?}} ({{.*}}) +// CHECK-NEXT:     #2 Thread1{{.*}} {{.*}}simple_stack2.cc:[[@LINE-17]]{{(:3)?}} ({{.*}})  // CHECK:        Previous read of size 4 at {{.*}} by main thread: -// CHECK-NEXT:     #0 foo2{{.*}} {{.*}}simple_stack2.cc:18{{(:22)?}} ({{.*}}) -// CHECK-NEXT:     #1 bar2{{.*}} {{.*}}simple_stack2.cc:27{{(:3)?}} ({{.*}}) -// CHECK-NEXT:     #2 main{{.*}} {{.*}}simple_stack2.cc:40{{(:3)?}} ({{.*}}) +// CHECK-NEXT:     #0 foo2{{.*}} {{.*}}simple_stack2.cc:[[@LINE-33]]{{(:22)?}} ({{.*}}) +// CHECK-NEXT:     #1 bar2{{.*}} {{.*}}simple_stack2.cc:[[@LINE-25]]{{(:3)?}} ({{.*}}) +// CHECK-NEXT:     #2 main{{.*}} {{.*}}simple_stack2.cc:[[@LINE-13]]{{(:3)?}} ({{.*}}) diff --git a/test/tsan/static_init6.cc b/test/tsan/static_init6.cc index fd22e0a02e6a5..06215ced3c76e 100644 --- a/test/tsan/static_init6.cc +++ b/test/tsan/static_init6.cc @@ -1,4 +1,5 @@ -// RUN: %clangxx_tsan -stdlib=libstdc++ -static-libstdc++ -O1 %s -o %t && %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_tsan %linux_static_libstdcplusplus -O1 %s -o %t && %run %t 2>&1 \ +// RUN: | FileCheck %s  #include <pthread.h>  #include <stdlib.h>  #include <stdio.h> diff --git a/test/tsan/strerror_r.cc b/test/tsan/strerror_r.cc index ad482013012c2..cfe8a18c17367 100644 --- a/test/tsan/strerror_r.cc +++ b/test/tsan/strerror_r.cc @@ -1,26 +1,30 @@  // RUN: %clangxx_tsan -O1 -DTEST_ERROR=ERANGE %s -o %t && %run %t 2>&1 | FileCheck --check-prefixes=CHECK,CHECK-SYS %s  // RUN: %clangxx_tsan -O1 -DTEST_ERROR=-1 %s -o %t && not %run %t 2>&1 | FileCheck --check-prefixes=CHECK,CHECK-USER %s  // UNSUPPORTED: darwin +// This test provokes a data race under FreeBSD +// XFAIL: freebsd + +#include "test.h" -#include <assert.h>  #include <errno.h>  #include <pthread.h> -#include <stdio.h>  #include <string.h>  char buffer[1000];  void *Thread(void *p) { +  barrier_wait(&barrier);    strerror_r(TEST_ERROR, buffer, sizeof(buffer));    return buffer;  }  int main() { -  pthread_t th[2]; -  pthread_create(&th[0], 0, Thread, 0); -  pthread_create(&th[1], 0, Thread, 0); -  pthread_join(th[0], 0); -  pthread_join(th[1], 0); +  barrier_init(&barrier, 2); +  pthread_t th; +  pthread_create(&th, 0, Thread, 0); +  strerror_r(TEST_ERROR, buffer, sizeof(buffer)); +  barrier_wait(&barrier); +  pthread_join(th, 0);    fprintf(stderr, "DONE\n");  } diff --git a/test/tsan/suppressions_mutex.cc b/test/tsan/suppressions_mutex.cc new file mode 100644 index 0000000000000..5d3a5d05289f1 --- /dev/null +++ b/test/tsan/suppressions_mutex.cc @@ -0,0 +1,19 @@ +// RUN: %clang_tsan -O1 %s -o %t && %env_tsan_opts=suppressions='%s.supp' %run %t 2>&1 | FileCheck %s +#include "test.h" + +void __attribute__((noinline)) suppress_this(pthread_mutex_t *mu) { +  pthread_mutex_destroy(mu); +} + +int main() { +  pthread_mutex_t mu; +  pthread_mutex_init(&mu, 0); +  pthread_mutex_lock(&mu); +  suppress_this(&mu); +  fprintf(stderr, "DONE\n"); +  return 0; +} + +// CHECK-NOT: failed to open suppressions file +// CHECK-NOT: WARNING: ThreadSanitizer: +// CHECK: DONE diff --git a/test/tsan/suppressions_mutex.cc.supp b/test/tsan/suppressions_mutex.cc.supp new file mode 100644 index 0000000000000..595febbea5ced --- /dev/null +++ b/test/tsan/suppressions_mutex.cc.supp @@ -0,0 +1,2 @@ +mutex:suppress_this + diff --git a/test/tsan/test.h b/test/tsan/test.h index bc4f7aad55fea..595590b58ce2d 100644 --- a/test/tsan/test.h +++ b/test/tsan/test.h @@ -56,7 +56,7 @@ unsigned long long monotonic_clock_ns() {  #endif  //The const kPCInc must be in sync with StackTrace::GetPreviousInstructionPc -#if defined(__powerpc64__) +#if defined(__powerpc64__) || defined(__arm__) || defined(__aarch64__)  // PCs are always 4 byte aligned.  const int kPCInc = 4;  #elif defined(__sparc__) || defined(__mips__) diff --git a/test/tsan/thread_name.cc b/test/tsan/thread_name.cc index 17caa62ef4401..1fa055579ee01 100644 --- a/test/tsan/thread_name.cc +++ b/test/tsan/thread_name.cc @@ -7,7 +7,7 @@  #elif defined(__FreeBSD__)  #include <pthread_np.h>  #define USE_PTHREAD_SETNAME_NP 1 -#define tasn_pthread_setname_np pthread_set_name_np +#define tsan_pthread_setname_np pthread_set_name_np  #elif defined(__NetBSD__)  #define USE_PTHREAD_SETNAME_NP 1  #define tsan_pthread_setname_np(a, b) pthread_setname_np((a), "%s", (void *)(b)) diff --git a/test/tsan/tls_race2.cc b/test/tsan/tls_race2.cc index f3139b69fc082..5968e66d5b181 100644 --- a/test/tsan/tls_race2.cc +++ b/test/tsan/tls_race2.cc @@ -22,6 +22,8 @@ int main() {    pthread_t t;    pthread_create(&t, 0, Thread, 0);    pthread_join(t, 0); +  fprintf(stderr, "DONE\n"); +  return 0;  }  // CHECK: WARNING: ThreadSanitizer: data race @@ -29,3 +31,4 @@ int main() {  // CHECK-FreeBSD:   Location is TLS of thread T1.  // CHECK-NetBSD:   Location is TLS of thread T1.  // CHECK-Darwin:   Location is heap block of size 4 +// CHECK: DONE diff --git a/test/ubsan/CMakeLists.txt b/test/ubsan/CMakeLists.txt index 7791681472fda..fa8b16b8093e0 100644 --- a/test/ubsan/CMakeLists.txt +++ b/test/ubsan/CMakeLists.txt @@ -38,6 +38,9 @@ set(UBSAN_TEST_ARCH ${UBSAN_SUPPORTED_ARCH})  if(APPLE)    darwin_filter_host_archs(UBSAN_SUPPORTED_ARCH UBSAN_TEST_ARCH)  endif() +if(OS_NAME MATCHES "SunOS") +  list(REMOVE_ITEM UBSAN_TEST_ARCH x86_64) +endif()  foreach(arch ${UBSAN_TEST_ARCH})    set(UBSAN_TEST_TARGET_ARCH ${arch}) diff --git a/test/ubsan/TestCases/Float/cast-overflow.cpp b/test/ubsan/TestCases/Float/cast-overflow.cpp index a53c663b13674..460150aa3b2ec 100644 --- a/test/ubsan/TestCases/Float/cast-overflow.cpp +++ b/test/ubsan/TestCases/Float/cast-overflow.cpp @@ -29,6 +29,16 @@  # ifndef LITTLE_ENDIAN  #  define LITTLE_ENDIAN _LITTLE_ENDIAN  # endif +#elif defined(__sun__) && defined(__svr4__) +// Solaris provides _BIG_ENDIAN/_LITTLE_ENDIAN selector in sys/types.h. +# include <sys/types.h> +# define BIG_ENDIAN 4321 +# define LITTLE_ENDIAN 1234 +# if defined(_BIG_ENDIAN) +#  define BYTE_ORDER BIG_ENDIAN +# else +#  define BYTE_ORDER LITTLE_ENDIAN +# endif  #elif defined(_WIN32)  # define BYTE_ORDER 0  # define BIG_ENDIAN 1 diff --git a/test/ubsan/TestCases/Integer/negate-overflow.cpp b/test/ubsan/TestCases/Integer/negate-overflow.cpp index 72438d3fba7f0..5e36b9db657ff 100644 --- a/test/ubsan/TestCases/Integer/negate-overflow.cpp +++ b/test/ubsan/TestCases/Integer/negate-overflow.cpp @@ -1,10 +1,12 @@  // RUN: %clangxx -fsanitize=signed-integer-overflow %s -o %t1 && %run %t1 2>&1 | FileCheck %s --check-prefix=CHECKS  // RUN: %clangxx -fsanitize=unsigned-integer-overflow %s -o %t2 && %run %t2 2>&1 | FileCheck %s --check-prefix=CHECKU +// RUN: %clangxx -fsanitize=unsigned-integer-overflow %s -o %t2 && %env_ubsan_opts=silence_unsigned_overflow=1 %run %t2 2>&1 | FileCheck %s --check-prefix=CHECKU-SILENT --allow-empty  int main() {    // CHECKS-NOT: runtime error -  // CHECKU: negate-overflow.cpp:[[@LINE+2]]:3: runtime error: negation of 2147483648 cannot be represented in type 'unsigned int' +  // CHECKU: negate-overflow.cpp:[[@LINE+3]]:3: runtime error: negation of 2147483648 cannot be represented in type 'unsigned int'    // CHECKU-NOT: cast to an unsigned +  // CHECKU-SILENT-NOT: runtime error    -unsigned(-0x7fffffff - 1); // ok    // CHECKS: negate-overflow.cpp:[[@LINE+2]]:3: runtime error: negation of -2147483648 cannot be represented in type 'int'; cast to an unsigned type to negate this value to itself    // CHECKU-NOT: runtime error diff --git a/test/ubsan/TestCases/Integer/no-recover.cpp b/test/ubsan/TestCases/Integer/no-recover.cpp index bbc2f8d2c1c46..515ebbd0702ed 100644 --- a/test/ubsan/TestCases/Integer/no-recover.cpp +++ b/test/ubsan/TestCases/Integer/no-recover.cpp @@ -1,5 +1,6 @@  // RUN: %clangxx -fsanitize=unsigned-integer-overflow %s -o %t && %run %t 2>&1 | FileCheck %s --check-prefix=RECOVER  // RUN: %clangxx -fsanitize=unsigned-integer-overflow -fno-sanitize-recover=all -fsanitize-recover=unsigned-integer-overflow %s -o %t && %run %t 2>&1 | FileCheck %s --check-prefix=RECOVER +// RUN: %env_ubsan_opts=silence_unsigned_overflow=1 %run %t 2>&1 | FileCheck %s --check-prefix=SILENT-RECOVER --allow-empty  // RUN: %clangxx -fsanitize=unsigned-integer-overflow -fno-sanitize-recover=unsigned-integer-overflow %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=ABORT  #include <stdint.h> @@ -18,5 +19,6 @@ int main() {    (void)(uint64_t(10000000000000000000ull) + uint64_t(9000000000000000000ull));    // RECOVER: 10000000000000000000 + 9000000000000000000 cannot be represented in type 'unsigned {{long( long)?}}' +  // SILENT-RECOVER-NOT: runtime error    // ABORT-NOT: runtime error  } diff --git a/test/ubsan/TestCases/Integer/suppressions.cpp b/test/ubsan/TestCases/Integer/suppressions.cpp index f72d82edf278c..65d8bba13b018 100644 --- a/test/ubsan/TestCases/Integer/suppressions.cpp +++ b/test/ubsan/TestCases/Integer/suppressions.cpp @@ -4,6 +4,8 @@  // requires the compiler-rt runtime to be able to symbolize stack addresses.  // REQUIRES: can-symbolize  // UNSUPPORTED: android +// Output differs on OpenBSD longer by displaying the values. +// XFAIL: openbsd  // Fails without any suppression.  // RUN: %env_ubsan_opts=halt_on_error=1 not %run %t 2>&1 | FileCheck %s diff --git a/test/ubsan/TestCases/Misc/coverage-levels.cc b/test/ubsan/TestCases/Misc/coverage-levels.cc index 05c19937ddf88..364f985c50514 100644 --- a/test/ubsan/TestCases/Misc/coverage-levels.cc +++ b/test/ubsan/TestCases/Misc/coverage-levels.cc @@ -3,26 +3,28 @@  // FIXME: Port the environment variable logic below for the lit shell.  // REQUIRES: shell  // -// RUN: rm -rf %T/coverage-levels && mkdir %T/coverage-levels +// RUN: rm -rf %t-dir && mkdir %t-dir  // RUN: %clangxx -fsanitize=shift                        -DGOOD_SHIFT=1 -O1 -fsanitize-coverage=func  %s -o %t -// RUN: %env_ubsan_opts=coverage=1:verbosity=1:coverage_dir='"%T/coverage-levels"' %run %t 2>&1 | FileCheck %s --check-prefix=CHECK1 --check-prefix=CHECK_NOWARN +// RUN: %env_ubsan_opts=coverage=1:verbosity=1:coverage_dir='"%t-dir"' %run %t 2>&1 | FileCheck %s --check-prefix=CHECK1 --check-prefix=CHECK_NOWARN  // RUN: %clangxx -fsanitize=undefined                    -DGOOD_SHIFT=1 -O1 -fsanitize-coverage=func  %s -o %t -// RUN: %env_ubsan_opts=coverage=1:verbosity=1:coverage_dir='"%T/coverage-levels"' %run %t 2>&1 | FileCheck %s --check-prefix=CHECK1 --check-prefix=CHECK_NOWARN +// RUN: %env_ubsan_opts=coverage=1:verbosity=1:coverage_dir='"%t-dir"' %run %t 2>&1 | FileCheck %s --check-prefix=CHECK1 --check-prefix=CHECK_NOWARN  // Also works without any sanitizer.  // RUN: %clangxx                                         -DGOOD_SHIFT=1 -O1 -fsanitize-coverage=func  %s -o %t -// RUN: %env_ubsan_opts=coverage=1:verbosity=1:coverage_dir='"%T/coverage-levels"' %run %t 2>&1 | FileCheck %s --check-prefix=CHECK1 --check-prefix=CHECK_NOWARN +// RUN: %env_ubsan_opts=coverage=1:verbosity=1:coverage_dir='"%t-dir"' %run %t 2>&1 | FileCheck %s --check-prefix=CHECK1 --check-prefix=CHECK_NOWARN  // RUN: %clangxx -fsanitize=shift -O1 -fsanitize-coverage=func  %s -o %t -// RUN: %env_ubsan_opts=coverage=1:verbosity=1:coverage_dir='"%T/coverage-levels"' %run %t 2>&1 | FileCheck %s --check-prefix=CHECK1 --check-prefix=CHECK_WARN +// RUN: %env_ubsan_opts=coverage=1:verbosity=1:coverage_dir='"%t-dir"' %run %t 2>&1 | FileCheck %s --check-prefix=CHECK1 --check-prefix=CHECK_WARN  // RUN: %clangxx -fsanitize=shift -O1 -fsanitize-coverage=bb  %s -o %t -// RUN: %env_ubsan_opts=coverage=1:verbosity=1:coverage_dir='"%T/coverage-levels"' %run %t 2>&1 | FileCheck %s --check-prefix=CHECK2 --check-prefix=CHECK_WARN +// RUN: %env_ubsan_opts=coverage=1:verbosity=1:coverage_dir='"%t-dir"' %run %t 2>&1 | FileCheck %s --check-prefix=CHECK2 --check-prefix=CHECK_WARN  // RUN: %clangxx -fsanitize=shift -O1 -fsanitize-coverage=edge  %s -o %t -// RUN: %env_ubsan_opts=coverage=1:verbosity=1:coverage_dir='"%T/coverage-levels"' %run %t 2>&1 | FileCheck %s --check-prefix=CHECK3 --check-prefix=CHECK_WARN +// RUN: %env_ubsan_opts=coverage=1:verbosity=1:coverage_dir='"%t-dir"' %run %t 2>&1 | FileCheck %s --check-prefix=CHECK3 --check-prefix=CHECK_WARN  // Coverage is not yet implemented in TSan.  // XFAIL: ubsan-tsan  // UNSUPPORTED: ubsan-standalone-static +// No coverage support +// UNSUPPORTED: openbsd  volatile int sink;  int main(int argc, char **argv) { diff --git a/test/ubsan/TestCases/Misc/missing_return.cpp b/test/ubsan/TestCases/Misc/missing_return.cpp index 5c5b286f1a65f..fe8c8bae603d9 100644 --- a/test/ubsan/TestCases/Misc/missing_return.cpp +++ b/test/ubsan/TestCases/Misc/missing_return.cpp @@ -1,6 +1,8 @@  // RUN: %clangxx -fsanitize=return %gmlt %s -O3 -o %t  // RUN: not %run %t 2>&1 | FileCheck %s  // RUN: %env_ubsan_opts=print_stacktrace=1 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-STACKTRACE +// Error message does not exact what expected +// XFAIL: openbsd  // CHECK: missing_return.cpp:[[@LINE+1]]:5: runtime error: execution reached the end of a value-returning function without returning a value  int f() { diff --git a/test/ubsan/TestCases/Misc/monitor.cpp b/test/ubsan/TestCases/Misc/monitor.cpp new file mode 100644 index 0000000000000..6c5cacfed8be2 --- /dev/null +++ b/test/ubsan/TestCases/Misc/monitor.cpp @@ -0,0 +1,44 @@ +// RUN: %clangxx -w -fsanitize=bool %s -o %t +// RUN: %run %t 2>&1 | FileCheck %s + +// __ubsan_on_report is not defined as weak. Redefining it here isn't supported +// on Windows. +// +// UNSUPPORTED: win32 +// Linkage issue +// XFAIL: openbsd + +#include <cstdio> + +extern "C" { +void __ubsan_get_current_report_data(const char **OutIssueKind, +                                     const char **OutMessage, +                                     const char **OutFilename, +                                     unsigned *OutLine, unsigned *OutCol, +                                     char **OutMemoryAddr); + +// Override the definition of __ubsan_on_report from the runtime, just for +// testing purposes. +void __ubsan_on_report(void) { +  const char *IssueKind, *Message, *Filename; +  unsigned Line, Col; +  char *Addr; +  __ubsan_get_current_report_data(&IssueKind, &Message, &Filename, &Line, &Col, +                                  &Addr); + +  printf("Issue: %s\n", IssueKind); +  printf("Location: %s:%u:%u\n", Filename, Line, Col); +  printf("Message: %s\n", Message); + +  (void)Addr; +} +} + +int main() { +  char C = 3; +  bool B = *(bool *)&C; +  // CHECK: Issue: invalid-bool-load +  // CHECK-NEXT: Location: {{.*}}monitor.cpp:[[@LINE-2]]:12 +  // CHECK-NEXT: Message: Load of value 3, which is not a valid value for type 'bool' +  return 0; +} diff --git a/test/ubsan/TestCases/TypeCheck/Function/function.cpp b/test/ubsan/TestCases/TypeCheck/Function/function.cpp index 25b2bdc32c7aa..7b9f0982639a2 100644 --- a/test/ubsan/TestCases/TypeCheck/Function/function.cpp +++ b/test/ubsan/TestCases/TypeCheck/Function/function.cpp @@ -1,8 +1,10 @@ -// RUN: %clangxx -fsanitize=function %s -O3 -g -o %t +// RUN: %clangxx -std=c++17 -fsanitize=function %s -O3 -g -o %t  // RUN: %run %t 2>&1 | FileCheck %s  // Verify that we can disable symbolization if needed:  // RUN: %env_ubsan_opts=symbolize=0 %run %t 2>&1 | FileCheck %s --check-prefix=NOSYM  // XFAIL: win32,win64 +// Unsupported function flag +// UNSUPPORTED: openbsd  #include <stdint.h> @@ -23,9 +25,49 @@ void make_invalid_call() {    reinterpret_cast<void (*)(int)>(reinterpret_cast<uintptr_t>(f))(42);  } +void f1(int) {} +void f2(unsigned int) {} +void f3(int) noexcept {} +void f4(unsigned int) noexcept {} + +void check_noexcept_calls() { +  void (*p1)(int); +  p1 = &f1; +  p1(0); +  p1 = reinterpret_cast<void (*)(int)>(&f2); +  // CHECK: function.cpp:[[@LINE+2]]:3: runtime error: call to function f2(unsigned int) through pointer to incorrect function type 'void (*)(int)' +  // NOSYM: function.cpp:[[@LINE+1]]:3: runtime error: call to function (unknown) through pointer to incorrect function type 'void (*)(int)' +  p1(0); +  p1 = &f3; +  p1(0); +  p1 = reinterpret_cast<void (*)(int)>(&f4); +  // CHECK: function.cpp:[[@LINE+2]]:3: runtime error: call to function f4(unsigned int) through pointer to incorrect function type 'void (*)(int)' +  // NOSYM: function.cpp:[[@LINE+1]]:3: runtime error: call to function (unknown) through pointer to incorrect function type 'void (*)(int)' +  p1(0); + +  void (*p2)(int) noexcept; +  p2 = reinterpret_cast<void (*)(int) noexcept>(&f1); +  // TODO: Unclear whether calling a non-noexcept function through a pointer to +  // nexcept function should cause an error. +  // CHECK-NOT: function.cpp:[[@LINE+2]]:3: runtime error: call to function f1(int) through pointer to incorrect function type 'void (*)(int) noexcept' +  // NOSYM-NOT: function.cpp:[[@LINE+1]]:3: runtime error: call to function (unknown) through pointer to incorrect function type 'void (*)(int) noexcept' +  p2(0); +  p2 = reinterpret_cast<void (*)(int) noexcept>(&f2); +  // CHECK: function.cpp:[[@LINE+2]]:3: runtime error: call to function f2(unsigned int) through pointer to incorrect function type 'void (*)(int) noexcept' +  // NOSYM: function.cpp:[[@LINE+1]]:3: runtime error: call to function (unknown) through pointer to incorrect function type 'void (*)(int) noexcept' +  p2(0); +  p2 = &f3; +  p2(0); +  p2 = reinterpret_cast<void (*)(int) noexcept>(&f4); +  // CHECK: function.cpp:[[@LINE+2]]:3: runtime error: call to function f4(unsigned int) through pointer to incorrect function type 'void (*)(int) noexcept' +  // NOSYM: function.cpp:[[@LINE+1]]:3: runtime error: call to function (unknown) through pointer to incorrect function type 'void (*)(int) noexcept' +  p2(0); +} +  int main(void) {    make_valid_call();    make_invalid_call(); +  check_noexcept_calls();    // Check that no more errors will be printed.    // CHECK-NOT: runtime error: call to function    // NOSYM-NOT: runtime error: call to function diff --git a/test/ubsan/TestCases/TypeCheck/misaligned.cpp b/test/ubsan/TestCases/TypeCheck/misaligned.cpp index 4eaedf37e5658..a5cefaa31cd64 100644 --- a/test/ubsan/TestCases/TypeCheck/misaligned.cpp +++ b/test/ubsan/TestCases/TypeCheck/misaligned.cpp @@ -11,6 +11,8 @@  // RUN: %clangxx -fsanitize=alignment -fno-sanitize-recover=alignment %s -O3 -o %t  // RUN: not %run %t w1 2>&1 | FileCheck %s --check-prefix=CHECK-WILD +// Compilation error make the test fails. +// XFAIL: openbsd  #include <new> diff --git a/test/ubsan/TestCases/TypeCheck/vptr.cpp b/test/ubsan/TestCases/TypeCheck/vptr.cpp index d7848c4ce3f90..9b53e80957778 100644 --- a/test/ubsan/TestCases/TypeCheck/vptr.cpp +++ b/test/ubsan/TestCases/TypeCheck/vptr.cpp @@ -40,6 +40,8 @@  // UNSUPPORTED: win32  // Suppressions file not pushed to the device.  // UNSUPPORTED: android +// Compilation error +// UNSUPPORTED: openbsd  #include <new>  #include <typeinfo>  #include <assert.h> diff --git a/test/ubsan/lit.common.cfg b/test/ubsan/lit.common.cfg index 83475a2dc36c0..e20832bd655fe 100644 --- a/test/ubsan/lit.common.cfg +++ b/test/ubsan/lit.common.cfg @@ -68,7 +68,7 @@ config.substitutions.append( ("%gmlt ", " ".join(config.debug_info_flags) + " ")  config.suffixes = ['.c', '.cc', '.cpp']  # Check that the host supports UndefinedBehaviorSanitizer tests -if config.host_os not in ['Linux', 'Darwin', 'FreeBSD', 'Windows', 'NetBSD']: +if config.host_os not in ['Linux', 'Darwin', 'FreeBSD', 'Windows', 'NetBSD', 'SunOS', 'OpenBSD']:    config.unsupported = True  config.available_features.add('arch=' + config.target_arch) diff --git a/test/ubsan_minimal/CMakeLists.txt b/test/ubsan_minimal/CMakeLists.txt index 712654e945186..5da5fcd02b94c 100644 --- a/test/ubsan_minimal/CMakeLists.txt +++ b/test/ubsan_minimal/CMakeLists.txt @@ -4,6 +4,9 @@ set(UBSAN_TEST_ARCH ${UBSAN_SUPPORTED_ARCH})  if(APPLE)    darwin_filter_host_archs(UBSAN_SUPPORTED_ARCH UBSAN_TEST_ARCH)  endif() +if(OS_NAME MATCHES "SunOS") +  list(REMOVE_ITEM UBSAN_TEST_ARCH x86_64) +endif()  set(UBSAN_TESTSUITES)  set(UBSAN_TEST_DEPS ${SANITIZER_COMMON_LIT_TEST_DEPS}) diff --git a/test/ubsan_minimal/lit.common.cfg b/test/ubsan_minimal/lit.common.cfg index e8b42bb823c89..a436a315f0a6a 100644 --- a/test/ubsan_minimal/lit.common.cfg +++ b/test/ubsan_minimal/lit.common.cfg @@ -30,7 +30,7 @@ config.substitutions.append( ("%clangxx ", build_invocation(clang_ubsan_cxxflags  config.suffixes = ['.c', '.cc', '.cpp']  # Check that the host supports UndefinedBehaviorSanitizerMinimal tests -if config.host_os not in ['Linux', 'FreeBSD', 'NetBSD', 'Darwin']: # TODO: Windows +if config.host_os not in ['Linux', 'FreeBSD', 'NetBSD', 'Darwin', 'OpenBSD']: # TODO: Windows    config.unsupported = True  # Don't target x86_64h if the test machine can't execute x86_64h binaries. diff --git a/test/xray/CMakeLists.txt b/test/xray/CMakeLists.txt index b51b3cd0ccd80..d049ac0f979fe 100644 --- a/test/xray/CMakeLists.txt +++ b/test/xray/CMakeLists.txt @@ -28,11 +28,13 @@ if (COMPILER_RT_BUILD_XRAY AND COMPILER_RT_HAS_XRAY)    # Add unit tests.    if(COMPILER_RT_INCLUDE_TESTS) -    configure_lit_site_cfg( -      ${CMAKE_CURRENT_SOURCE_DIR}/Unit/lit.site.cfg.in -      ${CMAKE_CURRENT_BINARY_DIR}/Unit/lit.site.cfg) -    list(APPEND XRAY_TEST_DEPS XRayUnitTests) -    list(APPEND XRAY_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/Unit) +    if(UNIX AND NOT APPLE) +      configure_lit_site_cfg( +        ${CMAKE_CURRENT_SOURCE_DIR}/Unit/lit.site.cfg.in +        ${CMAKE_CURRENT_BINARY_DIR}/Unit/lit.site.cfg) +      list(APPEND XRAY_TEST_DEPS XRayUnitTests) +      list(APPEND XRAY_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/Unit) +    endif()    endif()  endif() diff --git a/test/xray/TestCases/Linux/always-never-instrument.cc b/test/xray/TestCases/Posix/always-never-instrument.cc index 4e196859bcdae..fd9299b756bb8 100644 --- a/test/xray/TestCases/Linux/always-never-instrument.cc +++ b/test/xray/TestCases/Posix/always-never-instrument.cc @@ -9,7 +9,7 @@  // RUN:    FileCheck %s --check-prefix NOINSTR  // RUN: %llvm_xray extract -symbolize %t | \  // RUN:    FileCheck %s --check-prefix ALWAYSINSTR -// REQUIRES: x86_64-linux +// REQUIRES: x86_64-target-arch  // REQUIRES: built-in-llvm-tree  // NOINSTR-NOT: {{.*__xray_NeverInstrumented.*}} diff --git a/test/xray/TestCases/Linux/arg1-arg0-logging.cc b/test/xray/TestCases/Posix/arg1-arg0-logging.cc index e7730bfa6172d..757f81a8babb9 100644 --- a/test/xray/TestCases/Linux/arg1-arg0-logging.cc +++ b/test/xray/TestCases/Posix/arg1-arg0-logging.cc @@ -1,7 +1,7 @@  // Allow having both the no-arg and arg1 logging implementation live together,  // and be called in the correct cases.  // -// RUN: rm arg0-arg1-logging-* || true +// RUN: rm -f arg0-arg1-logging-*  // RUN: %clangxx_xray -std=c++11 %s -o %t  // RUN: XRAY_OPTIONS="patch_premain=true verbosity=1 xray_logfile_base=arg0-arg1-logging-" %run %t  // diff --git a/test/xray/TestCases/Linux/arg1-logger.cc b/test/xray/TestCases/Posix/arg1-logger.cc index 25dda13fb23d9..a6ca0a4952504 100644 --- a/test/xray/TestCases/Linux/arg1-logger.cc +++ b/test/xray/TestCases/Posix/arg1-logger.cc @@ -2,13 +2,13 @@  // using a custom logging function.  //  // RUN: %clangxx_xray -std=c++11 %s -o %t -// RUN: rm arg1-logger-* || true +// RUN: rm -f arg1-logger-*  // RUN: XRAY_OPTIONS="patch_premain=true verbosity=1 xray_naive_log=true \  // RUN:    xray_logfile_base=arg1-logger-" %run %t 2>&1 | FileCheck %s  //  // After all that, clean up the XRay log file.  // -// RUN: rm arg1-logger-* || true +// RUN: rm -f arg1-logger-*  //  // At the time of writing, the ARM trampolines weren't written yet.  // XFAIL: arm || aarch64 || mips diff --git a/test/xray/TestCases/Linux/arg1-logging-implicit-this.cc b/test/xray/TestCases/Posix/arg1-logging-implicit-this.cc index 66dfce9a3b7d5..d8dd62247bffd 100644 --- a/test/xray/TestCases/Linux/arg1-logging-implicit-this.cc +++ b/test/xray/TestCases/Posix/arg1-logging-implicit-this.cc @@ -1,10 +1,10 @@  // Intercept the implicit 'this' argument of class member functions.  //  // RUN: %clangxx_xray -g -std=c++11 %s -o %t -// RUN: rm log-args-this-* || true +// RUN: rm -f log-args-this-*  // RUN: XRAY_OPTIONS="patch_premain=true verbosity=1 xray_logfile_base=log-args-this-" %run %t  // -// XFAIL: arm || aarch64 || mips +// XFAIL: FreeBSD || arm || aarch64 || mips  // UNSUPPORTED: powerpc64le  #include "xray/xray_interface.h"  #include <cassert> diff --git a/test/xray/TestCases/Linux/argv0-log-file-name.cc b/test/xray/TestCases/Posix/argv0-log-file-name.cc index 2f9a234f80644..2f9a234f80644 100644 --- a/test/xray/TestCases/Linux/argv0-log-file-name.cc +++ b/test/xray/TestCases/Posix/argv0-log-file-name.cc diff --git a/test/xray/TestCases/Linux/basic-filtering.cc b/test/xray/TestCases/Posix/basic-filtering.cc index b758859cf6cb9..db07ef510c5c7 100644 --- a/test/xray/TestCases/Linux/basic-filtering.cc +++ b/test/xray/TestCases/Posix/basic-filtering.cc @@ -2,8 +2,8 @@  // logging implementation.  // RUN: %clangxx_xray -std=c++11 %s -o %t -g -// RUN: rm basic-filtering-* || true -// RUN: XRAY_OPTIONS="patch_premain=true xray_naive_log=true verbosity=1 \ +// RUN: rm -f basic-filtering-* +// RUN: XRAY_OPTIONS="patch_premain=true xray_mode=xray-basic verbosity=1 \  // RUN:     xray_logfile_base=basic-filtering- \  // RUN:     xray_naive_log_func_duration_threshold_us=1000 \  // RUN:     xray_naive_log_max_stack_depth=2" %run %t 2>&1 | \ @@ -11,9 +11,19 @@  // RUN: %llvm_xray convert --symbolize --output-format=yaml -instr_map=%t \  // RUN:     "`ls basic-filtering-* | head -1`" | \  // RUN:     FileCheck %s --check-prefix TRACE -// RUN: rm basic-filtering-* || true +// RUN: rm -f basic-filtering-*  // -// REQUIRES: x86_64-linux +// Now check support for the XRAY_BASIC_OPTIONS environment variable. +// RUN: XRAY_OPTIONS="patch_premain=true xray_mode=xray-basic verbosity=1 \ +// RUN:     xray_logfile_base=basic-filtering-" \ +// RUN: XRAY_BASIC_OPTIONS="func_duration_threshold_us=1000 max_stack_depth=2" \ +// RUN:     %run %t 2>&1 | FileCheck %s +// RUN: %llvm_xray convert --symbolize --output-format=yaml -instr_map=%t \ +// RUN:     "`ls basic-filtering-* | head -1`" | \ +// RUN:     FileCheck %s --check-prefix TRACE +// RUN: rm -f basic-filtering-* +// +// REQUIRES: x86_64-target-arch  // REQUIRES: built-in-llvm-tree  #include <cstdio> diff --git a/test/xray/TestCases/Posix/c-test.cc b/test/xray/TestCases/Posix/c-test.cc new file mode 100644 index 0000000000000..28a7870d0f743 --- /dev/null +++ b/test/xray/TestCases/Posix/c-test.cc @@ -0,0 +1,15 @@ +// RUN: %clang_xray -g -fxray-modes=xray-basic,xray-fdr,xray-profiling -o %t %s +// RUN: rm -f xray-log.c-test.* +// RUN: XRAY_OPTIONS=patch_premain=true:verbosity=1:xray_mode=xray-basic %t \ +// RUN:     2>&1 | FileCheck %s +// RUN: rm -f xray-log.c-test.* +// +// REQUIRES: x86_64-target-arch +// REQUIRES: built-in-llvm-tree +__attribute__((xray_always_instrument)) void always() {} + +int main() { +  always(); +} + +// CHECK: =={{[0-9].*}}==XRay: Log file in '{{.*}}' diff --git a/test/xray/TestCases/Linux/common-trampoline-alignment.cc b/test/xray/TestCases/Posix/common-trampoline-alignment.cc index 5d1cc1e9b4516..dac0789abdec7 100644 --- a/test/xray/TestCases/Linux/common-trampoline-alignment.cc +++ b/test/xray/TestCases/Posix/common-trampoline-alignment.cc @@ -4,7 +4,7 @@  // RUN: %clangxx_xray -std=c++11 %s -o %t  // RUN: XRAY_OPTIONS="patch_premain=false verbosity=1 xray_naive_log=false" \  // RUN:     %run %t 2>&1 -// REQUIRES: x86_64-linux +// REQUIRES: x86_64-target-arch  // REQUIRES: built-in-llvm-tree  #include "xray/xray_interface.h"  #include <stdio.h> diff --git a/test/xray/TestCases/Linux/coverage-sample.cc b/test/xray/TestCases/Posix/coverage-sample.cc index 62c13ba3d42a9..62c13ba3d42a9 100644 --- a/test/xray/TestCases/Linux/coverage-sample.cc +++ b/test/xray/TestCases/Posix/coverage-sample.cc diff --git a/test/xray/TestCases/Linux/custom-event-handler-alignment.cc b/test/xray/TestCases/Posix/custom-event-handler-alignment.cc index 447f6e4f2b425..c8de18b0e2b64 100644 --- a/test/xray/TestCases/Linux/custom-event-handler-alignment.cc +++ b/test/xray/TestCases/Posix/custom-event-handler-alignment.cc @@ -4,7 +4,7 @@  // RUN: %clangxx_xray -std=c++11 %s -o %t  // RUN: XRAY_OPTIONS="patch_premain=false verbosity=1 xray_naive_log=false" \  // RUN:     %run %t 2>&1 -// REQUIRES: x86_64-linux +// REQUIRES: x86_64-target-arch  // REQUIRES: built-in-llvm-tree  #include <xmmintrin.h>  #include <stdio.h> diff --git a/test/xray/TestCases/Linux/custom-event-logging.cc b/test/xray/TestCases/Posix/custom-event-logging.cc index 48fd62034194a..48fd62034194a 100644 --- a/test/xray/TestCases/Linux/custom-event-logging.cc +++ b/test/xray/TestCases/Posix/custom-event-logging.cc diff --git a/test/xray/TestCases/Posix/fdr-mode-inmemory.cc b/test/xray/TestCases/Posix/fdr-mode-inmemory.cc new file mode 100644 index 0000000000000..ff31626d77798 --- /dev/null +++ b/test/xray/TestCases/Posix/fdr-mode-inmemory.cc @@ -0,0 +1,50 @@ +// RUN: %clangxx_xray -g -std=c++11 %s -o %t -fxray-modes=xray-fdr +// RUN: rm -f fdr-inmemory-test-* +// RUN: XRAY_OPTIONS="patch_premain=false xray_logfile_base=fdr-inmemory-test- \ +// RUN:     verbosity=1" \ +// RUN: XRAY_FDR_OPTIONS="no_file_flush=true func_duration_threshold_us=0" \ +// RUN:     %run %t 2>&1 | FileCheck %s +// RUN: FILES=`find %T -name 'fdr-inmemory-test-*' | wc -l` +// RUN: [ $FILES -eq 0 ] +// RUN: rm -f fdr-inmemory-test-* +// +// REQUIRES: x86_64-target-arch +// REQUIRES: built-in-llvm-tree + +#include "xray/xray_log_interface.h" +#include <cassert> +#include <iostream> + +uint64_t var = 0; +uint64_t buffers = 0; +[[clang::xray_always_instrument]] void __attribute__((noinline)) f() { ++var; } + +int main(int argc, char *argv[]) { +  assert(__xray_log_select_mode("xray-fdr") == +         XRayLogRegisterStatus::XRAY_REGISTRATION_OK); +  auto status = __xray_log_init_mode( +      "xray-fdr", +      "buffer_size=4096:buffer_max=10:func_duration_threshold_us=0"); +  assert(status == XRayLogInitStatus::XRAY_LOG_INITIALIZED); +  __xray_patch(); + +  // Create enough entries. +  for (int i = 0; i != 1 << 20; ++i) { +    f(); +  } + +  // Then we want to verify that we're getting 10 buffers outside of the initial +  // header. +  auto finalize_status = __xray_log_finalize(); +  assert(finalize_status == XRayLogInitStatus::XRAY_LOG_FINALIZED); +  auto process_status = +      __xray_log_process_buffers([](const char *, XRayBuffer) { ++buffers; }); +  std::cout << "buffers = " << buffers << std::endl; +  assert(process_status == XRayLogFlushStatus::XRAY_LOG_FLUSHED); +  auto flush_status = __xray_log_flushLog(); +  assert(flush_status == XRayLogFlushStatus::XRAY_LOG_FLUSHED); +  // We expect 11 buffers because 1 header buffer + 10 actual FDR buffers. +  // CHECK: Buffers = 11 +  std::cout << "Buffers = " << buffers << std::endl; +  return 0; +} diff --git a/test/xray/TestCases/Posix/fdr-mode-multiple.cc b/test/xray/TestCases/Posix/fdr-mode-multiple.cc new file mode 100644 index 0000000000000..487e3031325ec --- /dev/null +++ b/test/xray/TestCases/Posix/fdr-mode-multiple.cc @@ -0,0 +1,76 @@ +// RUN: %clangxx_xray -g -std=c++11 %s -o %t -fxray-modes=xray-fdr +// RUN: rm -f fdr-inmemory-test-* +// RUN: XRAY_OPTIONS="patch_premain=false xray_logfile_base=fdr-inmemory-test- \ +// RUN:     verbosity=1" \ +// RUN: XRAY_FDR_OPTIONS="no_file_flush=true func_duration_threshold_us=0" \ +// RUN:     %run %t 2>&1 | FileCheck %s +// RUN: FILES=`find %T -name 'fdr-inmemory-test-*' | wc -l` +// RUN: [ $FILES -eq 0 ] +// RUN: rm -f fdr-inmemory-test-* +// +// REQUIRES: x86_64-target-arch +// REQUIRES: built-in-llvm-tree + +#include "xray/xray_log_interface.h" +#include <cassert> +#include <iostream> + +uint64_t var = 0; +uint64_t buffers = 0; +[[clang::xray_always_instrument]] void __attribute__((noinline)) f() { ++var; } + +int main(int argc, char *argv[]) { +  assert(__xray_log_select_mode("xray-fdr") == +         XRayLogRegisterStatus::XRAY_REGISTRATION_OK); +  auto status = __xray_log_init_mode( +      "xray-fdr", +      "buffer_size=4096:buffer_max=10:func_duration_threshold_us=0"); +  assert(status == XRayLogInitStatus::XRAY_LOG_INITIALIZED); +  __xray_patch(); + +  // Create enough entries. +  for (int i = 0; i != 1 << 20; ++i) { +    f(); +  } + +  // Then we want to verify that we're getting 10 buffers outside of the initial +  // header. +  auto finalize_status = __xray_log_finalize(); +  assert(finalize_status == XRayLogInitStatus::XRAY_LOG_FINALIZED); +  auto process_status = +      __xray_log_process_buffers([](const char *, XRayBuffer) { ++buffers; }); +  std::cout << "buffers = " << buffers << std::endl; +  assert(process_status == XRayLogFlushStatus::XRAY_LOG_FLUSHED); +  auto flush_status = __xray_log_flushLog(); +  assert(flush_status == XRayLogFlushStatus::XRAY_LOG_FLUSHED); +  // We expect 11 buffers because 1 header buffer + 10 actual FDR buffers. +  // CHECK: Buffers = 11 +  std::cout << "Buffers = " << buffers << std::endl; + +  // In this test we ensure that we can restart the cycle after the flush. +  status = __xray_log_init_mode( +      "xray-fdr", +      "buffer_size=4096:buffer_max=10:func_duration_threshold_us=0"); +  assert(status == XRayLogInitStatus::XRAY_LOG_INITIALIZED); +  __xray_patch(); + +  // Create enough entries. +  for (int i = 0; i != 1 << 20; ++i) { +    f(); +  } + +  // Then we want to verify that we're getting 10 buffers outside of the initial +  // header. +  finalize_status = __xray_log_finalize(); +  assert(finalize_status == XRayLogInitStatus::XRAY_LOG_FINALIZED); +  process_status = +      __xray_log_process_buffers([](const char *, XRayBuffer) { ++buffers; }); +  std::cout << "buffers = " << buffers << std::endl; +  assert(process_status == XRayLogFlushStatus::XRAY_LOG_FLUSHED); +  flush_status = __xray_log_flushLog(); +  assert(flush_status == XRayLogFlushStatus::XRAY_LOG_FLUSHED); +  // We expect 22 buffers because 1 header buffer + 10 actual FDR buffers, plus +  // the number of buffers we got from the previous run (also 11). +  // CHECK: Buffers = 22 +  std::cout << "Buffers = " << buffers << std::endl; +} diff --git a/test/xray/TestCases/Linux/fdr-mode.cc b/test/xray/TestCases/Posix/fdr-mode.cc index 744c051cfb2c7..b12d97c0005a7 100644 --- a/test/xray/TestCases/Linux/fdr-mode.cc +++ b/test/xray/TestCases/Posix/fdr-mode.cc @@ -1,14 +1,25 @@  // RUN: %clangxx_xray -g -std=c++11 %s -o %t -// RUN: rm fdr-logging-test-* || true -// RUN: rm fdr-unwrite-test-* || true -// RUN: XRAY_OPTIONS="patch_premain=false xray_naive_log=false xray_logfile_base=fdr-logging-test- xray_fdr_log=true verbosity=1 xray_fdr_log_func_duration_threshold_us=0" %run %t 2>&1 | FileCheck %s -// RUN: XRAY_OPTIONS="patch_premain=false xray_naive_log=false xray_logfile_base=fdr-unwrite-test- xray_fdr_log=true verbosity=1 xray_fdr_log_func_duration_threshold_us=5000" %run %t 2>&1 | FileCheck %s -// RUN: %llvm_xray convert --symbolize --output-format=yaml -instr_map=%t "`ls fdr-logging-test-* | head -1`" | FileCheck %s --check-prefix=TRACE -// RUN: %llvm_xray convert --symbolize --output-format=yaml -instr_map=%t "`ls fdr-unwrite-test-* | head -1`" | FileCheck %s --check-prefix=UNWRITE +// RUN: rm -f fdr-logging-test-* +// RUN: rm -f fdr-unwrite-test-* +// RUN: XRAY_OPTIONS="patch_premain=false xray_logfile_base=fdr-logging-test- \ +// RUN:     xray_mode=xray-fdr verbosity=1" \ +// RUN: XRAY_FDR_OPTIONS="func_duration_threshold_us=0" \ +// RUN:     %run %t 2>&1 | FileCheck %s +// RUN: XRAY_OPTIONS="patch_premain=false \ +// RUN:     xray_logfile_base=fdr-unwrite-test- xray_mode=xray-fdr \ +// RUN:     verbosity=1" \ +// RUN: XRAY_FDR_OPTIONS="func_duration_threshold_us=5000" \ +// RUN:     %run %t 2>&1 | FileCheck %s +// RUN: %llvm_xray convert --symbolize --output-format=yaml -instr_map=%t \ +// RUN:     "`ls fdr-logging-test-* | head -1`" \ +// RUN:     | FileCheck %s --check-prefix=TRACE +// RUN: %llvm_xray convert --symbolize --output-format=yaml -instr_map=%t \ +// RUN:     "`ls fdr-unwrite-test-* | head -1`" \ +// RUN:     | FileCheck %s --check-prefix=UNWRITE  // RUN: rm fdr-logging-test-*  // RUN: rm fdr-unwrite-test-*  // FIXME: Make llvm-xray work on non-x86_64 as well. -// REQUIRES: x86_64-linux +// REQUIRES: x86_64-target-arch  // REQUIRES: built-in-llvm-tree  #include "xray/xray_log_interface.h" @@ -20,9 +31,6 @@  #include <thread>  #include <time.h> -constexpr auto kBufferSize = 16384; -constexpr auto kBufferMax = 10; -  thread_local uint64_t var = 0;  [[clang::xray_always_instrument]] void __attribute__((noinline)) fC() { ++var; } @@ -35,11 +43,12 @@ void __attribute__((noinline)) fArg(int) { }  int main(int argc, char *argv[]) {    using namespace __xray; -  FDRLoggingOptions Options;    std::cout << "Logging before init." << std::endl;    // CHECK: Logging before init. -  auto status = __xray_log_init(kBufferSize, kBufferMax, &Options, -                                sizeof(FDRLoggingOptions)); +  assert(__xray_log_select_mode("xray-fdr") == +         XRayLogRegisterStatus::XRAY_REGISTRATION_OK); +  auto status = +      __xray_log_init_mode("xray-fdr", "buffer_size=16384:buffer_max=10");    assert(status == XRayLogInitStatus::XRAY_LOG_INITIALIZED);    std::cout << "Init status " << status << std::endl;    // CHECK: Init status {{.*}} @@ -72,32 +81,32 @@ int main(int argc, char *argv[]) {  }  // Check that we're able to see two threads, each entering and exiting fA(). -// TRACE-DAG: - { type: 0, func-id: [[FIDA:[0-9]+]], function: {{.*fA.*}}, cpu: {{.*}}, thread: [[THREAD1:[0-9]+]], kind: function-enter, tsc: {{[0-9]+}} } -// TRACE:     - { type: 0, func-id: [[FIDA]], function: {{.*fA.*}}, cpu: {{.*}}, thread: [[THREAD1]], kind: function-{{exit|tail-exit}}, tsc: {{[0-9]+}} } -// TRACE-DAG: - { type: 0, func-id: [[FIDA]], function: {{.*fA.*}}, cpu: {{.*}}, thread: [[THREAD2:[0-9]+]], kind: function-enter, tsc: {{[0-9]+}} } -// TRACE:     - { type: 0, func-id: [[FIDA]], function: {{.*fA.*}}, cpu: {{.*}}, thread: [[THREAD2]], kind: function-{{exit|tail-exit}}, tsc: {{[0-9]+}} } +// TRACE-DAG: - { type: 0, func-id: [[FIDA:[0-9]+]], function: {{.*fA.*}}, cpu: {{.*}}, thread: [[THREAD1:[0-9]+]], process: [[PROCESS:[0-9]+]], kind: function-enter, tsc: {{[0-9]+}} } +// TRACE:     - { type: 0, func-id: [[FIDA]], function: {{.*fA.*}}, cpu: {{.*}}, thread: [[THREAD1]], process: [[PROCESS]], kind: function-{{exit|tail-exit}}, tsc: {{[0-9]+}} } +// TRACE-DAG: - { type: 0, func-id: [[FIDA]], function: {{.*fA.*}}, cpu: {{.*}}, thread: [[THREAD2:[0-9]+]], process: [[PROCESS]], kind: function-enter, tsc: {{[0-9]+}} } +// TRACE:     - { type: 0, func-id: [[FIDA]], function: {{.*fA.*}}, cpu: {{.*}}, thread: [[THREAD2]], process: [[PROCESS]], kind: function-{{exit|tail-exit}}, tsc: {{[0-9]+}} }  //  // Do the same as above for fC() -// TRACE-DAG: - { type: 0, func-id: [[FIDC:[0-9]+]], function: {{.*fC.*}}, cpu: {{.*}}, thread: [[THREAD1:[0-9]+]], kind: function-enter, tsc: {{[0-9]+}} } -// TRACE:     - { type: 0, func-id: [[FIDC]], function: {{.*fC.*}}, cpu: {{.*}}, thread: [[THREAD1]], kind: function-{{exit|tail-exit}}, tsc: {{[0-9]+}} } -// TRACE-DAG: - { type: 0, func-id: [[FIDC]], function: {{.*fC.*}}, cpu: {{.*}}, thread: [[THREAD2:[0-9]+]], kind: function-enter, tsc: {{[0-9]+}} } -// TRACE:     - { type: 0, func-id: [[FIDC]], function: {{.*fC.*}}, cpu: {{.*}}, thread: [[THREAD2]], kind: function-{{exit|tail-exit}}, tsc: {{[0-9]+}} } +// TRACE-DAG: - { type: 0, func-id: [[FIDC:[0-9]+]], function: {{.*fC.*}}, cpu: {{.*}}, thread: [[THREAD1:[0-9]+]], process: [[PROCESS]], kind: function-enter, tsc: {{[0-9]+}} } +// TRACE:     - { type: 0, func-id: [[FIDC]], function: {{.*fC.*}}, cpu: {{.*}}, thread: [[THREAD1]], process: [[PROCESS]], kind: function-{{exit|tail-exit}}, tsc: {{[0-9]+}} } +// TRACE-DAG: - { type: 0, func-id: [[FIDC]], function: {{.*fC.*}}, cpu: {{.*}}, thread: [[THREAD2:[0-9]+]], process: [[PROCESS]], kind: function-enter, tsc: {{[0-9]+}} } +// TRACE:     - { type: 0, func-id: [[FIDC]], function: {{.*fC.*}}, cpu: {{.*}}, thread: [[THREAD2]], process: [[PROCESS]], kind: function-{{exit|tail-exit}}, tsc: {{[0-9]+}} }  // Do the same as above for fB() -// TRACE-DAG: - { type: 0, func-id: [[FIDB:[0-9]+]], function: {{.*fB.*}}, cpu: {{.*}}, thread: [[THREAD1:[0-9]+]], kind: function-enter, tsc: {{[0-9]+}} } -// TRACE:     - { type: 0, func-id: [[FIDB]], function: {{.*fB.*}}, cpu: {{.*}}, thread: [[THREAD1]], kind: function-{{exit|tail-exit}}, tsc: {{[0-9]+}} } -// TRACE-DAG: - { type: 0, func-id: [[FIDB]], function: {{.*fB.*}}, cpu: {{.*}}, thread: [[THREAD2:[0-9]+]], kind: function-enter, tsc: {{[0-9]+}} } -// TRACE:     - { type: 0, func-id: [[FIDB]], function: {{.*fB.*}}, cpu: {{.*}}, thread: [[THREAD2]], kind: function-{{exit|tail-exit}}, tsc: {{[0-9]+}} } +// TRACE-DAG: - { type: 0, func-id: [[FIDB:[0-9]+]], function: {{.*fB.*}}, cpu: {{.*}}, thread: [[THREAD1:[0-9]+]], process: [[PROCESS]], kind: function-enter, tsc: {{[0-9]+}} } +// TRACE:     - { type: 0, func-id: [[FIDB]], function: {{.*fB.*}}, cpu: {{.*}}, thread: [[THREAD1]], process: [[PROCESS]], kind: function-{{exit|tail-exit}}, tsc: {{[0-9]+}} } +// TRACE-DAG: - { type: 0, func-id: [[FIDB]], function: {{.*fB.*}}, cpu: {{.*}}, thread: [[THREAD2:[0-9]+]], process: [[PROCESS]], kind: function-enter, tsc: {{[0-9]+}} } +// TRACE:     - { type: 0, func-id: [[FIDB]], function: {{.*fB.*}}, cpu: {{.*}}, thread: [[THREAD2]], process: [[PROCESS]], kind: function-{{exit|tail-exit}}, tsc: {{[0-9]+}} } -// TRACE-DAG: - { type: 0, func-id: [[FIDARG:[0-9]+]], function: 'fArg(int)', args: [ 1 ], cpu: {{.*}}, thread: [[THREAD2]], kind: function-enter-arg, tsc: {{[0-9]+}} } -// TRACE-DAG: - { type: 0, func-id: [[FIDARG]], function: 'fArg(int)', cpu: {{.*}}, thread: [[THREAD2]], kind: function-exit, tsc: {{[0-9]+}} } +// TRACE-DAG: - { type: 0, func-id: [[FIDARG:[0-9]+]], function: 'fArg(int)', args: [ 1 ], cpu: {{.*}}, thread: [[THREAD2]], process: [[PROCESS]], kind: function-enter-arg, tsc: {{[0-9]+}} } +// TRACE-DAG: - { type: 0, func-id: [[FIDARG]], function: 'fArg(int)', cpu: {{.*}}, thread: [[THREAD2]], process: [[PROCESS]], kind: function-exit, tsc: {{[0-9]+}} }  // Assert that when unwriting is enabled with a high threshold time, all the function records are erased. A CPU switch could erroneously fail this test, but  // is unlikely given the test program.  // Even with a high threshold, arg1 logging is never unwritten.  // UNWRITE: header:  // UNWRITE: records: -// UNWRITE-NEXT: - { type: 0, func-id: [[FIDARG:[0-9]+]], function: 'fArg(int)', args: [ 1 ], cpu: {{.*}}, thread: [[THREAD2:[0-9]+]], kind: function-enter-arg, tsc: {{[0-9]+}} } -// UNWRITE-NEXT: - { type: 0, func-id: [[FIDARG]], function: 'fArg(int)', cpu: {{.*}}, thread: [[THREAD2]], kind: function-exit, tsc: {{[0-9]+}} } +// UNWRITE-NEXT: - { type: 0, func-id: [[FIDARG:[0-9]+]], function: 'fArg(int)', args: [ 1 ], cpu: {{.*}}, thread: [[THREAD2:[0-9]+]], process: [[PROCESS:[0-9]+]], kind: function-enter-arg, tsc: {{[0-9]+}} } +// UNWRITE-NEXT: - { type: 0, func-id: [[FIDARG]], function: 'fArg(int)', cpu: {{.*}}, thread: [[THREAD2]], process: [[PROCESS]], kind: function-exit, tsc: {{[0-9]+}} }  // UNWRITE-NOT: function-enter  // UNWRITE-NOT: function-{{exit|tail-exit}} diff --git a/test/xray/TestCases/Linux/fdr-single-thread.cc b/test/xray/TestCases/Posix/fdr-single-thread.cc index dd50f485f82bf..480502b0a60f3 100644 --- a/test/xray/TestCases/Linux/fdr-single-thread.cc +++ b/test/xray/TestCases/Posix/fdr-single-thread.cc @@ -1,5 +1,5 @@  // RUN: %clangxx_xray -g -std=c++11 %s -o %t -// RUN: rm fdr-logging-1thr-* || true +// RUN: rm -f fdr-logging-1thr-*  // RUN: XRAY_OPTIONS=XRAY_OPTIONS="verbosity=1 patch_premain=true \  // RUN:   xray_naive_log=false xray_fdr_log=true \  // RUN:   xray_fdr_log_func_duration_threshold_us=0 \ @@ -8,7 +8,7 @@  // RUN:   "`ls fdr-logging-1thr-* | head -n1`" | FileCheck %s  // RUN: rm fdr-logging-1thr-*  // -// REQUIRES: x86_64-linux +// REQUIRES: x86_64-target-arch  #include "xray/xray_log_interface.h"  #include <cassert> @@ -34,5 +34,5 @@ int main(int argc, char *argv[]) {  }  // CHECK: records: -// CHECK-NEXT: - { type: 0, func-id: [[FID1:[0-9]+]], function: {{.*fn.*}}, cpu: {{.*}}, thread: [[THREAD1:[0-9]+]], kind: function-enter, tsc: {{[0-9]+}} } -// CHECK-NEXT: - { type: 0, func-id: [[FID1:[0-9]+]], function: {{.*fn.*}}, cpu: {{.*}}, thread: [[THREAD1:[0-9]+]], kind: function-exit, tsc: {{[0-9]+}} } +// CHECK-NEXT: - { type: 0, func-id: [[FID1:[0-9]+]], function: {{.*fn.*}}, cpu: {{.*}}, thread: [[THREAD1:[0-9]+]], process: [[PROCESS:[0-9]+]], kind: function-enter, tsc: {{[0-9]+}} } +// CHECK-NEXT: - { type: 0, func-id: [[FID1:[0-9]+]], function: {{.*fn.*}}, cpu: {{.*}}, thread: [[THREAD1:[0-9]+]], process: [[PROCESS:[0-9]+]], kind: function-exit, tsc: {{[0-9]+}} } diff --git a/test/xray/TestCases/Linux/fdr-thread-order.cc b/test/xray/TestCases/Posix/fdr-thread-order.cc index 8e8c421dcc661..1d6b01759f14d 100644 --- a/test/xray/TestCases/Linux/fdr-thread-order.cc +++ b/test/xray/TestCases/Posix/fdr-thread-order.cc @@ -11,7 +11,7 @@  // RUN:    FileCheck %s --check-prefix TRACE  // RUN: rm fdr-thread-order.*  // FIXME: Make llvm-xray work on non-x86_64 as well. -// REQUIRES: x86_64-linux +// REQUIRES: x86_64-target-arch  // REQUIRES: built-in-llvm-tree  #include "xray/xray_log_interface.h" @@ -61,7 +61,7 @@ int main(int argc, char *argv[]) {  }  // We want to make sure that the order of the function log doesn't matter. -// TRACE-DAG: - { type: 0, func-id: [[FID1:[0-9]+]], function: {{.*f1.*}}, cpu: {{.*}}, thread: [[THREAD1:[0-9]+]], kind: function-enter, tsc: {{[0-9]+}} } -// TRACE-DAG: - { type: 0, func-id: [[FID2:[0-9]+]], function: {{.*f2.*}}, cpu: {{.*}}, thread: [[THREAD2:[0-9]+]], kind: function-enter, tsc: {{[0-9]+}} } -// TRACE-DAG: - { type: 0, func-id: [[FID1]], function: {{.*f1.*}}, cpu: {{.*}}, thread: [[THREAD1]], kind: {{function-exit|function-tail-exit}}, tsc: {{[0-9]+}} } -// TRACE-DAG: - { type: 0, func-id: [[FID2]], function: {{.*f2.*}}, cpu: {{.*}}, thread: [[THREAD2]], kind: {{function-exit|function-tail-exit}}, tsc: {{[0-9]+}} } +// TRACE-DAG: - { type: 0, func-id: [[FID1:[0-9]+]], function: {{.*f1.*}}, cpu: {{.*}}, thread: [[THREAD1:[0-9]+]], process: [[PROCESS:[0-9]+]], kind: function-enter, tsc: {{[0-9]+}} } +// TRACE-DAG: - { type: 0, func-id: [[FID2:[0-9]+]], function: {{.*f2.*}}, cpu: {{.*}}, thread: [[THREAD2:[0-9]+]], process: [[PROCESS]], kind: function-enter, tsc: {{[0-9]+}} } +// TRACE-DAG: - { type: 0, func-id: [[FID1]], function: {{.*f1.*}}, cpu: {{.*}}, thread: [[THREAD1]], process: [[PROCESS]], kind: {{function-exit|function-tail-exit}}, tsc: {{[0-9]+}} } +// TRACE-DAG: - { type: 0, func-id: [[FID2]], function: {{.*f2.*}}, cpu: {{.*}}, thread: [[THREAD2]], process: [[PROCESS]], kind: {{function-exit|function-tail-exit}}, tsc: {{[0-9]+}} } diff --git a/test/xray/TestCases/Linux/fixedsize-logging.cc b/test/xray/TestCases/Posix/fixedsize-logging.cc index a2a41ce60d6eb..a2a41ce60d6eb 100644 --- a/test/xray/TestCases/Linux/fixedsize-logging.cc +++ b/test/xray/TestCases/Posix/fixedsize-logging.cc diff --git a/test/xray/TestCases/Posix/fork_basic_logging.cc b/test/xray/TestCases/Posix/fork_basic_logging.cc new file mode 100644 index 0000000000000..5aefdec08016d --- /dev/null +++ b/test/xray/TestCases/Posix/fork_basic_logging.cc @@ -0,0 +1,100 @@ +// Check that when forking in basic logging mode, we get the different tids for child and parent +// RUN: %clangxx_xray -g -std=c++11 %s -o %t +// RUN: rm -f fork-basic-logging-test-* +// RUN: XRAY_OPTIONS="patch_premain=true xray_logfile_base=fork-basic-logging-test- \ +// RUN:     xray_mode=xray-basic verbosity=1 xray_naive_log_func_duration_threshold_us=0" \ +// RUN:     %run %t 2>&1 | FileCheck %s +// RUN: %llvm_xray convert --symbolize --output-format=yaml -instr_map=%t \ +// RUN:     "`ls -S fork-basic-logging-test-* | head -1`" \ +// RUN:     | FileCheck %s --check-prefix=TRACE + +// REQUIRES: x86_64-target-arch +// REQUIRES: built-in-llvm-tree + +#include "xray/xray_log_interface.h" +#include <stdio.h> +#include <unistd.h> +#include <stdint.h> +#include <sys/syscall.h> + +//modified from sanitizer + +static uintptr_t syscall_gettid() { +  uint64_t retval; +  asm volatile("syscall" : "=a"(retval) : "a"(__NR_gettid) : "rcx", "r11", +               "memory", "cc"); +  return retval; +} + +///////////// + +static uint64_t parent_tid; + +[[clang::xray_always_instrument]] +uint64_t __attribute__((noinline)) log_syscall_gettid() +{ +	//don't optimize this function away +	uint64_t tid = syscall_gettid(); +	printf("Logging tid %lu\n", tid); +	return tid; +} + +[[clang::xray_always_instrument, clang::xray_log_args(1)]] +void __attribute__((noinline)) print_parent_tid(uint64_t tid) +{ +	printf("Parent with tid %lu", tid); +} + +[[clang::xray_always_instrument, clang::xray_log_args(1)]] +void __attribute__((noinline)) print_child_tid(uint64_t tid) +{ +	printf("Child with tid %lu", tid); +} + +[[clang::xray_always_instrument]] void __attribute__((noinline)) print_parent_or_child() +{ +	uint64_t tid = syscall_gettid(); +	if(tid == parent_tid) +	{ +		print_parent_tid(tid); +	} +	else +	{ +		print_child_tid(tid); +	} +} + +int main() +{ +	parent_tid = log_syscall_gettid(); +	if(fork()) +	{ +		print_parent_or_child(); +  		// CHECK-DAG: Parent with tid +	} +	else +	{ +		print_parent_or_child(); +  		// CHECK-DAG: Child with tid +	} +	return 0; +} + +// Make sure we know which thread is the parent process +// TRACE-DAG: - { type: 0, func-id: [[LSGT:[0-9]+]], function: {{.*log_syscall_gettid.*}}, cpu: {{.*}}, thread: [[THREAD1:[0-9]+]], process: [[PROCESS1:[0-9]+]], kind: function-enter, tsc: {{[0-9]+}} } + +// TRACE-DAG: - { type: 0, func-id: [[PPOC:[0-9]+]], function: {{.*print_parent_or_child.*}}, cpu: {{.*}}, thread: [[THREAD1]], process: [[PROCESS1]], kind: function-enter, tsc: {{[0-9]+}} } +// +// The parent will print its pid +// TRACE-DAG: - { type: 0, func-id: [[PPTARG:[0-9]+]], function: {{.*print_parent_tid.*}}, args: [ [[THREAD1]] ], cpu: {{.*}}, thread: [[THREAD1]], process: [[PROCESS1]], kind: function-enter-arg, tsc: {{[0-9]+}} } +// TRACE-DAG: - { type: 0, func-id: [[PPTARG]], function: {{.*print_parent_tid.*}}, cpu: {{.*}}, thread: [[THREAD1]], process: [[PROCESS1]], kind: function-exit, tsc: {{[0-9]+}} } +// +// TRACE-DAG  - { type: 0, func-id: [[PPOC]], function: {{.*print_parent_or_child.*}}, cpu: {{.*}}, thread: [[THREAD1]], process: [[PROCESS1]], kind: function-{{exit|tail-exit}}, tsc: {{[0-9]+}} } + +// TRACE-DAG: - { type: 0, func-id: [[PPOC]], function: {{.*print_parent_or_child.*}}, cpu: {{.*}}, thread: [[THREAD2:[0-9]+]], process: [[PROCESS2:[0-9]+]], kind: function-enter, tsc: {{[0-9]+}} } +// +// The child will print its pid +// TRACE-DAG: - { type: 0, func-id: [[PCTARG:[0-9]+]], function: {{.*print_child_tid.*}}, args: [ [[THREAD2]] ], cpu: {{.*}}, thread: [[THREAD2]], process: [[PROCESS2]], kind: function-enter-arg, tsc: {{[0-9]+}} } +// TRACE-DAG: - { type: 0, func-id: [[PCTARG]], function: {{.*print_child_tid.*}}, cpu: {{.*}}, thread: [[THREAD2]], process: [[PROCESS2]], kind: function-exit, tsc: {{[0-9]+}} } +// +// TRACE-DAG: - { type: 0, func-id: [[PPOC]], function: {{.*print_parent_or_child.*}}, cpu: {{.*}}, thread: [[THREAD2]], process: [[PROCESS2]], kind: function-{{exit|tail-exit}}, tsc: {{[0-9]+}} } diff --git a/test/xray/TestCases/Linux/func-id-utils.cc b/test/xray/TestCases/Posix/func-id-utils.cc index 412753666019a..412753666019a 100644 --- a/test/xray/TestCases/Linux/func-id-utils.cc +++ b/test/xray/TestCases/Posix/func-id-utils.cc diff --git a/test/xray/TestCases/Linux/logging-modes.cc b/test/xray/TestCases/Posix/logging-modes.cc index 22f6942b75953..f839ba5e5f503 100644 --- a/test/xray/TestCases/Linux/logging-modes.cc +++ b/test/xray/TestCases/Posix/logging-modes.cc @@ -1,6 +1,7 @@  // Check that we can install an implementation associated with a mode.  // -// RUN: %clangxx_xray -std=c++11 %s -o %t +// RUN: rm -f xray-log.logging-modes* +// RUN: %clangxx_xray -std=c++11 %s -o %t -fxray-modes=none  // RUN: %run %t | FileCheck %s  //  // UNSUPPORTED: target-is-mips64,target-is-mips64el @@ -9,6 +10,7 @@  #include "xray/xray_log_interface.h"  #include <cassert>  #include <cstdio> +#include <string>  [[clang::xray_never_instrument]] void printing_handler(int32_t fid,                                                         XRayEntryType) { @@ -20,8 +22,29 @@    printing = false;  } +[[clang::xray_never_instrument]] XRayBuffer next_buffer(XRayBuffer buffer) { +  static const char data[10] = {}; +  static const XRayBuffer first_and_last{data, 10}; +  if (buffer.Data == nullptr) +    return first_and_last; +  if (buffer.Data == first_and_last.Data) +    return XRayBuffer{nullptr, 0}; +  assert(false && "Invalid buffer provided."); +} + +static constexpr char Options[] = "additional_flags"; +  [[clang::xray_never_instrument]] XRayLogInitStatus -printing_init(size_t, size_t, void *, size_t) { +printing_init(size_t BufferSize, size_t MaxBuffers, void *Config, +              size_t ArgsSize) { +  // We require that the printing init is called through the +  // __xray_log_init_mode(...) implementation, and that the promised contract is +  // enforced. +  assert(BufferSize == 0); +  assert(MaxBuffers == 0); +  assert(Config != nullptr); +  assert(ArgsSize == 0 || ArgsSize == sizeof(Options)); +  __xray_log_set_buffer_iterator(next_buffer);    return XRayLogInitStatus::XRAY_LOG_INITIALIZED;  } @@ -30,29 +53,42 @@ printing_init(size_t, size_t, void *, size_t) {  }  [[clang::xray_never_instrument]] XRayLogFlushStatus printing_flush_log() { +  __xray_log_remove_buffer_iterator();    return XRayLogFlushStatus::XRAY_LOG_FLUSHED;  }  [[clang::xray_always_instrument]] void callme() { std::printf("called me!\n"); } -static bool unused = [] { +static auto buffer_counter = 0; + +void process_buffer(const char *, XRayBuffer) { ++buffer_counter; } + +int main(int argc, char **argv) {    assert(__xray_log_register_mode("custom",                                    {printing_init, printing_finalize,                                     printing_handler, printing_flush_log}) ==           XRayLogRegisterStatus::XRAY_REGISTRATION_OK); -  return true; -}(); - -int main(int argc, char **argv) {    assert(__xray_log_select_mode("custom") ==           XRayLogRegisterStatus::XRAY_REGISTRATION_OK); +  assert(__xray_log_get_current_mode() != nullptr); +  std::string current_mode = __xray_log_get_current_mode(); +  assert(current_mode == "custom");    assert(__xray_patch() == XRayPatchingStatus::SUCCESS); -  assert(__xray_log_init(0, 0, nullptr, 0) == +  assert(__xray_log_init_mode("custom", "flags_config_here=true") ==           XRayLogInitStatus::XRAY_LOG_INITIALIZED); + +  // Also test that we can use the "binary" version of the +  // __xray_log_niit_mode(...) API. +  assert(__xray_log_init_mode_bin("custom", Options, sizeof(Options)) == +         XRayLogInitStatus::XRAY_LOG_INITIALIZED); +    // CHECK: printing {{.*}}    callme(); // CHECK: called me!    // CHECK: printing {{.*}}    assert(__xray_log_finalize() == XRayLogInitStatus::XRAY_LOG_FINALIZED); +  assert(__xray_log_process_buffers(process_buffer) == +         XRayLogFlushStatus::XRAY_LOG_FLUSHED); +  assert(buffer_counter == 1);    assert(__xray_log_flushLog() == XRayLogFlushStatus::XRAY_LOG_FLUSHED);    assert(__xray_log_select_mode("not-found") ==           XRayLogRegisterStatus::XRAY_MODE_NOT_FOUND); diff --git a/test/xray/TestCases/Linux/optional-inmemory-log.cc b/test/xray/TestCases/Posix/optional-inmemory-log.cc index feaaa41247500..feaaa41247500 100644 --- a/test/xray/TestCases/Linux/optional-inmemory-log.cc +++ b/test/xray/TestCases/Posix/optional-inmemory-log.cc diff --git a/test/xray/TestCases/Linux/patching-unpatching.cc b/test/xray/TestCases/Posix/patching-unpatching.cc index a7ea58f6dc69f..a7ea58f6dc69f 100644 --- a/test/xray/TestCases/Linux/patching-unpatching.cc +++ b/test/xray/TestCases/Posix/patching-unpatching.cc diff --git a/test/xray/TestCases/Linux/pic_test.cc b/test/xray/TestCases/Posix/pic_test.cc index 4de1ad3d6da9f..93e1a6a47d3c2 100644 --- a/test/xray/TestCases/Linux/pic_test.cc +++ b/test/xray/TestCases/Posix/pic_test.cc @@ -2,12 +2,12 @@  // RUN: %clangxx_xray -fxray-instrument -std=c++11 -ffunction-sections \  // RUN:     -fdata-sections -fpic -fpie -Wl,--gc-sections %s -o %t -// RUN: rm pic-test-logging-* || true +// RUN: rm -f pic-test-logging-*  // RUN: XRAY_OPTIONS="patch_premain=true verbosity=1 xray_naive_log=true \  // RUN:     xray_logfile_base=pic-test-logging-" %run %t 2>&1 | FileCheck %s  // After all that, clean up the output xray log.  // -// RUN: rm pic-test-logging-* || true +// RUN: rm -f pic-test-logging-*  // UNSUPPORTED: target-is-mips64,target-is-mips64el diff --git a/test/xray/TestCases/Posix/profiling-multi-threaded.cc b/test/xray/TestCases/Posix/profiling-multi-threaded.cc new file mode 100644 index 0000000000000..7ccad1bac1fd9 --- /dev/null +++ b/test/xray/TestCases/Posix/profiling-multi-threaded.cc @@ -0,0 +1,57 @@ +// Check that we can get a profile from a single-threaded application, on +// demand through the XRay logging implementation API. +// +// FIXME: Make -fxray-modes=xray-profiling part of the default? +// RUN: %clangxx_xray -std=c++11 %s -o %t -fxray-modes=xray-profiling +// RUN: rm -f xray-log.profiling-multi-* +// RUN: XRAY_OPTIONS=verbosity=1 \ +// RUN:     XRAY_PROFILING_OPTIONS=no_flush=1 %run %t +// RUN: XRAY_OPTIONS=verbosity=1 %run %t +// RUN: PROFILES=`ls xray-log.profiling-multi-* | wc -l` +// RUN: [ $PROFILES -eq 1 ] +// RUN: rm -f xray-log.profiling-multi-* +// +// REQUIRES: x86_64-target-arch +// REQUIRES: built-in-llvm-tree + +#include "xray/xray_interface.h" +#include "xray/xray_log_interface.h" +#include <cassert> +#include <cstdio> +#include <string> +#include <thread> + +[[clang::xray_always_instrument]] void f2() { return; } +[[clang::xray_always_instrument]] void f1() { f2(); } +[[clang::xray_always_instrument]] void f0() { f1(); } + +using namespace std; + +volatile int buffer_counter = 0; + +[[clang::xray_never_instrument]] void process_buffer(const char *, XRayBuffer) { +  // FIXME: Actually assert the contents of the buffer. +  ++buffer_counter; +} + +[[clang::xray_always_instrument]] int main(int, char **) { +  assert(__xray_log_select_mode("xray-profiling") == +         XRayLogRegisterStatus::XRAY_REGISTRATION_OK); +  assert(__xray_log_get_current_mode() != nullptr); +  std::string current_mode = __xray_log_get_current_mode(); +  assert(current_mode == "xray-profiling"); +  assert(__xray_patch() == XRayPatchingStatus::SUCCESS); +  assert(__xray_log_init(0, 0, nullptr, 0) == +         XRayLogInitStatus::XRAY_LOG_INITIALIZED); +  std::thread t0([] { f0(); }); +  std::thread t1([] { f0(); }); +  f0(); +  t0.join(); +  t1.join(); +  assert(__xray_log_finalize() == XRayLogInitStatus::XRAY_LOG_FINALIZED); +  assert(__xray_log_process_buffers(process_buffer) == +         XRayLogFlushStatus::XRAY_LOG_FLUSHED); +  // We're running three threds, so we expect three buffers. +  assert(buffer_counter == 3); +  assert(__xray_log_flushLog() == XRayLogFlushStatus::XRAY_LOG_FLUSHED); +} diff --git a/test/xray/TestCases/Posix/profiling-single-threaded.cc b/test/xray/TestCases/Posix/profiling-single-threaded.cc new file mode 100644 index 0000000000000..fd508b1acd147 --- /dev/null +++ b/test/xray/TestCases/Posix/profiling-single-threaded.cc @@ -0,0 +1,65 @@ +// Check that we can get a profile from a single-threaded application, on +// demand through the XRay logging implementation API. +// +// FIXME: Make -fxray-modes=xray-profiling part of the default? +// RUN: %clangxx_xray -std=c++11 %s -o %t -fxray-modes=xray-profiling +// RUN: rm -f xray-log.profiling-single-* +// RUN: XRAY_OPTIONS=verbosity=1 \ +// RUN:     XRAY_PROFILING_OPTIONS=no_flush=true %run %t +// RUN: XRAY_OPTIONS=verbosity=1 %run %t +// RUN: PROFILES=`ls xray-log.profiling-single-* | wc -l` +// RUN: [ $PROFILES -eq 2 ] +// RUN: rm -f xray-log.profiling-single-* +// +// REQUIRES: x86_64-target-arch +// REQUIRES: built-in-llvm-tree + +#include "xray/xray_interface.h" +#include "xray/xray_log_interface.h" +#include <cassert> +#include <cstdio> +#include <string> + +[[clang::xray_always_instrument]] void f2() { return; } +[[clang::xray_always_instrument]] void f1() { f2(); } +[[clang::xray_always_instrument]] void f0() { f1(); } + +using namespace std; + +volatile int buffer_counter = 0; + +[[clang::xray_never_instrument]] void process_buffer(const char *, XRayBuffer) { +  // FIXME: Actually assert the contents of the buffer. +  ++buffer_counter; +} + +[[clang::xray_always_instrument]] int main(int, char **) { +  assert(__xray_log_select_mode("xray-profiling") == +         XRayLogRegisterStatus::XRAY_REGISTRATION_OK); +  assert(__xray_log_get_current_mode() != nullptr); +  std::string current_mode = __xray_log_get_current_mode(); +  assert(current_mode == "xray-profiling"); +  assert(__xray_patch() == XRayPatchingStatus::SUCCESS); +  assert(__xray_log_init_mode("xray-profiling", "") == +         XRayLogInitStatus::XRAY_LOG_INITIALIZED); +  f0(); +  assert(__xray_log_finalize() == XRayLogInitStatus::XRAY_LOG_FINALIZED); +  f0(); +  assert(__xray_log_process_buffers(process_buffer) == +         XRayLogFlushStatus::XRAY_LOG_FLUSHED); +  assert(buffer_counter == 1); +  assert(__xray_log_flushLog() == XRayLogFlushStatus::XRAY_LOG_FLUSHED); + +  // Let's reset the counter. +  buffer_counter = 0; + +  assert(__xray_log_init_mode("xray-profiling", "") == +         XRayLogInitStatus::XRAY_LOG_INITIALIZED); +  f0(); +  assert(__xray_log_finalize() == XRayLogInitStatus::XRAY_LOG_FINALIZED); +  f0(); +  assert(__xray_log_process_buffers(process_buffer) == +         XRayLogFlushStatus::XRAY_LOG_FLUSHED); +  assert(buffer_counter == 1); +  assert(__xray_log_flushLog() == XRayLogFlushStatus::XRAY_LOG_FLUSHED); +} diff --git a/test/xray/TestCases/Linux/quiet-start.cc b/test/xray/TestCases/Posix/quiet-start.cc index e26fa63aa5baa..00d5af6609ddd 100644 --- a/test/xray/TestCases/Linux/quiet-start.cc +++ b/test/xray/TestCases/Posix/quiet-start.cc @@ -10,7 +10,7 @@  //  // FIXME: Understand how to make this work on other platforms  // REQUIRES: built-in-llvm-tree -// REQUIRES: x86_64-linux +// REQUIRES: x86_64-target-arch  #include <iostream>  using namespace std; diff --git a/test/xray/lit.cfg b/test/xray/lit.cfg index d5e40975da569..0dc2108ba1870 100644 --- a/test/xray/lit.cfg +++ b/test/xray/lit.cfg @@ -20,6 +20,11 @@ def build_invocation(compile_flags):  llvm_xray = os.path.join(config.llvm_tools_dir, 'llvm-xray')  # Setup substitutions. +if config.host_os == "Linux": +  libdl_flag = "-ldl" +else: +  libdl_flag = "" +  config.substitutions.append(      ('%clang ', build_invocation([config.target_cflags])))  config.substitutions.append( @@ -33,14 +38,14 @@ config.substitutions.append(      ('%llvm_xray', llvm_xray))  config.substitutions.append(      ('%xraylib', -        ('-lm -lpthread -ldl -lrt -L%s ' -         '-Wl,-whole-archive -lclang_rt.xray-%s -Wl,-no-whole-archive') -        % (config.compiler_rt_libdir, config.host_arch))) +        ('-lm -lpthread %s -lrt -L%s ' +         '-Wl,-whole-archive -lclang_rt.xray%s -Wl,-no-whole-archive') +        % (libdl_flag, config.compiler_rt_libdir, config.target_suffix)))  # Default test suffixes.  config.suffixes = ['.c', '.cc', '.cpp'] -if config.host_os not in ['Linux']: +if config.host_os not in ['FreeBSD', 'Linux', 'NetBSD', 'OpenBSD']:    config.unsupported = True  elif '64' not in config.host_arch:    if 'arm' in config.host_arch: diff --git a/utils/generate_netbsd_ioctls.awk b/utils/generate_netbsd_ioctls.awk new file mode 100755 index 0000000000000..9a92ff82a6866 --- /dev/null +++ b/utils/generate_netbsd_ioctls.awk @@ -0,0 +1,759 @@ +#!/usr/bin/awk -f + +#===-- generate_netbsd_ioctls.awk ------------------------------------------===# +# +#                     The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +#===------------------------------------------------------------------------===# +# +# This file is a generator of: +#  - include/sanitizer/sanitizer_interceptors_ioctl_netbsd.inc +# +# This script reads public headers from a NetBSD host. +# +#===------------------------------------------------------------------------===# + +BEGIN { +  # harcode the script name +  script_name = "generate_netbsd_ioctls.awk" +  outputinc = "../lib/sanitizer_common/sanitizer_interceptors_ioctl_netbsd.inc" + +  # assert that we are in the directory with scripts +  in_utils = system("test -f " script_name " && exit 1 || exit 0") +  if (in_utils == 0) { +    usage() +  } + +  # assert 0 argument passed +  if (ARGC != 1) { +    usage() +  } + +  # accept overloading CLANGFORMAT from environment +  clangformat = "clang-format" +  if ("CLANGFORMAT" in ENVIRON) { +    clangformat = ENVIRON["CLANGFORMAT"] +  } + +  # accept overloading ROOTDIR from environment +  rootdir = "/usr/include/" +  if ("ROOTDIR" in ENVIRON) { +    rootdir = ENVIRON["ROOTDIR"] +  } + +  # hardcode list of headers with ioctl(2) entries +  # List generated manually with the following script: +  #   for w in `find /usr/include/ -type f -name '*.h' -exec echo {} \;`; \ +  #   do awk '/[^a-zA-Z0-9_]_IO[W]*[R]*[ ]*\(/ && $2 ~ /^[A-Z_]+$/ {got=1} END{if(got) {print ARGV[1]}}' $w; \ +  #   done|awk '{print "  ARGV[ARGC++] = rootdir \"" substr($0, 14) "\""}' + +  ARGV[ARGC++] = rootdir "altq/altq_afmap.h" +  ARGV[ARGC++] = rootdir "altq/altq.h" +  ARGV[ARGC++] = rootdir "altq/altq_blue.h" +  ARGV[ARGC++] = rootdir "altq/altq_cbq.h" +  ARGV[ARGC++] = rootdir "altq/altq_cdnr.h" +  ARGV[ARGC++] = rootdir "altq/altq_fifoq.h" +  ARGV[ARGC++] = rootdir "altq/altq_hfsc.h" +  ARGV[ARGC++] = rootdir "altq/altq_jobs.h" +  ARGV[ARGC++] = rootdir "altq/altq_priq.h" +  ARGV[ARGC++] = rootdir "altq/altq_red.h" +  ARGV[ARGC++] = rootdir "altq/altq_rio.h" +  ARGV[ARGC++] = rootdir "altq/altq_wfq.h" +  ARGV[ARGC++] = rootdir "crypto/cryptodev.h" +  ARGV[ARGC++] = rootdir "dev/apm/apmio.h" +  ARGV[ARGC++] = rootdir "dev/dm/netbsd-dm.h" +  ARGV[ARGC++] = rootdir "dev/dmover/dmover_io.h" +  ARGV[ARGC++] = rootdir "dev/dtv/dtvio_demux.h" +  ARGV[ARGC++] = rootdir "dev/dtv/dtvio_frontend.h" +  ARGV[ARGC++] = rootdir "dev/filemon/filemon.h" +  ARGV[ARGC++] = rootdir "dev/hdaudio/hdaudioio.h" +  ARGV[ARGC++] = rootdir "dev/hdmicec/hdmicecio.h" +  ARGV[ARGC++] = rootdir "dev/hpc/hpcfbio.h" +  ARGV[ARGC++] = rootdir "dev/i2o/iopio.h" +  ARGV[ARGC++] = rootdir "dev/ic/athioctl.h" +  ARGV[ARGC++] = rootdir "dev/ic/bt8xx.h" +  ARGV[ARGC++] = rootdir "dev/ic/hd44780var.h" +  ARGV[ARGC++] = rootdir "dev/ic/icp_ioctl.h" +  ARGV[ARGC++] = rootdir "dev/ic/isp_ioctl.h" +  ARGV[ARGC++] = rootdir "dev/ic/mlxio.h" +  ARGV[ARGC++] = rootdir "dev/ic/nvmeio.h" +  ARGV[ARGC++] = rootdir "dev/ir/irdaio.h" +  ARGV[ARGC++] = rootdir "dev/isa/satlinkio.h" +  ARGV[ARGC++] = rootdir "dev/isa/isvio.h" +  ARGV[ARGC++] = rootdir "dev/isa/wtreg.h" +  ARGV[ARGC++] = rootdir "dev/iscsi/iscsi_ioctl.h" +  ARGV[ARGC++] = rootdir "dev/ofw/openfirmio.h" +  ARGV[ARGC++] = rootdir "dev/pci/amrio.h" +  ARGV[ARGC++] = rootdir "dev/pci/mlyio.h" +  ARGV[ARGC++] = rootdir "dev/pci/pciio.h" +  ARGV[ARGC++] = rootdir "dev/pci/tweio.h" +  ARGV[ARGC++] = rootdir "dev/pcmcia/if_cnwioctl.h" +  ARGV[ARGC++] = rootdir "dev/pcmcia/if_rayreg.h" +  ARGV[ARGC++] = rootdir "dev/raidframe/raidframeio.h" +  ARGV[ARGC++] = rootdir "dev/sbus/mbppio.h" +  ARGV[ARGC++] = rootdir "dev/scsipi/ses.h" +  ARGV[ARGC++] = rootdir "dev/sun/disklabel.h" +  ARGV[ARGC++] = rootdir "dev/sun/fbio.h" +  ARGV[ARGC++] = rootdir "dev/sun/kbio.h" +  ARGV[ARGC++] = rootdir "dev/sun/vuid_event.h" +  ARGV[ARGC++] = rootdir "dev/tc/sticio.h" +  ARGV[ARGC++] = rootdir "dev/usb/ukyopon.h" +  ARGV[ARGC++] = rootdir "dev/usb/urio.h" +  ARGV[ARGC++] = rootdir "dev/usb/usb.h" +  ARGV[ARGC++] = rootdir "dev/usb/utoppy.h" +  ARGV[ARGC++] = rootdir "dev/vme/xio.h" +  ARGV[ARGC++] = rootdir "dev/wscons/wsdisplay_usl_io.h" +  ARGV[ARGC++] = rootdir "dev/wscons/wsconsio.h" +  ARGV[ARGC++] = rootdir "dev/biovar.h" +  ARGV[ARGC++] = rootdir "dev/md.h" +  ARGV[ARGC++] = rootdir "dev/ccdvar.h" +  ARGV[ARGC++] = rootdir "dev/cgdvar.h" +  ARGV[ARGC++] = rootdir "dev/fssvar.h" +  ARGV[ARGC++] = rootdir "dev/bluetooth/btdev.h" +  ARGV[ARGC++] = rootdir "dev/bluetooth/btsco.h" +  ARGV[ARGC++] = rootdir "dev/kttcpio.h" +  ARGV[ARGC++] = rootdir "dev/lockstat.h" +  ARGV[ARGC++] = rootdir "dev/vndvar.h" +  ARGV[ARGC++] = rootdir "dev/spkrio.h" +  ARGV[ARGC++] = rootdir "net/bpf.h" +  ARGV[ARGC++] = rootdir "net/if_atm.h" +  ARGV[ARGC++] = rootdir "net/if_gre.h" +  ARGV[ARGC++] = rootdir "net/if_ppp.h" +  ARGV[ARGC++] = rootdir "net/npf.h" +  ARGV[ARGC++] = rootdir "net/if_pppoe.h" +  ARGV[ARGC++] = rootdir "net/if_sppp.h" +  ARGV[ARGC++] = rootdir "net/if_srt.h" +  ARGV[ARGC++] = rootdir "net/if_tap.h" +  ARGV[ARGC++] = rootdir "net/if_tun.h" +  ARGV[ARGC++] = rootdir "net/pfvar.h" +  ARGV[ARGC++] = rootdir "net/slip.h" +  ARGV[ARGC++] = rootdir "netbt/hci.h" +  ARGV[ARGC++] = rootdir "netinet/ip_nat.h" +  ARGV[ARGC++] = rootdir "netinet/ip_proxy.h" +  ARGV[ARGC++] = rootdir "netinet6/in6_var.h" +  ARGV[ARGC++] = rootdir "netnatm/natm.h" +  ARGV[ARGC++] = rootdir "netsmb/smb_dev.h" +  ARGV[ARGC++] = rootdir "sys/agpio.h" +  ARGV[ARGC++] = rootdir "sys/audioio.h" +  ARGV[ARGC++] = rootdir "sys/ataio.h" +  ARGV[ARGC++] = rootdir "sys/cdio.h" +  ARGV[ARGC++] = rootdir "sys/chio.h" +  ARGV[ARGC++] = rootdir "sys/clockctl.h" +  ARGV[ARGC++] = rootdir "sys/cpuio.h" +  ARGV[ARGC++] = rootdir "sys/dkio.h" +  ARGV[ARGC++] = rootdir "sys/drvctlio.h" +  ARGV[ARGC++] = rootdir "sys/dvdio.h" +  ARGV[ARGC++] = rootdir "sys/envsys.h" +  ARGV[ARGC++] = rootdir "sys/event.h" +  ARGV[ARGC++] = rootdir "sys/fdio.h" +  ARGV[ARGC++] = rootdir "sys/filio.h" +  ARGV[ARGC++] = rootdir "sys/gpio.h" +  ARGV[ARGC++] = rootdir "sys/ioctl.h" +  ARGV[ARGC++] = rootdir "sys/ioctl_compat.h" +  ARGV[ARGC++] = rootdir "sys/joystick.h" +  ARGV[ARGC++] = rootdir "sys/ksyms.h" +  ARGV[ARGC++] = rootdir "sys/lua.h" +  ARGV[ARGC++] = rootdir "sys/midiio.h" +  ARGV[ARGC++] = rootdir "sys/mtio.h" +  ARGV[ARGC++] = rootdir "sys/power.h" +  ARGV[ARGC++] = rootdir "sys/radioio.h" +  ARGV[ARGC++] = rootdir "sys/rndio.h" +  ARGV[ARGC++] = rootdir "sys/scanio.h" +  ARGV[ARGC++] = rootdir "sys/scsiio.h" +  ARGV[ARGC++] = rootdir "sys/sockio.h" +  ARGV[ARGC++] = rootdir "sys/timepps.h" +  ARGV[ARGC++] = rootdir "sys/ttycom.h" +  ARGV[ARGC++] = rootdir "sys/verified_exec.h" +  ARGV[ARGC++] = rootdir "sys/videoio.h" +  ARGV[ARGC++] = rootdir "sys/wdog.h" +  ARGV[ARGC++] = rootdir "soundcard.h" +  ARGV[ARGC++] = rootdir "xen/xenio.h" + +  ioctl_table_max = 0 +} + +# Scan RCS ID +FNR == 1 { +  fname[ioctl_table_max] = substr(FILENAME, length(rootdir) + 1) +} + +# _IO +/[^a-zA-Z0-9_]_IO[W]*[R]*[ ]*\(/ && $2 ~ /^[A-Z_]+$/ { +  if ($0 ~ /RAIDFRAME_GET_ACCTOTALS/ || +      $0 ~ /ALTQATTACH/ || +      $0 ~ /ALTQDETACH/ || +      $0 ~ /ALTQENABLE/ || +      $0 ~ /ALTQDISABLE/ || +      $0 ~ /ALTQCLEAR/ || +      $0 ~ /ALTQCONFIG/ || +      $0 ~ /ALTQADDCLASS/ || +      $0 ~ /ALTQMODCLASS/ || +      $0 ~ /ALTQDELCLASS/ || +      $0 ~ /ALTQADDFILTER/ || +      $0 ~ /ALTQDELFILTER/ || +      $0 ~ /ALTQGETSTATS/ || +      $0 ~ /ALTQGETCNTR/ || +      $0 ~ /HFSC_IF_ATTACH/ || +      $0 ~ /HFSC_MOD_CLASS/ || +      $0 ~ /HLCD_DISPCTL/ || +      $0 ~ /HLCD_RESET/ || +      $0 ~ /HLCD_CLEAR/ || +      $0 ~ /HLCD_CURSOR_LEFT/ || +      $0 ~ /HLCD_CURSOR_RIGHT/ || +      $0 ~ /HLCD_GET_CURSOR_POS/ || +      $0 ~ /HLCD_SET_CURSOR_POS/ || +      $0 ~ /HLCD_GETC/ || +      $0 ~ /HLCD_PUTC/ || +      $0 ~ /HLCD_SHIFT_LEFT/ || +      $0 ~ /HLCD_SHIFT_RIGHT/ || +      $0 ~ /HLCD_HOME/ || +      $0 ~ /HLCD_WRITE/ || +      $0 ~ /HLCD_READ/ || +      $0 ~ /HLCD_REDRAW/ || +      $0 ~ /HLCD_WRITE_INST/ || +      $0 ~ /HLCD_WRITE_DATA/ || +      $0 ~ /HLCD_GET_INFO/ || +      $0 ~ /HLCD_GET_CHIPNO/ || +      $0 ~ /HLCD_SET_CHIPNO/ || +      $0 ~ /RAIDFRAME_TEST_ACC/ || +      $0 ~ /FBIOGINFO/ || +      $0 ~ /FBIOSATTR/ || +      $0 ~ /OBIOCDISK/ || +      $0 ~ /OBIOCVOL/ || +      $0 ~ /BIOCSORTIMEOUT/ || +      $0 ~ /BIOCGORTIMEOUT/ || +      $0 ~ /PPPIOCSPASS/ || +      $0 ~ /PPPIOCSACTIVE/ || +      $0 ~ /PPPIOCSIPASS/ || +      $0 ~ /PPPIOCSOPASS/ || +      $0 ~ /PPPIOCSIACTIVE/ || +      $0 ~ /PPPIOCSOACTIVE/ || +      $0 ~ /SIOCPROXY/ || +      $0 ~ /SIOCXRAWATM/ || +      $0 ~ /AGPIOC_RESERVE/ || +      $0 ~ /AGPIOC_PROTECT/ || +      $0 ~ /CDIOCREADSUBCHANNEL_BUF/ || +      $0 ~ /CDIOREADTOCENTRIES_BUF/ || +      $0 ~ /MMCGETDISCINFO/ || +      $0 ~ /MMCGETTRACKINFO/ || +      $0 ~ /MMCOP/ || +      $0 ~ /MMCSETUPWRITEPARAMS/ || +      $0 ~ /DIOCGPARTINFO/ || +      $0 ~ /ODIOCGDINFO/ || +      $0 ~ /ODIOCSDINFO/ || +      $0 ~ /ODIOCWDINFO/ || +      $0 ~ /ODIOCGDEFLABEL/ || +      $0 ~ /GPIOPINREAD/ || +      $0 ~ /GPIOPINWRITE/ || +      $0 ~ /GPIOPINTOGGLE/ || +      $0 ~ /GPIOPINCTL/ || +      $0 ~ /GPIODETACH/ || +      $0 ~ /SEQUENCER_PERCMODE/ || +      $0 ~ /SEQUENCER_TESTMIDI/ || +      $0 ~ /SEQUENCER_MIDI_INFO/ || +      $0 ~ /SEQUENCER_ID/ || +      $0 ~ /SEQUENCER_CONTROL/ || +      $0 ~ /SEQUENCER_REMOVESAMPLE/ || +      $0 ~ /EVTCHN_RESET/ || +      $0 ~ /EVTCHN_BIND/ || +      $0 ~ /EVTCHN_UNBIND/) { +    # broken entry, incomplete definition of the 3rd parameterm etc +    next +  } + +  if ($0 ~ /APM_IOC_STANDBY/ || +      $0 ~ /APM_IOC_SUSPEND/ || +      $0 ~ /SCIOC_USE_ADF/ || +      $0 ~ /SCBUSIOLLSCAN/ || +      $0 ~ /UTOPPYIOCANCEL/ || +      $0 ~ /JOY_GET_X_OFFSET/ || +      $0 ~ /CHIOGPICKER/ || +      $0 ~ /SLIOCGUNIT/ || +      $0 ~ /SATIOSBUFSIZE/ || +      $0 ~ /TUNSLMODE/ || +      $0 ~ /CBQ_IF_ATTACH/ || +      $0 ~ /CDNR_IF_ATTACH/ || +      $0 ~ /RIO_IF_ATTACH/ || +      $0 ~ /CBQ_IF_DETACH/ || +      $0 ~ /HFSC_IF_DETACH/ || +      $0 ~ /WFQ_IF_DETACH/ || +      $0 ~ /RIO_IF_DETACH/ || +      $0 ~ /FIFOQ_IF_DETACH/ || +      $0 ~ /RED_IF_DETACH/ || +      $0 ~ /CDNR_ENABLE/ || +      $0 ~ /HFSC_ENABLE/ || +      $0 ~ /WFQ_ENABLE/ || +      $0 ~ /RIO_ENABLE/ || +      $0 ~ /FIFOQ_ENABLE/ || +      $0 ~ /RED_ENABLE/ || +      $0 ~ /BLUE_ENABLE/ || +      $0 ~ /CDNR_DISABLE/ || +      $0 ~ /HFSC_DISABLE/ || +      $0 ~ /WFQ_DISABLE/ || +      $0 ~ /RIO_DISABLE/ || +      $0 ~ /FIFOQ_DISABLE/ || +      $0 ~ /PRIQ_DISABLE/ || +      $0 ~ /CDNR_DEL_FILTER/ || +      $0 ~ /JOBS_DEL_CLASS/ || +      $0 ~ /JOBS_DEL_FILTER/ || +      $0 ~ /JOBS_GETSTATS/ || +      $0 ~ /WFQ_GET_STATS/ || +      $0 ~ /CBQ_ADD_FILTER/ || +      $0 ~ /HFSC_ADD_FILTER/ || +      $0 ~ /JOBS_ADD_FILTER/ || +      $0 ~ /RED_IF_ATTACH/ || +      $0 ~ /FIFOQ_IF_ATTACH/ || +      $0 ~ /BLUE_IF_DETACH/ || +      $0 ~ /CBQ_DISABLE/ || +      $0 ~ /RED_DISABLE/ || +      $0 ~ /CBQ_CLEAR_HIERARCHY/ || +      $0 ~ /HFSC_DEL_CLASS/ || +      $0 ~ /PRIQ_IF_DETACH/ || +      $0 ~ /PRIQ_ENABLE/ || +      $0 ~ /WFQ_IF_ATTACH/ || +      $0 ~ /HFSC_DEL_FILTER/) { +    # There are entries with duplicate codes.. disable the less used ones +    next +  } + +  if ($2 in known) { +    # Avoid duplicates +    # There are entries compatible with K&R and ANSI preprocessor +    next +  } + +  known[$2] = 1 + +  ioctl_name[ioctl_table_max] = $2 + +  split($3, a, "(") +  a3 = a[1] +  if (a3 ~ /_IO[ ]*$/) { +    ioctl_mode[ioctl_table_max] = "NONE" +  } else if (a3 ~ /_IOR[ ]*$/) { +    ioctl_mode[ioctl_table_max] = "WRITE" +  } else if (a3 ~ /_IOW[ ]*$/) { +    ioctl_mode[ioctl_table_max] = "READ" +  } else if (a3 ~ /_IOWR[ ]*$/) { +    ioctl_mode[ioctl_table_max] = "READWRITE" +  } else { +    print "Unknown mode, cannot parse: '" $3 "'" +  } + +  # This !NONE check allows to skip some unparsable entries +  if (ioctl_mode[ioctl_table_max] != "NONE") { +    # special cases first +    if ($0 ~ /POWER_IOC_GET_TYPE_WITH_LOSSAGE/) { +      ioctl_type[ioctl_table_max] = "sizeof(uptr)" +    } else { +      n = split($0, a, ",") +      if (n == 3) { +        gsub(/^[ ]+/, "", a[3]) +        match(a[3], /[a-zA-Z0-9_* ]+/) +        type = get_type(substr(a[3], 0, RLENGTH)) +        ioctl_type[ioctl_table_max] = type +      } +    } +  } + +  ioctl_table_max++ +} + +END { +  # empty files? +  if (NR < 1 && !abnormal_exit) { +    usage() +  } + +  # Handle abnormal exit +  if (abnormal_exit) { +    exit(abnormal_exit) +  } + +  # Generate sanitizer_interceptors_ioctl_netbsd.inc + +  # open pipe +  cmd = clangformat " > " outputinc + +  pcmd("//===-- sanitizer_interceptors_ioctl_netbsd.inc -----------------*- C++ -*-===//") +  pcmd("//") +  pcmd("//                     The LLVM Compiler Infrastructure") +  pcmd("//") +  pcmd("// This file is distributed under the University of Illinois Open Source") +  pcmd("// License. See LICENSE.TXT for details.") +  pcmd("//") +  pcmd("//===----------------------------------------------------------------------===//") +  pcmd("//") +  pcmd("// Ioctl handling in common sanitizer interceptors.") +  pcmd("//===----------------------------------------------------------------------===//") +  pcmd("") +  pcmd("#if SANITIZER_NETBSD") +  pcmd("") +  pcmd("#include \"sanitizer_flags.h\"") +  pcmd("") +  pcmd("struct ioctl_desc {") +  pcmd("  unsigned req;") +  pcmd("  // FIXME: support read+write arguments. Currently READWRITE and WRITE do the") +  pcmd("  // same thing.") +  pcmd("  // XXX: The declarations below may use WRITE instead of READWRITE, unless") +  pcmd("  // explicitly noted.") +  pcmd("  enum {") +  pcmd("    NONE,") +  pcmd("    READ,") +  pcmd("    WRITE,") +  pcmd("    READWRITE,") +  pcmd("    CUSTOM") +  pcmd("  } type : 3;") +  pcmd("  unsigned size : 29;") +  pcmd("  const char* name;") +  pcmd("};") +  pcmd("") +  pcmd("const unsigned ioctl_table_max = " ioctl_table_max ";") +  pcmd("static ioctl_desc ioctl_table[ioctl_table_max];") +  pcmd("static unsigned ioctl_table_size = 0;") +  pcmd("") +  pcmd("// This can not be declared as a global, because references to struct_*_sz") +  pcmd("// require a global initializer. And this table must be available before global") +  pcmd("// initializers are run.") +  pcmd("static void ioctl_table_fill() {") +  pcmd("#define _(rq, tp, sz)                                    \\") +  pcmd("  if (IOCTL_##rq != IOCTL_NOT_PRESENT) {                 \\") +  pcmd("    CHECK(ioctl_table_size < ioctl_table_max);           \\") +  pcmd("    ioctl_table[ioctl_table_size].req = IOCTL_##rq;      \\") +  pcmd("    ioctl_table[ioctl_table_size].type = ioctl_desc::tp; \\") +  pcmd("    ioctl_table[ioctl_table_size].size = sz;             \\") +  pcmd("    ioctl_table[ioctl_table_size].name = #rq;            \\") +  pcmd("    ++ioctl_table_size;                                  \\") +  pcmd("  }") +  pcmd("") + +  for (i = 0; i < ioctl_table_max; i++) { +    if (i in fname) { +      pcmd("  /* Entries from file: " fname[i] " */") +    } + +    if (i in ioctl_type) { +      type = ioctl_type[i] +    } else { +      type = "0" +    } + +    pcmd("  _(" ioctl_name[i] ", " ioctl_mode[i] "," type ");") +  } + +  pcmd("#undef _") +  pcmd("}") +  pcmd("") +  pcmd("static bool ioctl_initialized = false;") +  pcmd("") +  pcmd("struct ioctl_desc_compare {") +  pcmd("  bool operator()(const ioctl_desc& left, const ioctl_desc& right) const {") +  pcmd("    return left.req < right.req;") +  pcmd("  }") +  pcmd("};") +  pcmd("") +  pcmd("static void ioctl_init() {") +  pcmd("  ioctl_table_fill();") +  pcmd("  Sort(ioctl_table, ioctl_table_size, ioctl_desc_compare());") +  pcmd("") +  pcmd("  bool bad = false;") +  pcmd("  for (unsigned i = 0; i < ioctl_table_size - 1; ++i) {") +  pcmd("    if (ioctl_table[i].req >= ioctl_table[i + 1].req) {") +  pcmd("      Printf(\"Duplicate or unsorted ioctl request id %x >= %x (%s vs %s)\\n\",") +  pcmd("             ioctl_table[i].req, ioctl_table[i + 1].req, ioctl_table[i].name,") +  pcmd("             ioctl_table[i + 1].name);") +  pcmd("      bad = true;") +  pcmd("    }") +  pcmd("  }") +  pcmd("") +  pcmd("  if (bad) Die();") +  pcmd("") +  pcmd("  ioctl_initialized = true;") +  pcmd("}") +  pcmd("") +  pcmd("static const ioctl_desc *ioctl_table_lookup(unsigned req) {") +  pcmd("  int left = 0;") +  pcmd("  int right = ioctl_table_size;") +  pcmd("  while (left < right) {") +  pcmd("    int mid = (left + right) / 2;") +  pcmd("    if (ioctl_table[mid].req < req)") +  pcmd("      left = mid + 1;") +  pcmd("    else") +  pcmd("      right = mid;") +  pcmd("  }") +  pcmd("  if (left == right && ioctl_table[left].req == req)") +  pcmd("    return ioctl_table + left;") +  pcmd("  else") +  pcmd("    return nullptr;") +  pcmd("}") +  pcmd("") +  pcmd("static bool ioctl_decode(unsigned req, ioctl_desc *desc) {") +  pcmd("  CHECK(desc);") +  pcmd("  desc->req = req;") +  pcmd("  desc->name = \"<DECODED_IOCTL>\";") +  pcmd("  desc->size = IOC_SIZE(req);") +  pcmd("  // Sanity check.") +  pcmd("  if (desc->size > 0xFFFF) return false;") +  pcmd("  unsigned dir = IOC_DIR(req);") +  pcmd("  switch (dir) {") +  pcmd("    case IOC_NONE:") +  pcmd("      desc->type = ioctl_desc::NONE;") +  pcmd("      break;") +  pcmd("    case IOC_READ | IOC_WRITE:") +  pcmd("      desc->type = ioctl_desc::READWRITE;") +  pcmd("      break;") +  pcmd("    case IOC_READ:") +  pcmd("      desc->type = ioctl_desc::WRITE;") +  pcmd("      break;") +  pcmd("    case IOC_WRITE:") +  pcmd("      desc->type = ioctl_desc::READ;") +  pcmd("      break;") +  pcmd("    default:") +  pcmd("      return false;") +  pcmd("  }") +  pcmd("  // Size can be 0 iff type is NONE.") +  pcmd("  if ((desc->type == IOC_NONE) != (desc->size == 0)) return false;") +  pcmd("  // Sanity check.") +  pcmd("  if (IOC_TYPE(req) == 0) return false;") +  pcmd("  return true;") +  pcmd("}") +  pcmd("") +  pcmd("static const ioctl_desc *ioctl_lookup(unsigned req) {") +  pcmd("  const ioctl_desc *desc = ioctl_table_lookup(req);") +  pcmd("  if (desc) return desc;") +  pcmd("") +  pcmd("  // Try stripping access size from the request id.") +  pcmd("  desc = ioctl_table_lookup(req & ~(IOC_SIZEMASK << IOC_SIZESHIFT));") +  pcmd("  // Sanity check: requests that encode access size are either read or write and") +  pcmd("  // have size of 0 in the table.") +  pcmd("  if (desc && desc->size == 0 &&") +  pcmd("      (desc->type == ioctl_desc::READWRITE || desc->type == ioctl_desc::WRITE ||") +  pcmd("       desc->type == ioctl_desc::READ))") +  pcmd("    return desc;") +  pcmd("  return nullptr;") +  pcmd("}") +  pcmd("") +  pcmd("static void ioctl_common_pre(void *ctx, const ioctl_desc *desc, int d,") +  pcmd("                             unsigned request, void *arg) {") +  pcmd("  if (desc->type == ioctl_desc::READ || desc->type == ioctl_desc::READWRITE) {") +  pcmd("    unsigned size = desc->size ? desc->size : IOC_SIZE(request);") +  pcmd("    COMMON_INTERCEPTOR_READ_RANGE(ctx, arg, size);") +  pcmd("  }") +  pcmd("  if (desc->type != ioctl_desc::CUSTOM)") +  pcmd("    return;") +  pcmd("  if (request == IOCTL_SIOCGIFCONF) {") +  pcmd("    struct __sanitizer_ifconf *ifc = (__sanitizer_ifconf *)arg;") +  pcmd("    COMMON_INTERCEPTOR_READ_RANGE(ctx, (char*)&ifc->ifc_len,") +  pcmd("                                  sizeof(ifc->ifc_len));") +  pcmd("  }") +  pcmd("}") +  pcmd("") +  pcmd("static void ioctl_common_post(void *ctx, const ioctl_desc *desc, int res, int d,") +  pcmd("                              unsigned request, void *arg) {") +  pcmd("  if (desc->type == ioctl_desc::WRITE || desc->type == ioctl_desc::READWRITE) {") +  pcmd("    // FIXME: add verbose output") +  pcmd("    unsigned size = desc->size ? desc->size : IOC_SIZE(request);") +  pcmd("    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, arg, size);") +  pcmd("  }") +  pcmd("  if (desc->type != ioctl_desc::CUSTOM)") +  pcmd("    return;") +  pcmd("  if (request == IOCTL_SIOCGIFCONF) {") +  pcmd("    struct __sanitizer_ifconf *ifc = (__sanitizer_ifconf *)arg;") +  pcmd("    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ifc->ifc_ifcu.ifcu_req, ifc->ifc_len);") +  pcmd("  }") +  pcmd("}") +  pcmd("") +  pcmd("#endif // SANITIZER_NETBSD") + +  close(cmd) +} + +function usage() +{ +  print "Usage: " script_name +  abnormal_exit = 1 +  exit 1 +} + +function pcmd(string) +{ +  print string | cmd +} + +function get_type(string) +{ +  if (string == "int") { +    return "sizeof(int)" +  } else if (string == "unsigned int" || string == "u_int" || string == "uint") { +    return "sizeof(unsigned int)" +  } else if (string == "long") { +    return "sizeof(long)" +  } else if (string == "unsigned long" || string == "u_long") { +    return "sizeof(unsigned long)" +  } else if (string == "short") { +    return "sizeof(short)" +  } else if (string == "unsigned short") { +    return "sizeof(unsigned short)" +  } else if (string == "char") { +    return "sizeof(char)" +  } else if (string == "signed char") { +    return "sizeof(signed char)" +  } else if (string == "unsigned char") { +    return "sizeof(unsigned char)" +  } else if (string == "uint8_t") { +    return "sizeof(u8)" +  } else if (string == "uint16_t") { +    return "sizeof(u16)" +  } else if (string == "u_int32_t" || string == "uint32_t") { +    return "sizeof(u32)" +  } else if (string ~ /\*$/) { +    return "sizeof(uptr)" +  } else if (string == "off_t") { +    return "sizeof(uptr)" +  } else if (string == "pid_t" || string == "kbd_t") { +    return "sizeof(int)" +  } else if (string == "daddr_t" || string == "dev_t") { +    return "sizeof(u64)" +  } else if (substr(string, 0, 7) == "struct " ) { +    gsub(/ /, "", string) +    return "struct_" substr(string, 7) "_sz" +  } else if (string == "scsireq_t") { +    return "struct_scsireq_sz" +  } else if (string == "tone_t") { +    return "struct_tone_sz" +  } else if (string == "union twe_statrequest") { +    return "union_twe_statrequest_sz" +  } else if (string == "usb_device_descriptor_t") { +    return "struct_usb_device_descriptor_sz" +  } else if (string == "v4l2_std_id") { +    return "sizeof(u64)" +  } else if (string == "vtmode_t") { +    return "struct_vt_mode_sz" +  } else if (string == "_old_mixer_info") { +    return "struct__old_mixer_info_sz" +  } else if (string == "agp_allocate") { +    return "struct__agp_allocate_sz" +  } else if (string == "agp_bind") { +    return "struct__agp_bind_sz" +  } else if (string == "agp_info") { +    return "struct__agp_info_sz" +  } else if (string == "agp_region") { +    return "struct__agp_region_sz" +  } else if (string == "agp_setup") { +    return "struct__agp_setup_sz" +  } else if (string == "agp_unbind") { +    return "struct__agp_unbind_sz" +  } else if (string == "atareq_t") { +    return "struct_atareq_sz" +  } else if (string == "cpustate_t") { +    return "struct_cpustate_sz" +  } else if (string == "dmx_caps_t") { +    return "struct_dmx_caps_sz" +  } else if (string == "dmx_source_t") { +    return "enum_dmx_source_sz" +  } else if (string == "dvd_authinfo") { +    return "union_dvd_authinfo_sz" +  } else if (string == "dvd_struct") { +    return "union_dvd_struct_sz" +  } else if (string == "enum v4l2_priority") { +    return "enum_v4l2_priority_sz" +  } else if (string == "envsys_basic_info_t") { +    return "struct_envsys_basic_info_sz" +  } else if (string == "envsys_tre_data_t") { +    return "struct_envsys_tre_data_sz" +  } else if (string == "ext_accm") { +    return "(8 * sizeof(u32))" +  } else if (string == "fe_sec_mini_cmd_t") { +    return "enum_fe_sec_mini_cmd_sz" +  } else if (string == "fe_sec_tone_mode_t") { +    return "enum_fe_sec_tone_mode_sz" +  } else if (string == "fe_sec_voltage_t") { +    return "enum_fe_sec_voltage_sz" +  } else if (string == "fe_status_t") { +    return "enum_fe_status_sz" +  } else if (string == "gdt_ctrt_t") { +    return "struct_gdt_ctrt_sz" +  } else if (string == "gdt_event_t") { +    return "struct_gdt_event_sz" +  } else if (string == "gdt_osv_t") { +    return "struct_gdt_osv_sz" +  } else if (string == "gdt_rescan_t") { +    return "struct_gdt_rescan_sz" +  } else if (string == "gdt_statist_t") { +    return "struct_gdt_statist_sz" +  } else if (string == "gdt_ucmd_t") { +    return "struct_gdt_ucmd_sz" +  } else if (string == "iscsi_conn_status_parameters_t") { +    return "struct_iscsi_conn_status_parameters_sz" +  } else if (string == "iscsi_get_version_parameters_t") { +    return "struct_iscsi_get_version_parameters_sz" +  } else if (string == "iscsi_iocommand_parameters_t") { +    return "struct_iscsi_iocommand_parameters_sz" +  } else if (string == "iscsi_login_parameters_t") { +    return "struct_iscsi_login_parameters_sz" +  } else if (string == "iscsi_logout_parameters_t") { +    return "struct_iscsi_logout_parameters_sz" +  } else if (string == "iscsi_register_event_parameters_t") { +    return "struct_iscsi_register_event_parameters_sz" +  } else if (string == "iscsi_remove_parameters_t") { +    return "struct_iscsi_remove_parameters_sz" +  } else if (string == "iscsi_send_targets_parameters_t") { +    return "struct_iscsi_send_targets_parameters_sz" +  } else if (string == "iscsi_set_node_name_parameters_t") { +    return "struct_iscsi_set_node_name_parameters_sz" +  } else if (string == "iscsi_wait_event_parameters_t") { +    return "struct_iscsi_wait_event_parameters_sz" +  } else if (string == "isp_stats_t") { +    return "struct_isp_stats_sz" +  } else if (string == "lsenable_t") { +    return "struct_lsenable_sz" +  } else if (string == "lsdisable_t") { +    return "struct_lsdisable_sz" +  } else if (string == "mixer_ctrl_t") { +    return "struct_mixer_ctrl_sz" +  } else if (string == "mixer_devinfo_t") { +    return "struct_mixer_devinfo_sz" +  } else if (string == "mpu_command_rec") { +    return "struct_mpu_command_rec_sz" +  } else if (string == "rndstat_t") { +    return "struct_rndstat_sz" +  } else if (string == "rndstat_name_t") { +    return "struct_rndstat_name_sz" +  } else if (string == "rndctl_t") { +    return "struct_rndctl_sz" +  } else if (string == "rnddata_t") { +    return "struct_rnddata_sz" +  } else if (string == "rndpoolstat_t") { +    return "struct_rndpoolstat_sz" +  } else if (string == "rndstat_est_t") { +    return "struct_rndstat_est_sz" +  } else if (string == "rndstat_est_name_t") { +    return "struct_rndstat_est_name_sz" +  } else if (string == "pps_params_t") { +    return "struct_pps_params_sz" +  } else if (string == "pps_info_t") { +    return "struct_pps_info_sz" +  } else if (string == "linedn_t") { +    return "(32 * sizeof(char))" +  } else if (string == "mixer_info") { +    return "struct_mixer_info_sz" +  } else if (string == "RF_SparetWait_t") { +    return "struct_RF_SparetWait_sz" +  } else if (string == "RF_ComponentLabel_t") { +    return "struct_RF_ComponentLabel_sz" +  } else if (string == "RF_SingleComponent_t") { +    return "struct_RF_SingleComponent_sz" +  } else if (string == "RF_ProgressInfo_t") { +    return "struct_RF_ProgressInfo_sz" +  } else { +    print "Unrecognized entry: " string +    print "Aborting" +    abnormal_exit = 1 +    exit 1 +  } + +  return string +} diff --git a/utils/generate_netbsd_syscalls.awk b/utils/generate_netbsd_syscalls.awk new file mode 100755 index 0000000000000..5e08900a17eeb --- /dev/null +++ b/utils/generate_netbsd_syscalls.awk @@ -0,0 +1,2986 @@ +#!/usr/bin/awk -f + +#===-- generate_netbsd_syscalls.awk ----------------------------------------===# +# +#                     The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +#===------------------------------------------------------------------------===# +# +# This file is a generator of: +#  - include/sanitizer/netbsd_syscall_hooks.h +#  - lib/sanitizer_common/sanitizer_syscalls_netbsd.inc +# +# This script accepts on the input syscalls.master by default located in the +# /usr/src/sys/kern/syscalls.master path in the NetBSD distribution. +# +# NetBSD version 8.0. +# +#===------------------------------------------------------------------------===# + +BEGIN { +  # harcode the script name +  script_name = "generate_netbsd_syscalls.awk" +  outputh = "../include/sanitizer/netbsd_syscall_hooks.h" +  outputinc = "../lib/sanitizer_common/sanitizer_syscalls_netbsd.inc" + +  # assert that we are in the directory with scripts +  in_utils = system("test -f " script_name " && exit 1 || exit 0") +  if (in_utils == 0) { +    usage() +  } + +  # assert 1 argument passed +  if (ARGC != 2) { +    usage() +  } + +  # assert argument is a valid file path to syscall.master +  if (system("test -f " ARGV[1]) != 0) { +    usage() +  } + +  # sanity check that the path ends with "syscall.master" +  if (ARGV[1] !~ /syscalls\.master$/) { +    usage() +  } + +  # accept overloading CLANGFORMAT from environment +  clangformat = "clang-format" +  if ("CLANGFORMAT" in ENVIRON) { +    clangformat = ENVIRON["CLANGFORMAT"] +  } + +  # parsing specific symbols +  parsingheader=1 + +  parsedsyscalls=0 + +  # Hardcoded in algorithm +  SYS_MAXSYSARGS=8 +} + +# Parse the RCS ID from syscall.master +parsingheader == 1 && NR == 1 { +  if (match($0, /\$[^$]+\$/)) { +    # trim initial 'NetBSD: ' and trailing ' $' +    syscallmasterversion = substr($0, RSTART + 9, RLENGTH - 11) +  } else { +    # wrong file? +    usage() +  } +} + +# skip the following lines +#  - empty +NF == 0 { +  next +} +#  - comment +$1 == ";" { +  next +} + +# separator between the header and table with syscalls +$0 == "%%" { +  parsingheader = 0 +  next +} + +# preserve 'if/elif/else/endif' C preprocessor as-is +parsingheader == 0 && $0 ~ /^#/ { +  if (parsedsyscalls in ifelifelseendif) { +    ifelifelseendif[parsedsyscalls] = ifelifelseendif[parsedsyscalls] "\n" $0 +  } else { +    ifelifelseendif[parsedsyscalls] = $0 +  } +  next +} + +# parsing of syscall definitions +parsingheader == 0 && $1 ~ /^[0-9]+$/ { +  # first join multiple lines into single one +  while (sub(/\\$/, "")) { +    getline line +    $0 = $0 "" line +  } + +  # Skip unwanted syscalls +  skip=0 +  if ($0 ~ /OBSOL/ || $0 ~ /EXCL/ || $0 ~ /UNIMPL/) { +    skip=1 +  } + +  # Compose the syscall name +  #  - compat? +  compat="" +  if (match($0, /COMPAT_[0-9]+/)) { +    compat = tolower(substr($0, RSTART, RLENGTH)) +  } +  # - alias name? +  alias="" +  if ($(NF) != "}" && !skip) { +    alias = alias "" $(NF) +  } +  # - compat version? +  compatver="" +  if (match($0, /\|[0-9]+\|/)) { +    compatver = tolower(substr($0, RSTART + 1, RLENGTH - 2)) +  } +  # - basename? +  basename="" +  if (skip) { +    basename = $1 +  } else { +    if (match($0, /\|[_a-z0-9]+\(/)) { +      basename = tolower(substr($0, RSTART + 1, RLENGTH - 2)) +    } +  } + +  syscallname="" + +  if (skip) { +    syscallname= syscallname "$" +  } + +  if (length(compat) > 0) { +    syscallname = syscallname "" compat "_" +  } +  if (length(alias) > 0) { +    syscallname = syscallname "" alias +  } else { +    if (length(compatver) > 0) { +      syscallname = syscallname "__" basename "" compatver +    } else { +      syscallname = syscallname "" basename +    } +  } + +  # Store the syscallname +  syscalls[parsedsyscalls]=syscallname + +  # Extract syscall arguments +  if (match($0, /\([^)]+\)/)) { +    args = substr($0, RSTART + 1, RLENGTH - 2) + +    if (args == "void") { +      syscallargs[parsedsyscalls] = "void" +      syscallfullargs[parsedsyscalls] = "void" +    } else { +      # Normalize 'type * argument' to 'type *argument' +      gsub("\\*[ \t]+", "*", args) + +      n = split(args, a, ",") + +      # Handle the first argument +      match(a[1], /[*_a-z0-9\[\]]+$/) +      syscallfullargs[parsedsyscalls] = substr(a[1], RSTART) "_" + +      gsub(".+[ *]", "", a[1]) +      syscallargs[parsedsyscalls] = a[1] + +      # Handle the rest of arguments +      for (i = 2; i <= n; i++) { +        match(a[i], /[*_a-zA-Z0-9\[\]]+$/) +        fs = substr(a[i], RSTART) +        if (fs ~ /\[/) { +          sub(/\[/, "_[", fs) +        } else { +          fs = fs "_" +        } +        syscallfullargs[parsedsyscalls] = syscallfullargs[parsedsyscalls] "$" fs +	gsub(".+[ *]", "", a[i]) +        syscallargs[parsedsyscalls] = syscallargs[parsedsyscalls] "$" a[i] +      } + +      # Handle array arguments for syscall(2) and __syscall(2) +      nargs = "arg0$arg1$arg2$arg3$arg4$arg5$arg6$arg7" +      gsub(/args\[SYS_MAXSYSARGS\]/, nargs, syscallargs[parsedsyscalls]) +    } +  } + +  parsedsyscalls++ + +  # Done with this line +  next +} + + +END { +  # empty file? +  if (NR < 1 && !abnormal_exit) { +    usage() +  } + +  # Handle abnormal exit +  if (abnormal_exit) { +    exit(abnormal_exit) +  } + +  # Generate sanitizer_syscalls_netbsd.inc + +  # open pipe +  cmd = clangformat " > " outputh + +  pcmd("//===-- netbsd_syscall_hooks.h --------------------------------------------===//") +  pcmd("//") +  pcmd("//                     The LLVM Compiler Infrastructure") +  pcmd("//") +  pcmd("// This file is distributed under the University of Illinois Open Source") +  pcmd("// License. See LICENSE.TXT for details.") +  pcmd("//") +  pcmd("//===----------------------------------------------------------------------===//") +  pcmd("//") +  pcmd("// This file is a part of public sanitizer interface.") +  pcmd("//") +  pcmd("// System call handlers.") +  pcmd("//") +  pcmd("// Interface methods declared in this header implement pre- and post- syscall") +  pcmd("// actions for the active sanitizer.") +  pcmd("// Usage:") +  pcmd("//   __sanitizer_syscall_pre_getfoo(...args...);") +  pcmd("//   long long res = syscall(SYS_getfoo, ...args...);") +  pcmd("//   __sanitizer_syscall_post_getfoo(res, ...args...);") +  pcmd("//") +  pcmd("// DO NOT EDIT! THIS FILE HAS BEEN GENERATED!") +  pcmd("//") +  pcmd("// Generated with: " script_name) +  pcmd("// Generated date: " strftime("%F")) +  pcmd("// Generated from: " syscallmasterversion) +  pcmd("//") +  pcmd("//===----------------------------------------------------------------------===//") +  pcmd("#ifndef SANITIZER_NETBSD_SYSCALL_HOOKS_H") +  pcmd("#define SANITIZER_NETBSD_SYSCALL_HOOKS_H") +  pcmd("") + +  for (i = 0; i < parsedsyscalls; i++) { + +    if (i in ifelifelseendif) { +      pcmd(ifelifelseendif[i]) +    } + +    sn = syscalls[i] + +    if (sn ~ /^\$/) { +      pcmd("/* syscall " substr(sn,2) " has been skipped */") +      continue +    } + +    inargs = "" + +    if (syscallargs[i] != "void") { +      inargs = syscallargs[i] +      gsub(/\$/, ", ", inargs) +    } + +    outargs = "" + +    if (syscallargs[i] != "void") { +      outargs = "(long long)(" syscallargs[i] ")" +      gsub(/\$/, "), (long long)(", outargs) +    } + +    pcmd("#define __sanitizer_syscall_pre_" sn "(" inargs ") \\") +    pcmd("  __sanitizer_syscall_pre_impl_" sn "(" outargs ")") + +    if (inargs == "") { +      inargs = "res" +    } else { +      inargs = "res, " inargs +    } + +    if (outargs == "") { +      outargs = "res" +    } else { +      outargs = "res, " outargs +    } + +    pcmd("#define __sanitizer_syscall_post_" sn "(" inargs ") \\") +    pcmd("  __sanitizer_syscall_post_impl_" sn "(" outargs ")") +  } + +  pcmd("") +  pcmd("#ifdef __cplusplus") +  pcmd("extern \"C\" {") +  pcmd("#endif") +  pcmd("") +  pcmd("// Private declarations. Do not call directly from user code. Use macros above.") +  pcmd("") +  pcmd("// DO NOT EDIT! THIS FILE HAS BEEN GENERATED!") +  pcmd("") + +  for (i = 0; i < parsedsyscalls; i++) { + +    if (i in ifelifelseendif) { +      pcmd(ifelifelseendif[i]) +    } + +    sn = syscalls[i] + +    if (sn ~ /^\$/) { +      pcmd("/* syscall " substr(sn,2) " has been skipped */") +      continue +    } + +    preargs = syscallargs[i] + +    if (preargs != "void") { +      preargs = "long long " preargs +      gsub(/\$/, ", long long ", preargs) +    } + +    if (preargs == "void") { +      postargs = "long long res" +    } else { +      postargs = "long long res, " preargs +    } + +    pcmd("void __sanitizer_syscall_pre_impl_" sn "(" preargs ");") +    pcmd("void __sanitizer_syscall_post_impl_" sn "(" postargs ");") +  } + +  pcmd("") +  pcmd("#ifdef __cplusplus") +  pcmd("} // extern \"C\"") +  pcmd("#endif") + +  pcmd("") +  pcmd("// DO NOT EDIT! THIS FILE HAS BEEN GENERATED!") +  pcmd("") + +  pcmd("#endif  // SANITIZER_NETBSD_SYSCALL_HOOKS_H") + +  close(cmd) + +  # Generate sanitizer_syscalls_netbsd.inc + +  # open pipe +  cmd = clangformat " > " outputinc + +  pcmd("//===-- sanitizer_syscalls_netbsd.inc ---------------------------*- C++ -*-===//") +  pcmd("//") +  pcmd("//                     The LLVM Compiler Infrastructure") +  pcmd("//") +  pcmd("// This file is distributed under the University of Illinois Open Source") +  pcmd("// License. See LICENSE.TXT for details.") +  pcmd("//") +  pcmd("//===----------------------------------------------------------------------===//") +  pcmd("//") +  pcmd("// Common syscalls handlers for tools like AddressSanitizer,") +  pcmd("// ThreadSanitizer, MemorySanitizer, etc.") +  pcmd("//") +  pcmd("// This file should be included into the tool's interceptor file,") +  pcmd("// which has to define it's own macros:") +  pcmd("//   COMMON_SYSCALL_PRE_READ_RANGE") +  pcmd("//          Called in prehook for regions that will be read by the kernel and") +  pcmd("//          must be initialized.") +  pcmd("//   COMMON_SYSCALL_PRE_WRITE_RANGE") +  pcmd("//          Called in prehook for regions that will be written to by the kernel") +  pcmd("//          and must be addressable. The actual write range may be smaller than") +  pcmd("//          reported in the prehook. See POST_WRITE_RANGE.") +  pcmd("//   COMMON_SYSCALL_POST_READ_RANGE") +  pcmd("//          Called in posthook for regions that were read by the kernel. Does") +  pcmd("//          not make much sense.") +  pcmd("//   COMMON_SYSCALL_POST_WRITE_RANGE") +  pcmd("//          Called in posthook for regions that were written to by the kernel") +  pcmd("//          and are now initialized.") +  pcmd("//   COMMON_SYSCALL_ACQUIRE(addr)") +  pcmd("//          Acquire memory visibility from addr.") +  pcmd("//   COMMON_SYSCALL_RELEASE(addr)") +  pcmd("//          Release memory visibility to addr.") +  pcmd("//   COMMON_SYSCALL_FD_CLOSE(fd)") +  pcmd("//          Called before closing file descriptor fd.") +  pcmd("//   COMMON_SYSCALL_FD_ACQUIRE(fd)") +  pcmd("//          Acquire memory visibility from fd.") +  pcmd("//   COMMON_SYSCALL_FD_RELEASE(fd)") +  pcmd("//          Release memory visibility to fd.") +  pcmd("//   COMMON_SYSCALL_PRE_FORK()") +  pcmd("//          Called before fork syscall.") +  pcmd("//   COMMON_SYSCALL_POST_FORK(long long res)") +  pcmd("//          Called after fork syscall.") +  pcmd("//") +  pcmd("// DO NOT EDIT! THIS FILE HAS BEEN GENERATED!") +  pcmd("//") +  pcmd("// Generated with: " script_name) +  pcmd("// Generated date: " strftime("%F")) +  pcmd("// Generated from: " syscallmasterversion) +  pcmd("//") +  pcmd("//===----------------------------------------------------------------------===//") +  pcmd("") +  pcmd("#include \"sanitizer_platform.h\"") +  pcmd("#if SANITIZER_NETBSD") +  pcmd("") +  pcmd("#include \"sanitizer_libc.h\"") +  pcmd("") +  pcmd("#define PRE_SYSCALL(name)                                                      \\") +  pcmd("  SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_syscall_pre_impl_##name") +  pcmd("#define PRE_READ(p, s) COMMON_SYSCALL_PRE_READ_RANGE(p, s)") +  pcmd("#define PRE_WRITE(p, s) COMMON_SYSCALL_PRE_WRITE_RANGE(p, s)") +  pcmd("") +  pcmd("#define POST_SYSCALL(name)                                                     \\") +  pcmd("  SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_syscall_post_impl_##name") +  pcmd("#define POST_READ(p, s) COMMON_SYSCALL_POST_READ_RANGE(p, s)") +  pcmd("#define POST_WRITE(p, s) COMMON_SYSCALL_POST_WRITE_RANGE(p, s)") +  pcmd("") +  pcmd("#ifndef COMMON_SYSCALL_ACQUIRE") +  pcmd("# define COMMON_SYSCALL_ACQUIRE(addr) ((void)(addr))") +  pcmd("#endif") +  pcmd("") +  pcmd("#ifndef COMMON_SYSCALL_RELEASE") +  pcmd("# define COMMON_SYSCALL_RELEASE(addr) ((void)(addr))") +  pcmd("#endif") +  pcmd("") +  pcmd("#ifndef COMMON_SYSCALL_FD_CLOSE") +  pcmd("# define COMMON_SYSCALL_FD_CLOSE(fd) ((void)(fd))") +  pcmd("#endif") +  pcmd("") +  pcmd("#ifndef COMMON_SYSCALL_FD_ACQUIRE") +  pcmd("# define COMMON_SYSCALL_FD_ACQUIRE(fd) ((void)(fd))") +  pcmd("#endif") +  pcmd("") +  pcmd("#ifndef COMMON_SYSCALL_FD_RELEASE") +  pcmd("# define COMMON_SYSCALL_FD_RELEASE(fd) ((void)(fd))") +  pcmd("#endif") +  pcmd("") +  pcmd("#ifndef COMMON_SYSCALL_PRE_FORK") +  pcmd("# define COMMON_SYSCALL_PRE_FORK() {}") +  pcmd("#endif") +  pcmd("") +  pcmd("#ifndef COMMON_SYSCALL_POST_FORK") +  pcmd("# define COMMON_SYSCALL_POST_FORK(res) {}") +  pcmd("#endif") +  pcmd("") +  pcmd("// FIXME: do some kind of PRE_READ for all syscall arguments (int(s) and such).") +  pcmd("") +  pcmd("extern \"C\" {") +  pcmd("#define SYS_MAXSYSARGS " SYS_MAXSYSARGS) + +  for (i = 0; i < parsedsyscalls; i++) { + +    if (i in ifelifelseendif) { +      pcmd(ifelifelseendif[i]) +    } + +    sn = syscalls[i] + +    if (sn ~ /^\$/) { +      pcmd("/* syscall " substr(sn,2) " has been skipped */") +      continue +    } + +    preargs = syscallfullargs[i] + +    if (preargs != "void") { +      preargs = "long long " preargs +      gsub(/\$/, ", long long ", preargs) +      gsub(/long long \*/, "void *", preargs) +    } + +    if (preargs == "void") { +      postargs = "long long res" +    } else { +      postargs = "long long res, " preargs +    } + +    pcmd("PRE_SYSCALL(" sn ")(" preargs ")") +    pcmd("{") +    syscall_body(sn, "pre") +    pcmd("}") + +    pcmd("POST_SYSCALL(" sn ")(" postargs ")") +    pcmd("{") +    syscall_body(sn, "post") +    pcmd("}") +  } + +  pcmd("#undef SYS_MAXSYSARGS") +  pcmd("}  // extern \"C\"") +  pcmd("") +  pcmd("#undef PRE_SYSCALL") +  pcmd("#undef PRE_READ") +  pcmd("#undef PRE_WRITE") +  pcmd("#undef POST_SYSCALL") +  pcmd("#undef POST_READ") +  pcmd("#undef POST_WRITE") +  pcmd("") +  pcmd("#endif  // SANITIZER_NETBSD") + +  close(cmd) + +  # Hack for preprocessed code +  system("sed -i 's,^ \\([^ ]\\),  \\1,' " outputinc) +} + +function usage() +{ +  print "Usage: " script_name " syscalls.master" +  abnormal_exit = 1 +  exit 1 +} + +function pcmd(string) +{ +  print string | cmd +} + +function syscall_body(syscall, mode) +{ +  # Hardcode sanitizing rules here +  # These syscalls don't change often so they are hand coded +  if (syscall == "syscall") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "exit") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "fork") { +    if (mode == "pre") { +      pcmd("COMMON_SYSCALL_PRE_FORK();") +    } else { +      pcmd("COMMON_SYSCALL_POST_FORK(res);") +    } +  } else if (syscall == "read") { +    if (mode == "pre") { +      pcmd("if (buf_) {") +      pcmd("  PRE_WRITE(buf_, nbyte_);") +      pcmd("}") +    } else { +      pcmd("if (res > 0) {") +      pcmd("  POST_WRITE(buf_, res);") +      pcmd("}") +    } +  } else if (syscall == "write") { +    if (mode == "pre") { +      pcmd("if (buf_) {") +      pcmd("  PRE_READ(buf_, nbyte_);") +      pcmd("}") +    } else { +      pcmd("if (res > 0) {") +      pcmd("  POST_READ(buf_, res);") +      pcmd("}") +    } +  } else if (syscall == "open") { +    if (mode == "pre") { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (path) {") +      pcmd("  PRE_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("}") +    } else { +      pcmd("if (res > 0) {") +      pcmd("  const char *path = (const char *)path_;") +      pcmd("  if (path) {") +      pcmd("    POST_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("  }") +      pcmd("}") +    } +  } else if (syscall == "close") { +    if (mode == "pre") { +      pcmd("COMMON_SYSCALL_FD_CLOSE((int)fd_);") +    } else { +      pcmd("/* Nothing to do */") +    } +  } else if (syscall == "compat_50_wait4") { +    pcmd("/* TODO */") +  } else if (syscall == "compat_43_ocreat") { +    pcmd("/* TODO */") +  } else if (syscall == "link") { +    if (mode == "pre") { +      pcmd("const char *path = (const char *)path_;") +      pcmd("const char *link = (const char *)link_;") +      pcmd("if (path) {") +      pcmd("  PRE_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("}") +      pcmd("if (link) {") +      pcmd("  PRE_READ(path, __sanitizer::internal_strlen(link) + 1);") +      pcmd("}") +    } else { +      pcmd("if (res == 0) {") +      pcmd("  const char *path = (const char *)path_;") +      pcmd("  const char *link = (const char *)link_;") +      pcmd("  if (path) {") +      pcmd("    POST_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("  }") +      pcmd("  if (link) {") +      pcmd("    POST_READ(path, __sanitizer::internal_strlen(link) + 1);") +      pcmd("  }") +      pcmd("}") +    } +  } else if (syscall == "unlink") { +    if (mode == "pre") { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (path) {") +      pcmd("  PRE_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("}") +    } else { +      pcmd("if (res == 0) {") +      pcmd("  const char *path = (const char *)path_;") +      pcmd("  if (path) {") +      pcmd("    POST_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("  }") +      pcmd("}") +    } +  } else if (syscall == "chdir") { +    if (mode == "pre") { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (path) {") +      pcmd("  PRE_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("}") +    } else { +      pcmd("if (res == 0) {") +      pcmd("  const char *path = (const char *)path_;") +      pcmd("  if (path) {") +      pcmd("    POST_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("  }") +      pcmd("}") +    } +  } else if (syscall == "fchdir") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "compat_50_mknod") { +    pcmd("/* TODO */") +  } else if (syscall == "chmod") { +    if (mode == "pre") { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (path) {") +      pcmd("  PRE_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("}") +    } else { +      pcmd("if (res == 0) {") +      pcmd("  const char *path = (const char *)path_;") +      pcmd("  if (path) {") +      pcmd("    POST_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("  }") +      pcmd("}") +    } +  } else if (syscall == "chown") { +    if (mode == "pre") { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (path) {") +      pcmd("  PRE_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("}") +    } else { +      pcmd("if (res == 0) {") +      pcmd("  const char *path = (const char *)path_;") +      pcmd("  if (path) {") +      pcmd("    POST_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("  }") +      pcmd("}") +    } +  } else if (syscall == "break") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "compat_20_getfsstat") { +    pcmd("/* TODO */") +  } else if (syscall == "compat_43_olseek") { +    pcmd("/* TODO */") +  } else if (syscall == "getpid") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "compat_40_mount") { +    pcmd("/* TODO */") +  } else if (syscall == "unmount") { +    if (mode == "pre") { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (path) {") +      pcmd("  PRE_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("}") +    } else { +      pcmd("if (res == 0) {") +      pcmd("  const char *path = (const char *)path_;") +      pcmd("  if (path) {") +      pcmd("    POST_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("  }") +      pcmd("}") +    } +  } else if (syscall == "setuid") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "getuid") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "geteuid") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "ptrace") { +    if (mode == "pre") { +      pcmd("if (req_ == ptrace_pt_io) {") +      pcmd("  struct __sanitizer_ptrace_io_desc *addr = (struct __sanitizer_ptrace_io_desc *)addr_;") +      pcmd("  PRE_READ(addr, struct_ptrace_ptrace_io_desc_struct_sz);") +      pcmd("  if (addr->piod_op == ptrace_piod_write_d || addr->piod_op == ptrace_piod_write_i) {") +      pcmd("    PRE_READ(addr->piod_addr, addr->piod_len);") +      pcmd("  }") +      pcmd("  if (addr->piod_op == ptrace_piod_read_d || addr->piod_op == ptrace_piod_read_i || addr->piod_op == ptrace_piod_read_auxv) {") +      pcmd("    PRE_WRITE(addr->piod_addr, addr->piod_len);") +      pcmd("  }") +      pcmd("} else if (req_ == ptrace_pt_lwpinfo) {") +      pcmd("  struct __sanitizer_ptrace_lwpinfo *addr = (struct __sanitizer_ptrace_lwpinfo *)addr_;") +      pcmd("  PRE_READ(&addr->pl_lwpid, sizeof(__sanitizer_lwpid_t));") +      pcmd("  PRE_WRITE(addr, struct_ptrace_ptrace_lwpinfo_struct_sz);") +      pcmd("} else if (req_ == ptrace_pt_set_event_mask) {") +      pcmd("  PRE_READ(addr_, struct_ptrace_ptrace_event_struct_sz);") +      pcmd("} else if (req_ == ptrace_pt_get_event_mask) {") +      pcmd("  PRE_WRITE(addr_, struct_ptrace_ptrace_event_struct_sz);") +      pcmd("} else if (req_ == ptrace_pt_set_siginfo) {") +      pcmd("  PRE_READ(addr_, struct_ptrace_ptrace_siginfo_struct_sz);") +      pcmd("} else if (req_ == ptrace_pt_get_siginfo) {") +      pcmd("  PRE_WRITE(addr_, struct_ptrace_ptrace_siginfo_struct_sz);") +      pcmd("} else if (req_ == ptrace_pt_setregs) {") +      pcmd("  PRE_READ(addr_, struct_ptrace_reg_struct_sz);") +      pcmd("} else if (req_ == ptrace_pt_getregs) {") +      pcmd("  PRE_WRITE(addr_, struct_ptrace_reg_struct_sz);") +      pcmd("} else if (req_ == ptrace_pt_setfpregs) {") +      pcmd("  PRE_READ(addr_, struct_ptrace_fpreg_struct_sz);") +      pcmd("} else if (req_ == ptrace_pt_getfpregs) {") +      pcmd("  PRE_WRITE(addr_, struct_ptrace_fpreg_struct_sz);") +      pcmd("} else if (req_ == ptrace_pt_setdbregs) {") +      pcmd("  PRE_READ(addr_, struct_ptrace_dbreg_struct_sz);") +      pcmd("} else if (req_ == ptrace_pt_getdbregs) {") +      pcmd("  PRE_WRITE(addr_, struct_ptrace_dbreg_struct_sz);") +      pcmd("}") +    } else { +      pcmd("if (res == 0) {") +      pcmd("  if (req_ == ptrace_pt_io) {") +      pcmd("    struct __sanitizer_ptrace_io_desc *addr = (struct __sanitizer_ptrace_io_desc *)addr_;") +      pcmd("    POST_READ(addr, struct_ptrace_ptrace_io_desc_struct_sz);") +      pcmd("    if (addr->piod_op == ptrace_piod_write_d || addr->piod_op == ptrace_piod_write_i) {") +      pcmd("      POST_READ(addr->piod_addr, addr->piod_len);") +      pcmd("    }") +      pcmd("    if (addr->piod_op == ptrace_piod_read_d || addr->piod_op == ptrace_piod_read_i || addr->piod_op == ptrace_piod_read_auxv) {") +      pcmd("      POST_WRITE(addr->piod_addr, addr->piod_len);") +      pcmd("    }") +      pcmd("  } else if (req_ == ptrace_pt_lwpinfo) {") +      pcmd("    struct __sanitizer_ptrace_lwpinfo *addr = (struct __sanitizer_ptrace_lwpinfo *)addr_;") +      pcmd("    POST_READ(&addr->pl_lwpid, sizeof(__sanitizer_lwpid_t));") +      pcmd("    POST_WRITE(addr, struct_ptrace_ptrace_lwpinfo_struct_sz);") +      pcmd("  } else if (req_ == ptrace_pt_set_event_mask) {") +      pcmd("    POST_READ(addr_, struct_ptrace_ptrace_event_struct_sz);") +      pcmd("  } else if (req_ == ptrace_pt_get_event_mask) {") +      pcmd("    POST_WRITE(addr_, struct_ptrace_ptrace_event_struct_sz);") +      pcmd("  } else if (req_ == ptrace_pt_set_siginfo) {") +      pcmd("    POST_READ(addr_, struct_ptrace_ptrace_siginfo_struct_sz);") +      pcmd("  } else if (req_ == ptrace_pt_get_siginfo) {") +      pcmd("    POST_WRITE(addr_, struct_ptrace_ptrace_siginfo_struct_sz);") +      pcmd("  } else if (req_ == ptrace_pt_setregs) {") +      pcmd("    POST_READ(addr_, struct_ptrace_reg_struct_sz);") +      pcmd("  } else if (req_ == ptrace_pt_getregs) {") +      pcmd("    POST_WRITE(addr_, struct_ptrace_reg_struct_sz);") +      pcmd("  } else if (req_ == ptrace_pt_setfpregs) {") +      pcmd("    POST_READ(addr_, struct_ptrace_fpreg_struct_sz);") +      pcmd("  } else if (req_ == ptrace_pt_getfpregs) {") +      pcmd("    POST_WRITE(addr_, struct_ptrace_fpreg_struct_sz);") +      pcmd("  } else if (req_ == ptrace_pt_setdbregs) {") +      pcmd("    POST_READ(addr_, struct_ptrace_dbreg_struct_sz);") +      pcmd("  } else if (req_ == ptrace_pt_getdbregs) {") +      pcmd("    POST_WRITE(addr_, struct_ptrace_dbreg_struct_sz);") +      pcmd("  }") +      pcmd("}") +    } +  } else if (syscall == "recvmsg") { +    if (mode == "pre") { +      pcmd("PRE_WRITE(msg_, sizeof(__sanitizer_msghdr));") +    } else { +      pcmd("if (res > 0) {") +      pcmd("  POST_WRITE(msg_, sizeof(__sanitizer_msghdr));") +      pcmd("}") +    } +  } else if (syscall == "sendmsg") { +    if (mode == "pre") { +      pcmd("PRE_READ(msg_, sizeof(__sanitizer_msghdr));") +    } else { +      pcmd("if (res > 0) {") +      pcmd("  POST_READ(msg_, sizeof(__sanitizer_msghdr));") +      pcmd("}") +    } +  } else if (syscall == "recvfrom") { +    if (mode == "pre") { +      pcmd("PRE_WRITE(buf_, len_);") +      pcmd("PRE_WRITE(from_, struct_sockaddr_sz);") +      pcmd("PRE_WRITE(fromlenaddr_, sizeof(__sanitizer_socklen_t));") +    } else { +      pcmd("if (res >= 0) {") +      pcmd("  POST_WRITE(buf_, res);") +      pcmd("  POST_WRITE(from_, struct_sockaddr_sz);") +      pcmd("  POST_WRITE(fromlenaddr_, sizeof(__sanitizer_socklen_t));") +      pcmd("}") +    } +  } else if (syscall == "accept") { +    if (mode == "pre") { +      pcmd("PRE_WRITE(name_, struct_sockaddr_sz);") +      pcmd("PRE_WRITE(anamelen_, sizeof(__sanitizer_socklen_t));") +    } else { +      pcmd("if (res == 0) {") +      pcmd("  POST_WRITE(name_, struct_sockaddr_sz);") +      pcmd("  POST_WRITE(anamelen_, sizeof(__sanitizer_socklen_t));") +      pcmd("}") +    } +  } else if (syscall == "getpeername") { +    if (mode == "pre") { +      pcmd("PRE_WRITE(asa_, struct_sockaddr_sz);") +      pcmd("PRE_WRITE(alen_, sizeof(__sanitizer_socklen_t));") +    } else { +      pcmd("if (res == 0) {") +      pcmd("  POST_WRITE(asa_, struct_sockaddr_sz);") +      pcmd("  POST_WRITE(alen_, sizeof(__sanitizer_socklen_t));") +      pcmd("}") +    } +  } else if (syscall == "getsockname") { +    if (mode == "pre") { +      pcmd("PRE_WRITE(asa_, struct_sockaddr_sz);") +      pcmd("PRE_WRITE(alen_, sizeof(__sanitizer_socklen_t));") +    } else { +      pcmd("if (res == 0) {") +      pcmd("  POST_WRITE(asa_, struct_sockaddr_sz);") +      pcmd("  POST_WRITE(alen_, sizeof(__sanitizer_socklen_t));") +      pcmd("}") +    } +  } else if (syscall == "access") { +    if (mode == "pre") { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (path) {") +      pcmd("  PRE_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("}") +    } else { +      pcmd("if (res == 0) {") +      pcmd("  const char *path = (const char *)path_;") +      pcmd("  if (path) {") +      pcmd("    POST_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("  }") +      pcmd("}") +    } +  } else if (syscall == "chflags") { +    if (mode == "pre") { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (path) {") +      pcmd("  PRE_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("}") +    } else { +      pcmd("if (res == 0) {") +      pcmd("  const char *path = (const char *)path_;") +      pcmd("  if (path) {") +      pcmd("    POST_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("  }") +      pcmd("}") +    } +  } else if (syscall == "fchflags") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "sync") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "kill") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "compat_43_stat43") { +    pcmd("/* TODO */") +  } else if (syscall == "getppid") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "compat_43_lstat43") { +    pcmd("/* TODO */") +  } else if (syscall == "dup") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "pipe") { +    pcmd("/* pipe returns two descriptors through two returned values */") +  } else if (syscall == "getegid") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "profil") { +    if (mode == "pre") { +      pcmd("if (samples_) {") +      pcmd("  PRE_WRITE(samples_, size_);") +      pcmd("}") +    } else { +      pcmd("if (res == 0) {") +      pcmd("  if (samples_) {") +      pcmd("    POST_WRITE(samples_, size_);") +      pcmd("  }") +      pcmd("}") +    } +  } else if (syscall == "ktrace") { +    if (mode == "pre") { +      pcmd("const char *fname = (const char *)fname_;") +      pcmd("if (fname) {") +      pcmd("  PRE_READ(fname, __sanitizer::internal_strlen(fname) + 1);") +      pcmd("}") +    } else { +      pcmd("const char *fname = (const char *)fname_;") +      pcmd("if (res == 0) {") +      pcmd("  if (fname) {") +      pcmd("    POST_READ(fname, __sanitizer::internal_strlen(fname) + 1);") +      pcmd("  }") +      pcmd("}") +    } +  } else if (syscall == "compat_13_sigaction13") { +    pcmd("/* TODO */") +  } else if (syscall == "getgid") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "compat_13_sigprocmask13") { +    pcmd("/* TODO */") +  } else if (syscall == "__getlogin") { +    if (mode == "pre") { +      pcmd("if (namebuf_) {") +      pcmd("  PRE_WRITE(namebuf_, namelen_);") +      pcmd("}") +    } else { +      pcmd("if (res == 0) {") +      pcmd("  if (namebuf_) {") +      pcmd("    POST_WRITE(namebuf_, namelen_);") +      pcmd("  }") +      pcmd("}") +    } +  } else if (syscall == "__setlogin") { +    if (mode == "pre") { +      pcmd("const char *namebuf = (const char *)namebuf_;") +      pcmd("if (namebuf) {") +      pcmd("  PRE_READ(namebuf, __sanitizer::internal_strlen(namebuf) + 1);") +      pcmd("}") +    } else { +      pcmd("if (res == 0) {") +      pcmd("  const char *namebuf = (const char *)namebuf_;") +      pcmd("  if (namebuf) {") +      pcmd("    POST_READ(namebuf, __sanitizer::internal_strlen(namebuf) + 1);") +      pcmd("  }") +      pcmd("}") +    } +  } else if (syscall == "acct") { +    if (mode == "pre") { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (path) {") +      pcmd("  PRE_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("}") +    } else { +      pcmd("if (res == 0) {") +      pcmd("  const char *path = (const char *)path_;") +      pcmd("  if (path) {") +      pcmd("    POST_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("  }") +      pcmd("}") +    } +  } else if (syscall == "compat_13_sigpending13") { +    pcmd("/* TODO */") +  } else if (syscall == "compat_13_sigaltstack13") { +    pcmd("/* TODO */") +  } else if (syscall == "ioctl") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "compat_12_oreboot") { +    pcmd("/* TODO */") +  } else if (syscall == "revoke") { +    if (mode == "pre") { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (path) {") +      pcmd("  PRE_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("}") +    } else { +      pcmd("if (res == 0) {") +      pcmd("  const char *path = (const char *)path_;") +      pcmd("  if (path) {") +      pcmd("    POST_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("  }") +      pcmd("}") +    } +  } else if (syscall == "symlink") { +    if (mode == "pre") { +      pcmd("const char *path = (const char *)path_;") +      pcmd("const char *link = (const char *)link_;") +      pcmd("if (path) {") +      pcmd("  PRE_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("}") +      pcmd("if (link) {") +      pcmd("  PRE_READ(link, __sanitizer::internal_strlen(link) + 1);") +      pcmd("}") +    } else { +      pcmd("if (res == 0) {") +      pcmd("  const char *path = (const char *)path_;") +      pcmd("  const char *link = (const char *)link_;") +      pcmd("  if (path) {") +      pcmd("    POST_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("  }") +      pcmd("  if (link) {") +      pcmd("    POST_READ(link, __sanitizer::internal_strlen(link) + 1);") +      pcmd("  }") +      pcmd("}") +    } +  } else if (syscall == "readlink") { +    if (mode == "pre") { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (path) {") +      pcmd("  PRE_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("}") +      pcmd("if (buf_) {") +      pcmd("  PRE_WRITE(buf_, count_);") +      pcmd("}") +    } else { +      pcmd("if (res > 0) {") +      pcmd("  const char *path = (const char *)path_;") +      pcmd("  if (path) {") +      pcmd("    POST_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("  }") +      pcmd("  if (buf_) {") +      pcmd("    PRE_WRITE(buf_, res);") +      pcmd("  }") +      pcmd("}") +    } +  } else if (syscall == "execve") { +    if (mode == "pre") { +      pcmd("const char *path = (const char *)path_;") +      pcmd("char **argp = (char **)argp_;") +      pcmd("char **envp = (char **)envp_;") +      pcmd("if (path) {") +      pcmd("  PRE_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("}") +      pcmd("if (argp && argp[0]) {") +      pcmd("  char *a = argp[0];") +      pcmd("  while (a++) {") +      pcmd("    PRE_READ(a, __sanitizer::internal_strlen(a) + 1);") +      pcmd("  }") +      pcmd("}") +      pcmd("if (envp && envp[0]) {") +      pcmd("  char *e = envp[0];") +      pcmd("  while (e++) {") +      pcmd("    PRE_READ(e, __sanitizer::internal_strlen(e) + 1);") +      pcmd("  }") +      pcmd("}") +    } else { +      pcmd("/* If we are here, something went wrong */") +      pcmd("const char *path = (const char *)path_;") +      pcmd("char **argp = (char **)argp_;") +      pcmd("char **envp = (char **)envp_;") +      pcmd("if (path) {") +      pcmd("  POST_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("}") +      pcmd("if (argp && argp[0]) {") +      pcmd("  char *a = argp[0];") +      pcmd("  while (a++) {") +      pcmd("    POST_READ(a, __sanitizer::internal_strlen(a) + 1);") +      pcmd("  }") +      pcmd("}") +      pcmd("if (envp && envp[0]) {") +      pcmd("  char *e = envp[0];") +      pcmd("  while (e++) {") +      pcmd("    POST_READ(e, __sanitizer::internal_strlen(e) + 1);") +      pcmd("  }") +      pcmd("}") +    } +  } else if (syscall == "umask") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "chroot") { +    if (mode == "pre") { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (path) {") +      pcmd("  PRE_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("}") +    } else { +      pcmd("if (res == 0) {") +      pcmd("  const char *path = (const char *)path_;") +      pcmd("  if (path) {") +      pcmd("    POST_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("  }") +      pcmd("}") +    } +  } else if (syscall == "compat_43_fstat43") { +    pcmd("/* TODO */") +  } else if (syscall == "compat_43_ogetkerninfo") { +    pcmd("/* TODO */") +  } else if (syscall == "compat_43_ogetpagesize") { +    pcmd("/* TODO */") +  } else if (syscall == "compat_12_msync") { +    pcmd("/* TODO */") +  } else if (syscall == "vfork") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "compat_43_ommap") { +    pcmd("/* TODO */") +  } else if (syscall == "vadvise") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "munmap") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "mprotect") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "madvise") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "mincore") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "getgroups") { +    if (mode == "pre") { +      pcmd("unsigned int *gidset = (unsigned int *)gidset_;") +      pcmd("if (gidset) {") +      pcmd("  PRE_WRITE(gidset, sizeof(*gidset) * gidsetsize_);") +      pcmd("}") +    } else { +      pcmd("if (res == 0) {") +      pcmd("  unsigned int *gidset = (unsigned int *)gidset_;") +      pcmd("  if (gidset) {") +      pcmd("    POST_WRITE(gidset, sizeof(*gidset) * gidsetsize_);") +      pcmd("  }") +      pcmd("}") +    } +  } else if (syscall == "setgroups") { +    if (mode == "pre") { +      pcmd("unsigned int *gidset = (unsigned int *)gidset_;") +      pcmd("if (gidset) {") +      pcmd("  PRE_READ(gidset, sizeof(*gidset) * gidsetsize_);") +      pcmd("}") +    } else { +      pcmd("if (res == 0) {") +      pcmd("  unsigned int *gidset = (unsigned int *)gidset_;") +      pcmd("  if (gidset) {") +      pcmd("    POST_READ(gidset, sizeof(*gidset) * gidsetsize_);") +      pcmd("  }") +      pcmd("}") +    } +  } else if (syscall == "getpgrp") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "setpgid") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "compat_50_setitimer") { +    pcmd("/* TODO */") +  } else if (syscall == "compat_43_owait") { +    pcmd("/* TODO */") +  } else if (syscall == "compat_12_oswapon") { +    pcmd("/* TODO */") +  } else if (syscall == "compat_50_getitimer") { +    pcmd("/* TODO */") +  } else if (syscall == "compat_43_ogethostname") { +    pcmd("/* TODO */") +  } else if (syscall == "compat_43_osethostname") { +    pcmd("/* TODO */") +  } else if (syscall == "compat_43_ogetdtablesize") { +    pcmd("/* TODO */") +  } else if (syscall == "dup2") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "fcntl") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "compat_50_select") { +    pcmd("/* TODO */") +  } else if (syscall == "fsync") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "setpriority") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "compat_30_socket") { +    pcmd("/* TODO */") +  } else if (syscall == "connect") { +    if (mode == "pre") { +      pcmd("PRE_READ(name_, namelen_);") +    } else { +      pcmd("if (res == 0) {") +      pcmd("  POST_READ(name_, namelen_);") +      pcmd("}") +    } +  } else if (syscall == "compat_43_oaccept") { +    pcmd("/* TODO */") +  } else if (syscall == "getpriority") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "compat_43_osend") { +    pcmd("/* TODO */") +  } else if (syscall == "compat_43_orecv") { +    pcmd("/* TODO */") +  } else if (syscall == "compat_13_sigreturn13") { +    pcmd("/* TODO */") +  } else if (syscall == "bind") { +    if (mode == "pre") { +      pcmd("PRE_READ(name_, namelen_);") +    } else { +      pcmd("if (res == 0) {") +      pcmd("  PRE_READ(name_, namelen_);") +      pcmd("}") +    } +  } else if (syscall == "setsockopt") { +    if (mode == "pre") { +      pcmd("if (val_) {") +      pcmd("  PRE_READ(val_, valsize_);") +      pcmd("}") +    } else { +      pcmd("if (res == 0) {") +      pcmd("  if (val_) {") +      pcmd("    POST_READ(val_, valsize_);") +      pcmd("  }") +      pcmd("}") +    } +  } else if (syscall == "listen") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "compat_43_osigvec") { +    pcmd("/* TODO */") +  } else if (syscall == "compat_43_osigblock") { +    pcmd("/* TODO */") +  } else if (syscall == "compat_43_osigsetmask") { +    pcmd("/* TODO */") +  } else if (syscall == "compat_13_sigsuspend13") { +    pcmd("/* TODO */") +  } else if (syscall == "compat_43_osigstack") { +    pcmd("/* TODO */") +  } else if (syscall == "compat_43_orecvmsg") { +    pcmd("/* TODO */") +  } else if (syscall == "compat_43_osendmsg") { +    pcmd("/* TODO */") +  } else if (syscall == "compat_50_gettimeofday") { +    pcmd("/* TODO */") +  } else if (syscall == "compat_50_getrusage") { +    pcmd("/* TODO */") +  } else if (syscall == "getsockopt") { +    pcmd("/* TODO */") +  } else if (syscall == "readv") { +    if (mode == "pre") { +      pcmd("struct __sanitizer_iovec *iovp = (struct __sanitizer_iovec *)iovp_;") +      pcmd("int i;") +      pcmd("if (iovp) {") +      pcmd("  PRE_READ(iovp, sizeof(struct __sanitizer_iovec) * iovcnt_);") +      pcmd("  for (i = 0; i < iovcnt_; i++) {") +      pcmd("    PRE_WRITE(iovp[i].iov_base, iovp[i].iov_len);") +      pcmd("  }") +      pcmd("}") +    } else { +      pcmd("struct __sanitizer_iovec *iovp = (struct __sanitizer_iovec *)iovp_;") +      pcmd("int i;") +      pcmd("uptr m, n = res;") +      pcmd("if (res > 0) {") +      pcmd("  if (iovp) {") +      pcmd("    POST_READ(iovp, sizeof(struct __sanitizer_iovec) * iovcnt_);") +      pcmd("    for (i = 0; i < iovcnt_ && n > 0; i++) {") +      pcmd("      m = n > iovp[i].iov_len ? iovp[i].iov_len : n;") +      pcmd("      POST_WRITE(iovp[i].iov_base, m);") +      pcmd("      n -= m;") +      pcmd("    }") +      pcmd("  }") +      pcmd("}") +    } +  } else if (syscall == "writev") { +    if (mode == "pre") { +      pcmd("struct __sanitizer_iovec *iovp = (struct __sanitizer_iovec *)iovp_;") +      pcmd("int i;") +      pcmd("if (iovp) {") +      pcmd("  PRE_READ(iovp, sizeof(struct __sanitizer_iovec) * iovcnt_);") +      pcmd("  for (i = 0; i < iovcnt_; i++) {") +      pcmd("    PRE_READ(iovp[i].iov_base, iovp[i].iov_len);") +      pcmd("  }") +      pcmd("}") +    } else { +      pcmd("struct __sanitizer_iovec *iovp = (struct __sanitizer_iovec *)iovp_;") +      pcmd("int i;") +      pcmd("uptr m, n = res;") +      pcmd("if (res > 0) {") +      pcmd("  if (iovp) {") +      pcmd("    POST_READ(iovp, sizeof(struct __sanitizer_iovec) * iovcnt_);") +      pcmd("    for (i = 0; i < iovcnt_ && n > 0; i++) {") +      pcmd("      m = n > iovp[i].iov_len ? iovp[i].iov_len : n;") +      pcmd("      POST_READ(iovp[i].iov_base, m);") +      pcmd("      n -= m;") +      pcmd("    }") +      pcmd("  }") +      pcmd("}") +    } +  } else if (syscall == "compat_50_settimeofday") { +    pcmd("/* TODO */") +  } else if (syscall == "fchown") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "fchmod") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "compat_43_orecvfrom") { +    pcmd("/* TODO */") +  } else if (syscall == "setreuid") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "setregid") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "rename") { +    if (mode == "pre") { +      pcmd("const char *from = (const char *)from_;") +      pcmd("const char *to = (const char *)to_;") +      pcmd("if (from) {") +      pcmd("  PRE_READ(from, __sanitizer::internal_strlen(from) + 1);") +      pcmd("}") +      pcmd("if (to) {") +      pcmd("  PRE_READ(to, __sanitizer::internal_strlen(to) + 1);") +      pcmd("}") +    } else { +      pcmd("if (res == 0) {") +      pcmd("  const char *from = (const char *)from_;") +      pcmd("  const char *to = (const char *)to_;") +      pcmd("  if (from) {") +      pcmd("    POST_READ(from, __sanitizer::internal_strlen(from) + 1);") +      pcmd("  }") +      pcmd("  if (to) {") +      pcmd("    POST_READ(to, __sanitizer::internal_strlen(to) + 1);") +      pcmd("  }") +      pcmd("}") +    } +  } else if (syscall == "compat_43_otruncate") { +    pcmd("/* TODO */") +  } else if (syscall == "compat_43_oftruncate") { +    pcmd("/* TODO */") +  } else if (syscall == "flock") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "mkfifo") { +    if (mode == "pre") { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (path) {") +      pcmd("  PRE_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("}") +    } else { +      pcmd("if (res == 0) {") +      pcmd("  const char *path = (const char *)path_;") +      pcmd("  if (path) {") +      pcmd("    POST_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("  }") +      pcmd("}") +    } +  } else if (syscall == "sendto") { +    if (mode == "pre") { +      pcmd("PRE_READ(buf_, len_);") +      pcmd("PRE_READ(to_, tolen_);") +    } else { +      pcmd("if (res >= 0) {") +      pcmd("  POST_READ(buf_, len_);") +      pcmd("  POST_READ(to_, tolen_);") +      pcmd("}") +    } +  } else if (syscall == "shutdown") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "socketpair") { +    if (mode == "pre") { +      pcmd("PRE_WRITE(rsv_, 2 * sizeof(int));") +    } else { +      pcmd("if (res == 0) {") +      pcmd("  POST_WRITE(rsv_, 2 * sizeof(int));") +      pcmd("}") +    } +  } else if (syscall == "mkdir") { +    if (mode == "pre") { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (path) {") +      pcmd("  PRE_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("}") +    } else { +      pcmd("if (res == 0) {") +      pcmd("  const char *path = (const char *)path_;") +      pcmd("  if (path) {") +      pcmd("    POST_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("  }") +      pcmd("}") +    } +  } else if (syscall == "rmdir") { +    if (mode == "pre") { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (path) {") +      pcmd("  PRE_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("}") +    } else { +      pcmd("if (res == 0) {") +      pcmd("  const char *path = (const char *)path_;") +      pcmd("  if (path) {") +      pcmd("    POST_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("  }") +      pcmd("}") +    } +  } else if (syscall == "compat_50_utimes") { +    pcmd("/* TODO */") +  } else if (syscall == "compat_50_adjtime") { +    pcmd("/* TODO */") +  } else if (syscall == "compat_43_ogetpeername") { +    pcmd("/* TODO */") +  } else if (syscall == "compat_43_ogethostid") { +    pcmd("/* TODO */") +  } else if (syscall == "compat_43_osethostid") { +    pcmd("/* TODO */") +  } else if (syscall == "compat_43_ogetrlimit") { +    pcmd("/* TODO */") +  } else if (syscall == "compat_43_osetrlimit") { +    pcmd("/* TODO */") +  } else if (syscall == "compat_43_okillpg") { +    pcmd("/* TODO */") +  } else if (syscall == "setsid") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "compat_50_quotactl") { +    pcmd("/* TODO */") +  } else if (syscall == "compat_43_oquota") { +    pcmd("/* TODO */") +  } else if (syscall == "compat_43_ogetsockname") { +    pcmd("/* TODO */") +  } else if (syscall == "nfssvc") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "compat_43_ogetdirentries") { +    pcmd("/* TODO */") +  } else if (syscall == "compat_20_statfs") { +    pcmd("/* TODO */") +  } else if (syscall == "compat_20_fstatfs") { +    pcmd("/* TODO */") +  } else if (syscall == "compat_30_getfh") { +    pcmd("/* TODO */") +  } else if (syscall == "compat_09_ogetdomainname") { +    pcmd("/* TODO */") +  } else if (syscall == "compat_09_osetdomainname") { +    pcmd("/* TODO */") +  } else if (syscall == "compat_09_ouname") { +    pcmd("/* TODO */") +  } else if (syscall == "sysarch") { +    pcmd("/* TODO */") +  } else if (syscall == "compat_10_osemsys") { +    pcmd("/* TODO */") +  } else if (syscall == "compat_10_omsgsys") { +    pcmd("/* TODO */") +  } else if (syscall == "compat_10_oshmsys") { +    pcmd("/* TODO */") +  } else if (syscall == "pread") { +    if (mode == "pre") { +      pcmd("if (buf_) {") +      pcmd("  PRE_WRITE(buf_, nbyte_);") +      pcmd("}") +    } else { +      pcmd("if (res > 0) {") +      pcmd("  POST_WRITE(buf_, res);") +      pcmd("}") +    } +  } else if (syscall == "pwrite") { +    if (mode == "pre") { +      pcmd("if (buf_) {") +      pcmd("  PRE_READ(buf_, nbyte_);") +      pcmd("}") +    } else { +      pcmd("if (res > 0) {") +      pcmd("  POST_READ(buf_, res);") +      pcmd("}") +    } +  } else if (syscall == "compat_30_ntp_gettime") { +    pcmd("/* TODO */") +  } else if (syscall == "ntp_adjtime") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "setgid") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "setegid") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "seteuid") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "lfs_bmapv") { +    pcmd("/* TODO */") +  } else if (syscall == "lfs_markv") { +    pcmd("/* TODO */") +  } else if (syscall == "lfs_segclean") { +    pcmd("/* TODO */") +  } else if (syscall == "compat_50_lfs_segwait") { +    pcmd("/* TODO */") +  } else if (syscall == "compat_12_stat12") { +    pcmd("/* TODO */") +  } else if (syscall == "compat_12_fstat12") { +    pcmd("/* TODO */") +  } else if (syscall == "compat_12_lstat12") { +    pcmd("/* TODO */") +  } else if (syscall == "pathconf") { +    if (mode == "pre") { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (path) {") +      pcmd("  PRE_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("}") +    } else { +      pcmd("if (res != -1) {") +      pcmd("  const char *path = (const char *)path_;") +      pcmd("  if (path) {") +      pcmd("    POST_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("  }") +      pcmd("}") +    } +  } else if (syscall == "fpathconf") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "getrlimit") { +    if (mode == "pre") { +      pcmd("PRE_WRITE(rlp_, struct_rlimit_sz);") +    } else { +      pcmd("if (res == 0) {") +      pcmd("  POST_WRITE(rlp_, struct_rlimit_sz);") +      pcmd("}") +    } +  } else if (syscall == "setrlimit") { +    if (mode == "pre") { +      pcmd("PRE_READ(rlp_, struct_rlimit_sz);") +    } else { +      pcmd("if (res == 0) {") +      pcmd("  POST_READ(rlp_, struct_rlimit_sz);") +      pcmd("}") +    } +  } else if (syscall == "compat_12_getdirentries") { +    pcmd("/* TODO */") +  } else if (syscall == "mmap") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "__syscall") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "lseek") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "truncate") { +    if (mode == "pre") { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (path) {") +      pcmd("  PRE_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("}") +    } else { +      pcmd("if (res == 0) {") +      pcmd("  const char *path = (const char *)path_;") +      pcmd("  if (path) {") +      pcmd("    POST_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("  }") +      pcmd("}") +    } +  } else if (syscall == "ftruncate") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "__sysctl") { +    if (mode == "pre") { +      pcmd("const int *name = (const int *)name_;") +      pcmd("if (name) {") +      pcmd("  PRE_READ(name, namelen_ * sizeof(*name));") +      pcmd("}") +      pcmd("if (newv_) {") +      pcmd("  PRE_READ(name, newlen_);") +      pcmd("}") +    } else { +      pcmd("if (res == 0) {") +      pcmd("  const int *name = (const int *)name_;") +      pcmd("  if (name) {") +      pcmd("    POST_READ(name, namelen_ * sizeof(*name));") +      pcmd("  }") +      pcmd("  if (newv_) {") +      pcmd("    POST_READ(name, newlen_);") +      pcmd("  }") +      pcmd("}") +    } +  } else if (syscall == "mlock") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "munlock") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "undelete") { +    if (mode == "pre") { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (path) {") +      pcmd("  PRE_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("}") +    } else { +      pcmd("if (res == 0) {") +      pcmd("  const char *path = (const char *)path_;") +      pcmd("  if (path) {") +      pcmd("    POST_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("  }") +      pcmd("}") +    } +  } else if (syscall == "compat_50_futimes") { +    pcmd("/* TODO */") +  } else if (syscall == "getpgid") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "reboot") { +    if (mode == "pre") { +      pcmd("const char *bootstr = (const char *)bootstr_;") +      pcmd("if (bootstr) {") +      pcmd("  PRE_READ(bootstr, __sanitizer::internal_strlen(bootstr) + 1);") +      pcmd("}") +    } else { +      pcmd("/* This call should never return */") +      pcmd("const char *bootstr = (const char *)bootstr_;") +      pcmd("if (bootstr) {") +      pcmd("  POST_READ(bootstr, __sanitizer::internal_strlen(bootstr) + 1);") +      pcmd("}") +    } +  } else if (syscall == "poll") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "afssys") { +    pcmd("/* TODO */") +  } else if (syscall == "compat_14___semctl") { +    pcmd("/* TODO */") +  } else if (syscall == "semget") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "semop") { +    if (mode == "pre") { +      pcmd("if (sops_) {") +      pcmd("  PRE_READ(sops_, nsops_ * struct_sembuf_sz);") +      pcmd("}") +    } else { +      pcmd("if (res == 0) {") +      pcmd("  if (sops_) {") +      pcmd("    POST_READ(sops_, nsops_ * struct_sembuf_sz);") +      pcmd("  }") +      pcmd("}") +    } +  } else if (syscall == "semconfig") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "compat_14_msgctl") { +    pcmd("/* TODO */") +  } else if (syscall == "msgget") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "msgsnd") { +    if (mode == "pre") { +      pcmd("if (msgp_) {") +      pcmd("  PRE_READ(msgp_, msgsz_);") +      pcmd("}") +    } else { +      pcmd("if (res == 0) {") +      pcmd("  if (msgp_) {") +      pcmd("    POST_READ(msgp_, msgsz_);") +      pcmd("  }") +      pcmd("}") +    } +  } else if (syscall == "msgrcv") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "shmat") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "compat_14_shmctl") { +    pcmd("/* TODO */") +  } else if (syscall == "shmdt") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "shmget") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "compat_50_clock_gettime") { +    pcmd("/* TODO */") +  } else if (syscall == "compat_50_clock_settime") { +    pcmd("/* TODO */") +  } else if (syscall == "compat_50_clock_getres") { +    pcmd("/* TODO */") +  } else if (syscall == "timer_create") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "timer_delete") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "compat_50_timer_settime") { +    pcmd("/* TODO */") +  } else if (syscall == "compat_50_timer_gettime") { +    pcmd("/* TODO */") +  } else if (syscall == "timer_getoverrun") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "compat_50_nanosleep") { +    pcmd("/* TODO */") +  } else if (syscall == "fdatasync") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "mlockall") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "munlockall") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "compat_50___sigtimedwait") { +    pcmd("/* TODO */") +  } else if (syscall == "sigqueueinfo") { +    if (mode == "pre") { +      pcmd("if (info_) {") +      pcmd("  PRE_READ(info_, siginfo_t_sz);") +      pcmd("}") +    } +  } else if (syscall == "modctl") { +    pcmd("/* TODO */") +  } else if (syscall == "_ksem_init") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "_ksem_open") { +    if (mode == "pre") { +      pcmd("const char *name = (const char *)name_;") +      pcmd("if (name) {") +      pcmd("  PRE_READ(name, __sanitizer::internal_strlen(name) + 1);") +      pcmd("}") +    } else { +      pcmd("const char *name = (const char *)name_;") +      pcmd("if (name) {") +      pcmd("  POST_READ(name, __sanitizer::internal_strlen(name) + 1);") +      pcmd("}") +    } +  } else if (syscall == "_ksem_unlink") { +    if (mode == "pre") { +      pcmd("const char *name = (const char *)name_;") +      pcmd("if (name) {") +      pcmd("  PRE_READ(name, __sanitizer::internal_strlen(name) + 1);") +      pcmd("}") +    } else { +      pcmd("const char *name = (const char *)name_;") +      pcmd("if (name) {") +      pcmd("  POST_READ(name, __sanitizer::internal_strlen(name) + 1);") +      pcmd("}") +    } +  } else if (syscall == "_ksem_close") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "_ksem_post") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "_ksem_wait") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "_ksem_trywait") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "_ksem_getvalue") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "_ksem_destroy") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "_ksem_timedwait") { +    if (mode == "pre") { +      pcmd("if (abstime_) {") +      pcmd("  PRE_READ(abstime_, struct_timespec_sz);") +      pcmd("}") +    } +  } else if (syscall == "mq_open") { +    if (mode == "pre") { +      pcmd("const char *name = (const char *)name_;") +      pcmd("if (name) {") +      pcmd("  PRE_READ(name, __sanitizer::internal_strlen(name) + 1);") +      pcmd("}") +    } else { +      pcmd("const char *name = (const char *)name_;") +      pcmd("if (name) {") +      pcmd("  POST_READ(name, __sanitizer::internal_strlen(name) + 1);") +      pcmd("}") +    } +  } else if (syscall == "mq_close") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "mq_unlink") { +    if (mode == "pre") { +      pcmd("const char *name = (const char *)name_;") +      pcmd("if (name) {") +      pcmd("  PRE_READ(name, __sanitizer::internal_strlen(name) + 1);") +      pcmd("}") +    } else { +      pcmd("const char *name = (const char *)name_;") +      pcmd("if (name) {") +      pcmd("  POST_READ(name, __sanitizer::internal_strlen(name) + 1);") +      pcmd("}") +    } +  } else if (syscall == "mq_getattr") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "mq_setattr") { +    if (mode == "pre") { +      pcmd("if (mqstat_) {") +      pcmd("  PRE_READ(mqstat_, struct_mq_attr_sz);") +      pcmd("}") +    } +  } else if (syscall == "mq_notify") { +    if (mode == "pre") { +      pcmd("if (notification_) {") +      pcmd("  PRE_READ(notification_, struct_sigevent_sz);") +      pcmd("}") +    } +  } else if (syscall == "mq_send") { +    if (mode == "pre") { +      pcmd("if (msg_ptr_) {") +      pcmd("  PRE_READ(msg_ptr_, msg_len_);") +      pcmd("}") +    } +  } else if (syscall == "mq_receive") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "compat_50_mq_timedsend") { +    pcmd("/* TODO */") +  } else if (syscall == "compat_50_mq_timedreceive") { +    pcmd("/* TODO */") +  } else if (syscall == "__posix_rename") { +    if (mode == "pre") { +      pcmd("const char *from = (const char *)from_;") +      pcmd("const char *to = (const char *)to_;") +      pcmd("if (from_) {") +      pcmd("  PRE_READ(from, __sanitizer::internal_strlen(from) + 1);") +      pcmd("}") +      pcmd("if (to) {") +      pcmd("  PRE_READ(to, __sanitizer::internal_strlen(to) + 1);") +      pcmd("}") +    } else { +      pcmd("const char *from = (const char *)from_;") +      pcmd("const char *to = (const char *)to_;") +      pcmd("if (from) {") +      pcmd("  POST_READ(from, __sanitizer::internal_strlen(from) + 1);") +      pcmd("}") +      pcmd("if (to) {") +      pcmd("  POST_READ(to, __sanitizer::internal_strlen(to) + 1);") +      pcmd("}") +    } +  } else if (syscall == "swapctl") { +    pcmd("/* TODO */") +  } else if (syscall == "compat_30_getdents") { +    pcmd("/* TODO */") +  } else if (syscall == "minherit") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "lchmod") { +    if (mode == "pre") { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (path) {") +      pcmd("  PRE_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("}") +    } else { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (path) {") +      pcmd("  POST_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("}") +    } +  } else if (syscall == "lchown") { +    if (mode == "pre") { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (path) {") +      pcmd("  PRE_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("}") +    } else { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (path) {") +      pcmd("  POST_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("}") +    } +  } else if (syscall == "compat_50_lutimes") { +    pcmd("/* TODO */") +  } else if (syscall == "__msync13") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "compat_30___stat13") { +    pcmd("/* TODO */") +  } else if (syscall == "compat_30___fstat13") { +    pcmd("/* TODO */") +  } else if (syscall == "compat_30___lstat13") { +    pcmd("/* TODO */") +  } else if (syscall == "__sigaltstack14") { +    if (mode == "pre") { +      pcmd("if (nss_) {") +      pcmd("  PRE_READ(nss_, struct_sigaltstack_sz);") +      pcmd("}") +      pcmd("if (oss_) {") +      pcmd("  PRE_READ(oss_, struct_sigaltstack_sz);") +      pcmd("}") +    } +  } else if (syscall == "__vfork14") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "__posix_chown") { +    if (mode == "pre") { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (path) {") +      pcmd("  PRE_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("}") +    } else { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (path) {") +      pcmd("  POST_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("}") +    } +  } else if (syscall == "__posix_fchown") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "__posix_lchown") { +    if (mode == "pre") { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (path) {") +      pcmd("  PRE_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("}") +    } else { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (path) {") +      pcmd("  POST_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("}") +    } +  } else if (syscall == "getsid") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "__clone") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "fktrace") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "preadv") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "pwritev") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "compat_16___sigaction14") { +    pcmd("/* TODO */") +  } else if (syscall == "__sigpending14") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "__sigprocmask14") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "__sigsuspend14") { +    pcmd("if (set_) {") +    pcmd("  PRE_READ(set_, sizeof(__sanitizer_sigset_t));") +    pcmd("}") +  } else if (syscall == "compat_16___sigreturn14") { +    pcmd("/* TODO */") +  } else if (syscall == "__getcwd") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "fchroot") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "compat_30_fhopen") { +    pcmd("/* TODO */") +  } else if (syscall == "compat_30_fhstat") { +    pcmd("/* TODO */") +  } else if (syscall == "compat_20_fhstatfs") { +    pcmd("/* TODO */") +  } else if (syscall == "compat_50_____semctl13") { +    pcmd("/* TODO */") +  } else if (syscall == "compat_50___msgctl13") { +    pcmd("/* TODO */") +  } else if (syscall == "compat_50___shmctl13") { +    pcmd("/* TODO */") +  } else if (syscall == "lchflags") { +    if (mode == "pre") { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (path) {") +      pcmd("  PRE_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("}") +    } else { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (path) {") +      pcmd("  POST_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("}") +    } +  } else if (syscall == "issetugid") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "utrace") { +    if (mode == "pre") { +      pcmd("const char *label = (const char *)label_;") +      pcmd("if (label) {") +      pcmd("  PRE_READ(label, __sanitizer::internal_strlen(label) + 1);") +      pcmd("}") +      pcmd("if (addr_) {") +      pcmd("  PRE_READ(addr_, len_);") +      pcmd("}") +    } else { +      pcmd("const char *label = (const char *)label_;") +      pcmd("if (label) {") +      pcmd("  POST_READ(label, __sanitizer::internal_strlen(label) + 1);") +      pcmd("}") +      pcmd("if (addr_) {") +      pcmd("  POST_READ(addr_, len_);") +      pcmd("}") +    } +  } else if (syscall == "getcontext") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "setcontext") { +    if (mode == "pre") { +      pcmd("if (ucp_) {") +      pcmd("  PRE_READ(ucp_, ucontext_t_sz);") +      pcmd("}") +    } +  } else if (syscall == "_lwp_create") { +    if (mode == "pre") { +      pcmd("if (ucp_) {") +      pcmd("  PRE_READ(ucp_, ucontext_t_sz);") +      pcmd("}") +    } +  } else if (syscall == "_lwp_exit") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "_lwp_self") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "_lwp_wait") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "_lwp_suspend") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "_lwp_continue") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "_lwp_wakeup") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "_lwp_getprivate") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "_lwp_setprivate") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "_lwp_kill") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "_lwp_detach") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "compat_50__lwp_park") { +    pcmd("/* TODO */") +  } else if (syscall == "_lwp_unpark") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "_lwp_unpark_all") { +    if (mode == "pre") { +      pcmd("if (targets_) {") +      pcmd("  PRE_READ(targets_, ntargets_ * sizeof(__sanitizer_lwpid_t));") +      pcmd("}") +    } +  } else if (syscall == "_lwp_setname") { +    if (mode == "pre") { +      pcmd("const char *name = (const char *)name_;") +      pcmd("if (name) {") +      pcmd("  PRE_READ(name, __sanitizer::internal_strlen(name) + 1);") +      pcmd("}") +    } else { +      pcmd("const char *name = (const char *)name_;") +      pcmd("if (name) {") +      pcmd("  POST_READ(name, __sanitizer::internal_strlen(name) + 1);") +      pcmd("}") +    } +  } else if (syscall == "_lwp_getname") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "_lwp_ctl") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "compat_60_sa_register") { +    pcmd("/* TODO */") +  } else if (syscall == "compat_60_sa_stacks") { +    pcmd("/* TODO */") +  } else if (syscall == "compat_60_sa_enable") { +    pcmd("/* TODO */") +  } else if (syscall == "compat_60_sa_setconcurrency") { +    pcmd("/* TODO */") +  } else if (syscall == "compat_60_sa_yield") { +    pcmd("/* TODO */") +  } else if (syscall == "compat_60_sa_preempt") { +    pcmd("/* TODO */") +  } else if (syscall == "__sigaction_sigtramp") { +    pcmd("if (nsa_) {") +    pcmd("  PRE_READ(nsa_, sizeof(__sanitizer_sigaction));") +    pcmd("}") +  } else if (syscall == "pmc_get_info") { +    pcmd("/* TODO */") +  } else if (syscall == "pmc_control") { +    pcmd("/* TODO */") +  } else if (syscall == "rasctl") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "kqueue") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "compat_50_kevent") { +    pcmd("/* TODO */") +  } else if (syscall == "_sched_setparam") { +    pcmd("if (params_) {") +    pcmd("  PRE_READ(params_, struct_sched_param_sz);") +    pcmd("}") +  } else if (syscall == "_sched_getparam") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "_sched_setaffinity") { +    pcmd("if (cpuset_) {") +    pcmd("  PRE_READ(cpuset_, size_);") +    pcmd("}") +  } else if (syscall == "_sched_getaffinity") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "sched_yield") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "_sched_protect") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "fsync_range") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "uuidgen") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "getvfsstat") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "statvfs1") { +    if (mode == "pre") { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (path) {") +      pcmd("  PRE_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("}") +    } else { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (path) {") +      pcmd("  POST_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("}") +    } +  } else if (syscall == "fstatvfs1") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "compat_30_fhstatvfs1") { +    pcmd("/* TODO */") +  } else if (syscall == "extattrctl") { +    if (mode == "pre") { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (path) {") +      pcmd("  PRE_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("}") +    } else { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (path) {") +      pcmd("  POST_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("}") +    } +  } else if (syscall == "extattr_set_file") { +    if (mode == "pre") { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (path) {") +      pcmd("  PRE_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("}") +    } else { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (path) {") +      pcmd("  POST_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("}") +    } +  } else if (syscall == "extattr_get_file") { +    if (mode == "pre") { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (path) {") +      pcmd("  PRE_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("}") +    } else { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (path) {") +      pcmd("  POST_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("}") +    } +  } else if (syscall == "extattr_delete_file") { +    if (mode == "pre") { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (path) {") +      pcmd("  PRE_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("}") +    } else { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (path) {") +      pcmd("  POST_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("}") +    } +  } else if (syscall == "extattr_set_fd") { +    pcmd("/* TODO */") +  } else if (syscall == "extattr_get_fd") { +    pcmd("/* TODO */") +  } else if (syscall == "extattr_delete_fd") { +    pcmd("/* TODO */") +  } else if (syscall == "extattr_set_link") { +    if (mode == "pre") { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (path) {") +      pcmd("  PRE_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("}") +    } else { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (path) {") +      pcmd("  POST_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("}") +    } +  } else if (syscall == "extattr_get_link") { +    if (mode == "pre") { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (path) {") +      pcmd("  PRE_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("}") +    } else { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (path) {") +      pcmd("  POST_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("}") +    } +  } else if (syscall == "extattr_delete_link") { +    if (mode == "pre") { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (path) {") +      pcmd("  PRE_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("}") +    } else { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (path) {") +      pcmd("  POST_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("}") +    } +  } else if (syscall == "extattr_list_fd") { +    pcmd("/* TODO */") +  } else if (syscall == "extattr_list_file") { +    if (mode == "pre") { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (path) {") +      pcmd("  PRE_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("}") +    } else { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (path) {") +      pcmd("  POST_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("}") +    } +  } else if (syscall == "extattr_list_link") { +    if (mode == "pre") { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (path) {") +      pcmd("  PRE_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("}") +    } else { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (path) {") +      pcmd("  POST_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("}") +    } +  } else if (syscall == "compat_50_pselect") { +    pcmd("/* TODO */") +  } else if (syscall == "compat_50_pollts") { +    pcmd("/* TODO */") +  } else if (syscall == "setxattr") { +    if (mode == "pre") { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (path) {") +      pcmd("  PRE_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("}") +    } else { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (path) {") +      pcmd("  POST_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("}") +    } +  } else if (syscall == "lsetxattr") { +    if (mode == "pre") { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (path) {") +      pcmd("  PRE_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("}") +    } else { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (path) {") +      pcmd("  POST_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("}") +    } +  } else if (syscall == "fsetxattr") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "getxattr") { +    if (mode == "pre") { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (path) {") +      pcmd("  PRE_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("}") +    } else { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (path) {") +      pcmd("  POST_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("}") +    } +  } else if (syscall == "lgetxattr") { +    if (mode == "pre") { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (path) {") +      pcmd("  PRE_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("}") +    } else { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (path) {") +      pcmd("  POST_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("}") +    } +  } else if (syscall == "fgetxattr") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "listxattr") { +    if (mode == "pre") { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (path) {") +      pcmd("  PRE_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("}") +    } else { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (path) {") +      pcmd("  POST_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("}") +    } +  } else if (syscall == "llistxattr") { +    if (mode == "pre") { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (path) {") +      pcmd("  PRE_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("}") +    } else { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (path) {") +      pcmd("  POST_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("}") +    } +  } else if (syscall == "flistxattr") { +    pcmd("/* TODO */") +  } else if (syscall == "removexattr") { +    if (mode == "pre") { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (path) {") +      pcmd("  PRE_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("}") +    } else { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (path) {") +      pcmd("  POST_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("}") +    } +  } else if (syscall == "lremovexattr") { +    if (mode == "pre") { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (path) {") +      pcmd("  PRE_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("}") +    } else { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (path) {") +      pcmd("  POST_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("}") +    } +  } else if (syscall == "fremovexattr") { +    pcmd("/* TODO */") +  } else if (syscall == "compat_50___stat30") { +    pcmd("/* TODO */") +  } else if (syscall == "compat_50___fstat30") { +    pcmd("/* TODO */") +  } else if (syscall == "compat_50___lstat30") { +    pcmd("/* TODO */") +  } else if (syscall == "__getdents30") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "posix_fadvise") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "compat_30___fhstat30") { +    pcmd("/* TODO */") +  } else if (syscall == "compat_50___ntp_gettime30") { +    pcmd("/* TODO */") +  } else if (syscall == "__socket30") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "__getfh30") { +    if (mode == "pre") { +      pcmd("const char *fname = (const char *)fname_;") +      pcmd("if (fname) {") +      pcmd("  PRE_READ(fname, __sanitizer::internal_strlen(fname) + 1);") +      pcmd("}") +    } else { +      pcmd("const char *fname = (const char *)fname_;") +      pcmd("if (res == 0) {") +      pcmd("  if (fname) {") +      pcmd("    POST_READ(fname, __sanitizer::internal_strlen(fname) + 1);") +      pcmd("  }") +      pcmd("}") +    } +  } else if (syscall == "__fhopen40") { +    if (mode == "pre") { +      pcmd("if (fhp_) {") +      pcmd("  PRE_READ(fhp_, fh_size_);") +      pcmd("}") +    } +  } else if (syscall == "__fhstatvfs140") { +    if (mode == "pre") { +      pcmd("if (fhp_) {") +      pcmd("  PRE_READ(fhp_, fh_size_);") +      pcmd("}") +    } +  } else if (syscall == "compat_50___fhstat40") { +    if (mode == "pre") { +      pcmd("if (fhp_) {") +      pcmd("  PRE_READ(fhp_, fh_size_);") +      pcmd("}") +    } +  } else if (syscall == "aio_cancel") { +    if (mode == "pre") { +      pcmd("if (aiocbp_) {") +      pcmd("  PRE_READ(aiocbp_, sizeof(struct __sanitizer_aiocb));") +      pcmd("}") +    } +  } else if (syscall == "aio_error") { +    if (mode == "pre") { +      pcmd("if (aiocbp_) {") +      pcmd("  PRE_READ(aiocbp_, sizeof(struct __sanitizer_aiocb));") +      pcmd("}") +    } +  } else if (syscall == "aio_fsync") { +    if (mode == "pre") { +      pcmd("if (aiocbp_) {") +      pcmd("  PRE_READ(aiocbp_, sizeof(struct __sanitizer_aiocb));") +      pcmd("}") +    } +  } else if (syscall == "aio_read") { +    if (mode == "pre") { +      pcmd("if (aiocbp_) {") +      pcmd("  PRE_READ(aiocbp_, sizeof(struct __sanitizer_aiocb));") +      pcmd("}") +    } +  } else if (syscall == "aio_return") { +    if (mode == "pre") { +      pcmd("if (aiocbp_) {") +      pcmd("  PRE_READ(aiocbp_, sizeof(struct __sanitizer_aiocb));") +      pcmd("}") +    } +  } else if (syscall == "compat_50_aio_suspend") { +    pcmd("/* TODO */") +  } else if (syscall == "aio_write") { +    if (mode == "pre") { +      pcmd("if (aiocbp_) {") +      pcmd("  PRE_READ(aiocbp_, sizeof(struct __sanitizer_aiocb));") +      pcmd("}") +    } +  } else if (syscall == "lio_listio") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "__mount50") { +    if (mode == "pre") { +      pcmd("const char *type = (const char *)type_;") +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (type) {") +      pcmd("  PRE_READ(type, __sanitizer::internal_strlen(type) + 1);") +      pcmd("}") +      pcmd("if (path) {") +      pcmd("  PRE_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("}") +      pcmd("if (data_) {") +      pcmd("  PRE_READ(data_, data_len_);") +      pcmd("}") +    } else { +      pcmd("const char *type = (const char *)type_;") +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (type) {") +      pcmd("  POST_READ(type, __sanitizer::internal_strlen(type) + 1);") +      pcmd("}") +      pcmd("if (path) {") +      pcmd("  POST_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("}") +      pcmd("if (data_) {") +      pcmd("  POST_READ(data_, data_len_);") +      pcmd("}") +    } +  } else if (syscall == "mremap") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "pset_create") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "pset_destroy") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "pset_assign") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "_pset_bind") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "__posix_fadvise50") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "__select50") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "__gettimeofday50") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "__settimeofday50") { +    if (mode == "pre") { +      pcmd("if (tv_) {") +      pcmd("  PRE_READ(tv_, timeval_sz);") +      pcmd("}") +      pcmd("if (tzp_) {") +      pcmd("  PRE_READ(tzp_, struct_timezone_sz);") +      pcmd("}") +    } +  } else if (syscall == "__utimes50") { +    if (mode == "pre") { +      pcmd("struct __sanitizer_timespec **tptr = (struct __sanitizer_timespec **)tptr_;") +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (path) {") +      pcmd("  PRE_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("}") +      pcmd("if (tptr) {") +      pcmd("  PRE_READ(tptr[0], struct_timespec_sz);") +      pcmd("  PRE_READ(tptr[1], struct_timespec_sz);") +      pcmd("}") +    } +  } else if (syscall == "__adjtime50") { +    if (mode == "pre") { +      pcmd("if (delta_) {") +      pcmd("  PRE_READ(delta_, timeval_sz);") +      pcmd("}") +    } +  } else if (syscall == "__lfs_segwait50") { +    pcmd("/* TODO */") +  } else if (syscall == "__futimes50") { +    if (mode == "pre") { +      pcmd("struct __sanitizer_timespec **tptr = (struct __sanitizer_timespec **)tptr_;") +      pcmd("if (tptr) {") +      pcmd("  PRE_READ(tptr[0], struct_timespec_sz);") +      pcmd("  PRE_READ(tptr[1], struct_timespec_sz);") +      pcmd("}") +    } +  } else if (syscall == "__lutimes50") { +    if (mode == "pre") { +      pcmd("struct __sanitizer_timespec **tptr = (struct __sanitizer_timespec **)tptr_;") +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (path) {") +      pcmd("  PRE_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("}") +      pcmd("if (tptr) {") +      pcmd("  PRE_READ(tptr[0], struct_timespec_sz);") +      pcmd("  PRE_READ(tptr[1], struct_timespec_sz);") +      pcmd("}") +    } else { +      pcmd("struct __sanitizer_timespec **tptr = (struct __sanitizer_timespec **)tptr_;") +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (path) {") +      pcmd("  POST_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("}") +      pcmd("if (tptr) {") +      pcmd("  POST_READ(tptr[0], struct_timespec_sz);") +      pcmd("  POST_READ(tptr[1], struct_timespec_sz);") +      pcmd("}") +    } +  } else if (syscall == "__setitimer50") { +    if (mode == "pre") { +      pcmd("struct __sanitizer_itimerval *itv = (struct __sanitizer_itimerval *)itv_;") +      pcmd("if (itv) {") +      pcmd("  PRE_READ(&itv->it_interval.tv_sec, sizeof(__sanitizer_time_t));") +      pcmd("  PRE_READ(&itv->it_interval.tv_usec, sizeof(__sanitizer_suseconds_t));") +      pcmd("  PRE_READ(&itv->it_value.tv_sec, sizeof(__sanitizer_time_t));") +      pcmd("  PRE_READ(&itv->it_value.tv_usec, sizeof(__sanitizer_suseconds_t));") +      pcmd("}") +    } +  } else if (syscall == "__getitimer50") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "__clock_gettime50") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "__clock_settime50") { +    if (mode == "pre") { +      pcmd("if (tp_) {") +      pcmd("  PRE_READ(tp_, struct_timespec_sz);") +      pcmd("}") +    } +  } else if (syscall == "__clock_getres50") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "__nanosleep50") { +    if (mode == "pre") { +      pcmd("if (rqtp_) {") +      pcmd("  PRE_READ(rqtp_, struct_timespec_sz);") +      pcmd("}") +    } +  } else if (syscall == "____sigtimedwait50") { +    if (mode == "pre") { +      pcmd("if (set_) {") +      pcmd("  PRE_READ(set_, sizeof(__sanitizer_sigset_t));") +      pcmd("}") +      pcmd("if (timeout_) {") +      pcmd("  PRE_READ(timeout_, struct_timespec_sz);") +      pcmd("}") +    } +  } else if (syscall == "__mq_timedsend50") { +    if (mode == "pre") { +      pcmd("if (msg_ptr_) {") +      pcmd("  PRE_READ(msg_ptr_, msg_len_);") +      pcmd("}") +      pcmd("if (abs_timeout_) {") +      pcmd("  PRE_READ(abs_timeout_, struct_timespec_sz);") +      pcmd("}") +    } +  } else if (syscall == "__mq_timedreceive50") { +    if (mode == "pre") { +      pcmd("if (msg_ptr_) {") +      pcmd("  PRE_READ(msg_ptr_, msg_len_);") +      pcmd("}") +      pcmd("if (abs_timeout_) {") +      pcmd("  PRE_READ(abs_timeout_, struct_timespec_sz);") +      pcmd("}") +    } +  } else if (syscall == "compat_60__lwp_park") { +    pcmd("/* TODO */") +  } else if (syscall == "__kevent50") { +    if (mode == "pre") { +      pcmd("if (changelist_) {") +      pcmd("  PRE_READ(changelist_, nchanges_ * struct_kevent_sz);") +      pcmd("}") +      pcmd("if (timeout_) {") +      pcmd("  PRE_READ(timeout_, struct_timespec_sz);") +      pcmd("}") +    } +  } else if (syscall == "__pselect50") { +    if (mode == "pre") { +      pcmd("if (ts_) {") +      pcmd("  PRE_READ(ts_, struct_timespec_sz);") +      pcmd("}") +      pcmd("if (mask_) {") +      pcmd("  PRE_READ(mask_, sizeof(struct __sanitizer_sigset_t));") +      pcmd("}") +    } +  } else if (syscall == "__pollts50") { +    if (mode == "pre") { +      pcmd("if (ts_) {") +      pcmd("  PRE_READ(ts_, struct_timespec_sz);") +      pcmd("}") +      pcmd("if (mask_) {") +      pcmd("  PRE_READ(mask_, sizeof(struct __sanitizer_sigset_t));") +      pcmd("}") +    } +  } else if (syscall == "__aio_suspend50") { +    if (mode == "pre") { +      pcmd("int i;") +      pcmd("const struct aiocb * const *list = (const struct aiocb * const *)list_;") +      pcmd("if (list) {") +      pcmd("  for (i = 0; i < nent_; i++) {") +      pcmd("    if (list[i]) {") +      pcmd("      PRE_READ(list[i], sizeof(struct __sanitizer_aiocb));") +      pcmd("    }") +      pcmd("  }") +      pcmd("}") +      pcmd("if (timeout_) {") +      pcmd("  PRE_READ(timeout_, struct_timespec_sz);") +      pcmd("}") +    } +  } else if (syscall == "__stat50") { +    if (mode == "pre") { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (path) {") +      pcmd("  PRE_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("}") +    } else { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (res == 0) {") +      pcmd("  if (path) {") +      pcmd("    POST_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("  }") +      pcmd("}") +    } +  } else if (syscall == "__fstat50") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "__lstat50") { +    if (mode == "pre") { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (path) {") +      pcmd("  PRE_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("}") +    } else { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (res == 0) {") +      pcmd("  if (path) {") +      pcmd("    POST_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("  }") +      pcmd("}") +    } +  } else if (syscall == "____semctl50") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "__shmctl50") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "__msgctl50") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "__getrusage50") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "__timer_settime50") { +    if (mode == "pre") { +      pcmd("struct __sanitizer_itimerval *value = (struct __sanitizer_itimerval *)value_;") +      pcmd("if (value) {") +      pcmd("  PRE_READ(&value->it_interval.tv_sec, sizeof(__sanitizer_time_t));") +      pcmd("  PRE_READ(&value->it_interval.tv_usec, sizeof(__sanitizer_suseconds_t));") +      pcmd("  PRE_READ(&value->it_value.tv_sec, sizeof(__sanitizer_time_t));") +      pcmd("  PRE_READ(&value->it_value.tv_usec, sizeof(__sanitizer_suseconds_t));") +      pcmd("}") +    } else { +      pcmd("struct __sanitizer_itimerval *value = (struct __sanitizer_itimerval *)value_;") +      pcmd("if (res == 0) {") +      pcmd("  if (value) {") +      pcmd("    POST_READ(&value->it_interval.tv_sec, sizeof(__sanitizer_time_t));") +      pcmd("    POST_READ(&value->it_interval.tv_usec, sizeof(__sanitizer_suseconds_t));") +      pcmd("    POST_READ(&value->it_value.tv_sec, sizeof(__sanitizer_time_t));") +      pcmd("    POST_READ(&value->it_value.tv_usec, sizeof(__sanitizer_suseconds_t));") +      pcmd("  }") +      pcmd("}") +    } +  } else if (syscall == "__timer_gettime50") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "__ntp_gettime50") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "__wait450") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "__mknod50") { +    if (mode == "pre") { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (path) {") +      pcmd("  PRE_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("}") +    } else { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (res == 0) {") +      pcmd("  if (path) {") +      pcmd("    POST_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("  }") +      pcmd("}") +    } +  } else if (syscall == "__fhstat50") { +    if (mode == "pre") { +      pcmd("if (fhp_) {") +      pcmd("  PRE_READ(fhp_, fh_size_);") +      pcmd("}") +    } else { +      pcmd("if (res == 0) {") +      pcmd("  if (fhp_) {") +      pcmd("    POST_READ(fhp_, fh_size_);") +      pcmd("  }") +      pcmd("}") +    } +  } else if (syscall == "pipe2") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "dup3") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "kqueue1") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "paccept") { +    if (mode == "pre") { +      pcmd("if (mask_) {") +      pcmd("  PRE_READ(mask_, sizeof(__sanitizer_sigset_t));") +      pcmd("}") +    } else { +      pcmd("if (res >= 0) {") +      pcmd("  if (mask_) {") +      pcmd("    PRE_READ(mask_, sizeof(__sanitizer_sigset_t));") +      pcmd("  }") +      pcmd("}") +    } +  } else if (syscall == "linkat") { +    if (mode == "pre") { +      pcmd("const char *name1 = (const char *)name1_;") +      pcmd("const char *name2 = (const char *)name2_;") +      pcmd("if (name1) {") +      pcmd("  PRE_READ(name1, __sanitizer::internal_strlen(name1) + 1);") +      pcmd("}") +      pcmd("if (name2) {") +      pcmd("  PRE_READ(name2, __sanitizer::internal_strlen(name2) + 1);") +      pcmd("}") +    } else { +      pcmd("const char *name1 = (const char *)name1_;") +      pcmd("const char *name2 = (const char *)name2_;") +      pcmd("if (res == 0) {") +      pcmd("  if (name1) {") +      pcmd("    POST_READ(name1, __sanitizer::internal_strlen(name1) + 1);") +      pcmd("  }") +      pcmd("  if (name2) {") +      pcmd("    POST_READ(name2, __sanitizer::internal_strlen(name2) + 1);") +      pcmd("  }") +      pcmd("}") +    } +  } else if (syscall == "renameat") { +    if (mode == "pre") { +      pcmd("const char *from = (const char *)from_;") +      pcmd("const char *to = (const char *)to_;") +      pcmd("if (from) {") +      pcmd("  PRE_READ(from, __sanitizer::internal_strlen(from) + 1);") +      pcmd("}") +      pcmd("if (to) {") +      pcmd("  PRE_READ(to, __sanitizer::internal_strlen(to) + 1);") +      pcmd("}") +    } else { +      pcmd("const char *from = (const char *)from_;") +      pcmd("const char *to = (const char *)to_;") +      pcmd("if (res == 0) {") +      pcmd("  if (from) {") +      pcmd("    POST_READ(from, __sanitizer::internal_strlen(from) + 1);") +      pcmd("  }") +      pcmd("  if (to) {") +      pcmd("    POST_READ(to, __sanitizer::internal_strlen(to) + 1);") +      pcmd("  }") +      pcmd("}") +    } +  } else if (syscall == "mkfifoat") { +    if (mode == "pre") { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (path) {") +      pcmd("  PRE_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("}") +    } else { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (res == 0) {") +      pcmd("  if (path) {") +      pcmd("    POST_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("  }") +      pcmd("}") +    } +  } else if (syscall == "mknodat") { +    if (mode == "pre") { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (path) {") +      pcmd("  PRE_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("}") +    } else { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (res == 0) {") +      pcmd("  if (path) {") +      pcmd("    POST_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("  }") +      pcmd("}") +    } +  } else if (syscall == "mkdirat") { +    if (mode == "pre") { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (path) {") +      pcmd("  PRE_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("}") +    } else { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (res == 0) {") +      pcmd("  if (path) {") +      pcmd("    POST_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("  }") +      pcmd("}") +    } +  } else if (syscall == "faccessat") { +    if (mode == "pre") { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (path) {") +      pcmd("  PRE_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("}") +    } else { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (res == 0) {") +      pcmd("  if (path) {") +      pcmd("    POST_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("  }") +      pcmd("}") +    } +  } else if (syscall == "fchmodat") { +    if (mode == "pre") { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (path) {") +      pcmd("  PRE_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("}") +    } else { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (res == 0) {") +      pcmd("  if (path) {") +      pcmd("    POST_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("  }") +      pcmd("}") +    } +  } else if (syscall == "fchownat") { +    if (mode == "pre") { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (path) {") +      pcmd("  PRE_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("}") +    } else { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (res == 0) {") +      pcmd("  if (path) {") +      pcmd("    POST_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("  }") +      pcmd("}") +    } +  } else if (syscall == "fexecve") { +    pcmd("/* TODO */") +  } else if (syscall == "fstatat") { +    if (mode == "pre") { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (path) {") +      pcmd("  PRE_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("}") +    } else { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (path) {") +      pcmd("  POST_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("}") +    } +  } else if (syscall == "utimensat") { +    if (mode == "pre") { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (path) {") +      pcmd("  PRE_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("}") +      pcmd("if (tptr_) {") +      pcmd("  PRE_READ(tptr_, struct_timespec_sz);") +      pcmd("}") +    } else { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (res > 0) {") +      pcmd("  if (path) {") +      pcmd("    POST_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("  }") +      pcmd("  if (tptr_) {") +      pcmd("    POST_READ(tptr_, struct_timespec_sz);") +      pcmd("  }") +      pcmd("}") +    } +  } else if (syscall == "openat") { +    if (mode == "pre") { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (path) {") +      pcmd("  PRE_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("}") +    } else { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (res > 0) {") +      pcmd("  if (path) {") +      pcmd("    POST_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("  }") +      pcmd("}") +    } +  } else if (syscall == "readlinkat") { +    if (mode == "pre") { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (path) {") +      pcmd("  PRE_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("}") +    } else { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (res > 0) {") +      pcmd("  if (path) {") +      pcmd("    POST_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("  }") +      pcmd("}") +    } +  } else if (syscall == "symlinkat") { +    if (mode == "pre") { +      pcmd("const char *path1 = (const char *)path1_;") +      pcmd("const char *path2 = (const char *)path2_;") +      pcmd("if (path1) {") +      pcmd("  PRE_READ(path1, __sanitizer::internal_strlen(path1) + 1);") +      pcmd("}") +      pcmd("if (path2) {") +      pcmd("  PRE_READ(path2, __sanitizer::internal_strlen(path2) + 1);") +      pcmd("}") +    } else { +      pcmd("const char *path1 = (const char *)path1_;") +      pcmd("const char *path2 = (const char *)path2_;") +      pcmd("if (res == 0) {") +      pcmd("  if (path1) {") +      pcmd("    POST_READ(path1, __sanitizer::internal_strlen(path1) + 1);") +      pcmd("  }") +      pcmd("  if (path2) {") +      pcmd("    POST_READ(path2, __sanitizer::internal_strlen(path2) + 1);") +      pcmd("  }") +      pcmd("}") +    } +  } else if (syscall == "unlinkat") { +    if (mode == "pre") { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (path) {") +      pcmd("  PRE_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("}") +    } else { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (res == 0) {") +      pcmd("  if (path) {") +      pcmd("    POST_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("  }") +      pcmd("}") +    } +  } else if (syscall == "futimens") { +    if (mode == "pre") { +      pcmd("struct __sanitizer_timespec **tptr = (struct __sanitizer_timespec **)tptr_;") +      pcmd("if (tptr) {") +      pcmd("  PRE_READ(tptr[0], struct_timespec_sz);") +      pcmd("  PRE_READ(tptr[1], struct_timespec_sz);") +      pcmd("}") +    } else { +      pcmd("struct __sanitizer_timespec **tptr = (struct __sanitizer_timespec **)tptr_;") +      pcmd("if (res == 0) {") +      pcmd("  if (tptr) {") +      pcmd("    POST_READ(tptr[0], struct_timespec_sz);") +      pcmd("    POST_READ(tptr[1], struct_timespec_sz);") +      pcmd("  }") +      pcmd("}") +    } +  } else if (syscall == "__quotactl") { +    if (mode == "pre") { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (path) {") +      pcmd("  PRE_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("}") +    } else { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (res == 0) {") +      pcmd("  if (path) {") +      pcmd("    POST_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("  }") +      pcmd("}") +    } +  } else if (syscall == "posix_spawn") { +    if (mode == "pre") { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (path) {") +      pcmd("  PRE_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("}") +    } else { +      pcmd("const char *path = (const char *)path_;") +      pcmd("if (pid_) {") +      pcmd("  if (path) {") +      pcmd("    POST_READ(path, __sanitizer::internal_strlen(path) + 1);") +      pcmd("  }") +      pcmd("}") +    } +  } else if (syscall == "recvmmsg") { +    if (mode == "pre") { +      pcmd("if (timeout_) {") +      pcmd("  PRE_READ(timeout_, struct_timespec_sz);") +      pcmd("}") +    } else { +      pcmd("if (res >= 0) {") +      pcmd("  if (timeout_) {") +      pcmd("    POST_READ(timeout_, struct_timespec_sz);") +      pcmd("  }") +      pcmd("}") +    } +  } else if (syscall == "sendmmsg") { +    if (mode == "pre") { +      pcmd("struct __sanitizer_mmsghdr *mmsg = (struct __sanitizer_mmsghdr *)mmsg_;") +      pcmd("unsigned int vlen = (vlen_ > 1024 ? 1024 : vlen_);") +      pcmd("if (mmsg) {") +      pcmd("  PRE_READ(mmsg, sizeof(struct __sanitizer_mmsghdr) * vlen);") +      pcmd("}") +    } else { +      pcmd("struct __sanitizer_mmsghdr *mmsg = (struct __sanitizer_mmsghdr *)mmsg_;") +      pcmd("unsigned int vlen = (vlen_ > 1024 ? 1024 : vlen_);") +      pcmd("if (res >= 0) {") +      pcmd("  if (mmsg) {") +      pcmd("    POST_READ(mmsg, sizeof(struct __sanitizer_mmsghdr) * vlen);") +      pcmd("  }") +      pcmd("}") +    } +  } else if (syscall == "clock_nanosleep") { +    if (mode == "pre") { +      pcmd("if (rqtp_) {") +      pcmd("  PRE_READ(rqtp_, struct_timespec_sz);") +      pcmd("}") +    } else { +      pcmd("if (rqtp_) {") +      pcmd("  POST_READ(rqtp_, struct_timespec_sz);") +      pcmd("}") +    } +  } else if (syscall == "___lwp_park60") { +    if (mode == "pre") { +      pcmd("if (ts_) {") +      pcmd("  PRE_READ(ts_, struct_timespec_sz);") +      pcmd("}") +    } else { +      pcmd("if (res == 0) {") +      pcmd("  if (ts_) {") +      pcmd("    POST_READ(ts_, struct_timespec_sz);") +      pcmd("  }") +      pcmd("}") +    } +  } else if (syscall == "posix_fallocate") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "fdiscard") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "wait6") { +    pcmd("/* Nothing to do */") +  } else if (syscall == "clock_getcpuclockid2") { +    pcmd("/* Nothing to do */") +  } else { +    print "Unrecognized syscall: " syscall +    abnormal_exit = 1 +    exit 1 +  } +}  | 
