Index: clang/include/clang/Driver/Options.td =================================================================== --- clang/include/clang/Driver/Options.td +++ clang/include/clang/Driver/Options.td @@ -869,6 +869,10 @@ Group; def fno_sanitize_undefined_trap_on_error : Flag<["-"], "fno-sanitize-undefined-trap-on-error">, Group; +def fsanitize_minimal_runtime : Flag<["-"], "fsanitize-minimal-runtime">, + Group; +def fno_sanitize_minimal_runtime : Flag<["-"], "fno-sanitize-minimal-runtime">, + Group; def fsanitize_link_cxx_runtime : Flag<["-"], "fsanitize-link-c++-runtime">, Group; def fsanitize_cfi_cross_dso : Flag<["-"], "fsanitize-cfi-cross-dso">, Index: clang/include/clang/Driver/SanitizerArgs.h =================================================================== --- clang/include/clang/Driver/SanitizerArgs.h +++ clang/include/clang/Driver/SanitizerArgs.h @@ -43,6 +43,7 @@ bool TsanMemoryAccess = true; bool TsanFuncEntryExit = true; bool TsanAtomics = true; + bool MinimalRuntime = false; public: /// Parses the sanitizer arguments from an argument list. @@ -58,6 +59,7 @@ !Sanitizers.has(SanitizerKind::Address); } bool needsUbsanRt() const; + bool requiresMinimalRuntime() const { return MinimalRuntime; } bool needsDfsanRt() const { return Sanitizers.has(SanitizerKind::DataFlow); } bool needsSafeStackRt() const { return SafeStackRuntime; } bool needsCfiRt() const; Index: clang/include/clang/Frontend/CodeGenOptions.def =================================================================== --- clang/include/clang/Frontend/CodeGenOptions.def +++ clang/include/clang/Frontend/CodeGenOptions.def @@ -148,6 +148,7 @@ CODEGENOPT(SanitizeMemoryUseAfterDtor, 1, 0) ///< Enable use-after-delete detection ///< in MemorySanitizer CODEGENOPT(SanitizeCfiCrossDso, 1, 0) ///< Enable cross-dso support in CFI. +CODEGENOPT(SanitizeMinimalRuntime, 1, 0) ///< TODO CODEGENOPT(SanitizeCoverageType, 2, 0) ///< Type of sanitizer coverage ///< instrumentation. CODEGENOPT(SanitizeCoverageIndirectCalls, 1, 0) ///< Enable sanitizer coverage Index: clang/lib/CodeGen/CGExpr.cpp =================================================================== --- clang/lib/CodeGen/CGExpr.cpp +++ clang/lib/CodeGen/CGExpr.cpp @@ -2704,12 +2704,15 @@ assert(IsFatal || RecoverKind != CheckRecoverableKind::Unrecoverable); bool NeedsAbortSuffix = IsFatal && RecoverKind != CheckRecoverableKind::Unrecoverable; + bool MinimalRuntime = CGF.CGM.getCodeGenOpts().SanitizeMinimalRuntime; const SanitizerHandlerInfo &CheckInfo = SanitizerHandlers[CheckHandler]; const StringRef CheckName = CheckInfo.Name; std::string FnName = ("__ubsan_handle_" + CheckName + - (CheckInfo.Version ? "_v" + llvm::utostr(CheckInfo.Version) : "") + - (NeedsAbortSuffix ? "_abort" : "")) + ((CheckInfo.Version && !MinimalRuntime) + ? "_v" + llvm::utostr(CheckInfo.Version) + : "") + + (MinimalRuntime ? "_minimal" : "") + (NeedsAbortSuffix ? "_abort" : "")) .str(); bool MayReturn = !IsFatal || RecoverKind == CheckRecoverableKind::AlwaysRecoverable; Index: clang/lib/Driver/SanitizerArgs.cpp =================================================================== --- clang/lib/Driver/SanitizerArgs.cpp +++ clang/lib/Driver/SanitizerArgs.cpp @@ -41,6 +41,7 @@ Nullability | LocalBounds | CFI, TrappingDefault = CFI, CFIClasses = CFIVCall | CFINVCall | CFIDerivedCast | CFIUnrelatedCast, + CompatibleWithMinimalRuntime = TrappingSupported, }; enum CoverageFeature { @@ -491,6 +492,16 @@ Stats = Args.hasFlag(options::OPT_fsanitize_stats, options::OPT_fno_sanitize_stats, false); + MinimalRuntime = + Args.hasFlag(options::OPT_fsanitize_minimal_runtime, + options::OPT_fno_sanitize_minimal_runtime, MinimalRuntime); + + if (MinimalRuntime && (AllAddedKinds & ~AllRemove & + ~setGroupBits(CompatibleWithMinimalRuntime))) + D.Diag(clang::diag::err_drv_argument_not_allowed_with) + << "-fsanitize-minimal-runtime" + << lastArgumentForMask(D, Args, ~CompatibleWithMinimalRuntime); + // Parse -f(no-)?sanitize-coverage flags if coverage is supported by the // enabled sanitizers. for (const auto *Arg : Args) { @@ -752,6 +763,9 @@ if (Stats) CmdArgs.push_back("-fsanitize-stats"); + if (MinimalRuntime) + CmdArgs.push_back("-fsanitize-minimal-runtime"); + if (AsanFieldPadding) CmdArgs.push_back(Args.MakeArgString("-fsanitize-address-field-padding=" + llvm::utostr(AsanFieldPadding))); Index: clang/lib/Driver/ToolChains/CommonArgs.cpp =================================================================== --- clang/lib/Driver/ToolChains/CommonArgs.cpp +++ clang/lib/Driver/ToolChains/CommonArgs.cpp @@ -541,6 +541,16 @@ if (SanArgs.needsAsanRt() && SanArgs.needsSharedAsanRt()) { SharedRuntimes.push_back("asan"); } + if (SanArgs.needsUbsanRt() && TC.getTriple().isAndroid()) { + if (SanArgs.requiresMinimalRuntime()) { + SharedRuntimes.push_back("ubsan_minimal"); + } else { + SharedRuntimes.push_back("ubsan_standalone"); + if (SanArgs.linkCXXRuntimes()) + SharedRuntimes.push_back("ubsan_standalone_cxx"); + } + } + // The stats_client library is also statically linked into DSOs. if (SanArgs.needsStatsRt()) StaticRuntimes.push_back("stats_client"); @@ -574,9 +584,13 @@ StaticRuntimes.push_back("tsan_cxx"); } if (SanArgs.needsUbsanRt()) { - StaticRuntimes.push_back("ubsan_standalone"); - if (SanArgs.linkCXXRuntimes()) - StaticRuntimes.push_back("ubsan_standalone_cxx"); + if (SanArgs.requiresMinimalRuntime()) { + StaticRuntimes.push_back("ubsan_minimal"); + } else { + StaticRuntimes.push_back("ubsan_standalone"); + if (SanArgs.linkCXXRuntimes()) + StaticRuntimes.push_back("ubsan_standalone_cxx"); + } } if (SanArgs.needsSafeStackRt()) { NonWholeStaticRuntimes.push_back("safestack"); Index: clang/lib/Frontend/CompilerInvocation.cpp =================================================================== --- clang/lib/Frontend/CompilerInvocation.cpp +++ clang/lib/Frontend/CompilerInvocation.cpp @@ -799,6 +799,7 @@ getLastArgIntValue(Args, OPT_fsanitize_memory_track_origins_EQ, 0, Diags); Opts.SanitizeMemoryUseAfterDtor = Args.hasArg(OPT_fsanitize_memory_use_after_dtor); + Opts.SanitizeMinimalRuntime = Args.hasArg(OPT_fsanitize_minimal_runtime); Opts.SanitizeCfiCrossDso = Args.hasArg(OPT_fsanitize_cfi_cross_dso); Opts.SanitizeStats = Args.hasArg(OPT_fsanitize_stats); if (Arg *A = Args.getLastArg(OPT_fsanitize_address_use_after_scope, Index: compiler-rt/lib/CMakeLists.txt =================================================================== --- compiler-rt/lib/CMakeLists.txt +++ compiler-rt/lib/CMakeLists.txt @@ -34,6 +34,7 @@ add_subdirectory(stats) add_subdirectory(lsan) add_subdirectory(ubsan) + add_subdirectory(ubsan_minimal) endif() foreach(sanitizer ${COMPILER_RT_SANITIZERS_TO_BUILD}) Index: compiler-rt/lib/ubsan_minimal/CMakeLists.txt =================================================================== --- /dev/null +++ compiler-rt/lib/ubsan_minimal/CMakeLists.txt @@ -0,0 +1,63 @@ +# Build for the undefined behavior sanitizer runtime support library. + +set(UBSAN_MINIMAL_SOURCES + ubsan_minimal_handlers.cc + ) + +include_directories(..) + +set(UBSAN_CFLAGS ${SANITIZER_COMMON_CFLAGS}) +append_rtti_flag(OFF UBSAN_CFLAGS) + +set(UBSAN_STANDALONE_CFLAGS ${SANITIZER_COMMON_CFLAGS}) +append_rtti_flag(OFF UBSAN_STANDALONE_CFLAGS) + +set(UBSAN_CXXFLAGS ${SANITIZER_COMMON_CFLAGS}) +append_rtti_flag(ON UBSAN_CXXFLAGS) +append_list_if(SANITIZER_CAN_USE_CXXABI -DUBSAN_CAN_USE_CXXABI UBSAN_CXXFLAGS) + +append_list_if(COMPILER_RT_HAS_LIBDL dl UBSAN_DYNAMIC_LIBS) +append_list_if(COMPILER_RT_HAS_LIBLOG log UBSAN_DYNAMIC_LIBS) +append_list_if(COMPILER_RT_HAS_LIBRT rt UBSAN_DYNAMIC_LIBS) +append_list_if(COMPILER_RT_HAS_LIBPTHREAD pthread UBSAN_DYNAMIC_LIBS) + +add_compiler_rt_component(ubsan-minimal) + +if(APPLE) + +else() + # Common parts of UBSan runtime. + add_compiler_rt_object_libraries(RTUbsan_minimal + ARCHS ${UBSAN_COMMON_SUPPORTED_ARCH} + SOURCES ${UBSAN_MINIMAL_SOURCES} CFLAGS ${UBSAN_CFLAGS}) + + + if(COMPILER_RT_HAS_UBSAN) + # Initializer of standalone UBSan runtime. + + # Standalone UBSan runtimes. + add_compiler_rt_runtime(clang_rt.ubsan_minimal + STATIC + ARCHS ${UBSAN_SUPPORTED_ARCH} + OBJECT_LIBS RTUbsan_minimal + CFLAGS ${UBSAN_CFLAGS} + PARENT_TARGET ubsan-minimal) + + add_compiler_rt_runtime(clang_rt.ubsan_minimal + SHARED + ARCHS ${UBSAN_SUPPORTED_ARCH} + OBJECT_LIBS RTUbsan_minimal + CFLAGS ${UBSAN_CFLAGS} + LINK_LIBS ${UBSAN_DYNAMIC_LIBS} + PARENT_TARGET ubsan-minimal) + + if (UNIX) + set(ARCHS_FOR_SYMBOLS ${UBSAN_SUPPORTED_ARCH}) + list(REMOVE_ITEM ARCHS_FOR_SYMBOLS i386 i686) + add_sanitizer_rt_symbols(clang_rt.ubsan_minimal + ARCHS ${ARCHS_FOR_SYMBOLS} + PARENT_TARGET ubsan-minimal + EXTRA ubsan.syms.extra) + endif() + endif() +endif() Index: compiler-rt/lib/ubsan_minimal/ubsan.syms.extra =================================================================== --- /dev/null +++ compiler-rt/lib/ubsan_minimal/ubsan.syms.extra @@ -0,0 +1 @@ +__ubsan_* Index: compiler-rt/lib/ubsan_minimal/ubsan_minimal_handlers.cc =================================================================== --- /dev/null +++ compiler-rt/lib/ubsan_minimal/ubsan_minimal_handlers.cc @@ -0,0 +1,51 @@ +#include +#include +#include + +#if defined(__ANDROID__) +extern "C" void android_set_abort_message(const char *msg); +static void abort_with_message(const char *msg) { +#if __ANDROID_API__ >= 21 + android_set_abort_message(msg); +#endif + abort(); +} +#else +static void abort_with_message(const char *unused) { abort(); } +#endif + +static void message(const char *msg) { + write(2, msg, strlen(msg)); +} + +#define INTERFACE extern "C" __attribute__((visibility("default"))) + +#define HANDLER(name, msg) \ + INTERFACE void __ubsan_handle_##name##_minimal() { \ + message("ubsan: " msg "\n"); \ + } \ + \ + INTERFACE void __ubsan_handle_##name##_minimal_abort() { \ + message("ubsan: " msg "\n"); \ + abort_with_message("ubsan: " msg); \ + } + +HANDLER(type_mismatch, "type-mismatch") +HANDLER(add_overflow, "add-overflow") +HANDLER(sub_overflow, "sub-overflow") +HANDLER(mul_overflow, "mul-overflow") +HANDLER(negate_overflow, "negate-overflow") +HANDLER(divrem_overflow, "divrem-overflow") +HANDLER(shift_out_of_bounds, "shift-out-of-bounds") +HANDLER(out_of_bounds, "out-of-bounds") +HANDLER(builtin_unreachable, "builtin-unreachable") +HANDLER(missing_return, "missing-return") +HANDLER(vla_bound_not_positive, "vla-bound-not-positive") +HANDLER(float_cast_overflow, "float-cast-overflow") +HANDLER(load_invalid_value, "load-invalid-value") +HANDLER(invalid_builtin, "invalid-builtin") +HANDLER(function_type_mismatch, "function-type-mismatch") +HANDLER(nonnull_arg, "nonnull-arg") +HANDLER(nullability_arg, "nullability-arg") +HANDLER(pointer_overflow, "pointer-overflow") +HANDLER(cfi_check_fail, "cfi-check-fail")