Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

[Flang][Sanitizer] Support sanitizer flag for Flang Driver. #137759

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: main
Choose a base branch
Loading
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 53 additions & 49 deletions 102 clang/include/clang/Driver/Options.td

Large diffs are not rendered by default.

13 changes: 13 additions & 0 deletions 13 clang/lib/Driver/ToolChains/Flang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

#include "clang/Basic/CodeGenOptions.h"
#include "clang/Driver/Options.h"
#include "clang/Driver/SanitizerArgs.h"
#include "llvm/Frontend/Debug/Options.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
Expand Down Expand Up @@ -143,6 +144,15 @@ void Flang::addOtherOptions(const ArgList &Args, ArgStringList &CmdArgs) const {
addDebugInfoKind(CmdArgs, DebugInfoKind);
}

void Flang::addSanitizerOptions(const ToolChain &TC, const ArgList &Args,
ArgStringList &CmdArgs,
types::ID InputType) const {
SanitizerArgs SanArgs = TC.getSanitizerArgs(Args);
SanArgs.addArgs(TC, Args, CmdArgs, InputType);
// If Tc.getTriple() == amdgpu search for only allow -fsanitize=address for
// that target
}

void Flang::addCodegenOptions(const ArgList &Args,
ArgStringList &CmdArgs) const {
Arg *stackArrays =
Expand Down Expand Up @@ -869,6 +879,9 @@ void Flang::ConstructJob(Compilation &C, const JobAction &JA,
// Add Codegen options
addCodegenOptions(Args, CmdArgs);

// Add Sanitizer Options
addSanitizerOptions(TC, Args, CmdArgs, InputType);

// Add R Group options
Args.AddAllArgs(CmdArgs, options::OPT_R_Group);

Expand Down
9 changes: 9 additions & 0 deletions 9 clang/lib/Driver/ToolChains/Flang.h
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,15 @@ class LLVM_LIBRARY_VISIBILITY Flang : public Tool {
void addCodegenOptions(const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs) const;

/// Extract sanitizer options for code generation from the driver arguments
/// and add them to the command arguments.
///
/// \param [in] Args The list of input driver arguments
/// \param [out] CmdArgs The list of output command arguments
void addSanitizerOptions(const ToolChain &TC, const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs,
types::ID InputType) const;

/// Extract other compilation options from the driver arguments and add them
/// to the command arguments.
///
Expand Down
67 changes: 67 additions & 0 deletions 67 flang/include/flang/Frontend/CodeGenOptions.def
Original file line number Diff line number Diff line change
Expand Up @@ -47,5 +47,72 @@ ENUM_CODEGENOPT(FramePointer, llvm::FramePointerKind, 2, llvm::FramePointerKind:

ENUM_CODEGENOPT(DoConcurrentMapping, DoConcurrentMappingKind, 2, DoConcurrentMappingKind::DCMK_None) ///< Map `do concurrent` to OpenMP

CODEGENOPT(SanitizeAddressUseAfterScope , 1, 0) ///< Enable use-after-scope detection
///< in AddressSanitizer
ENUM_CODEGENOPT(SanitizeAddressUseAfterReturn,
llvm::AsanDetectStackUseAfterReturnMode, 2,
llvm::AsanDetectStackUseAfterReturnMode::Runtime
) ///< Set detection mode for stack-use-after-return.
CODEGENOPT(SanitizeAddressPoisonCustomArrayCookie, 1,
0) ///< Enable poisoning operator new[] which is not a replaceable
///< global allocation function in AddressSanitizer
CODEGENOPT(SanitizeAddressGlobalsDeadStripping, 1, 0) ///< Enable linker dead stripping
///< of globals in AddressSanitizer
CODEGENOPT(SanitizeAddressUseOdrIndicator, 1, 0) ///< Enable ODR indicator globals
CODEGENOPT(SanitizeMemoryTrackOrigins, 2, 0) ///< Enable tracking origins in
///< MemorySanitizer
ENUM_CODEGENOPT(SanitizeAddressDtor, llvm::AsanDtorKind, 2,
llvm::AsanDtorKind::Global) ///< Set how ASan global
///< destructors are emitted.
CODEGENOPT(SanitizeMemoryParamRetval, 1, 0) ///< Enable detection of uninitialized
///< parameters and return values
///< in MemorySanitizer
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) ///< Use "_minimal" sanitizer runtime for
///< diagnostics.
CODEGENOPT(SanitizeCfiICallGeneralizePointers, 1, 0) ///< Generalize pointer types in
///< CFI icall function signatures
CODEGENOPT(SanitizeCfiICallNormalizeIntegers, 1, 0) ///< Normalize integer types in
///< CFI icall function signatures
CODEGENOPT(SanitizeCfiCanonicalJumpTables, 1, 0) ///< Make jump table symbols canonical
///< instead of creating a local jump table.
CODEGENOPT(UniqueSourceFileNames, 1, 0) ///< Allow the compiler to assume that TUs
///< have unique source file names at link time
CODEGENOPT(SanitizeKcfiArity, 1, 0) ///< Embed arity in KCFI patchable function prefix
CODEGENOPT(SanitizeCoverageType, 2, 0) ///< Type of sanitizer coverage
///< instrumentation.
CODEGENOPT(SanitizeCoverageIndirectCalls, 1, 0) ///< Enable sanitizer coverage
///< for indirect calls.
CODEGENOPT(SanitizeCoverageTraceBB, 1, 0) ///< Enable basic block tracing in
///< in sanitizer coverage.
CODEGENOPT(SanitizeCoverageTraceCmp, 1, 0) ///< Enable cmp instruction tracing
///< in sanitizer coverage.
CODEGENOPT(SanitizeCoverageTraceDiv, 1, 0) ///< Enable div instruction tracing
///< in sanitizer coverage.
CODEGENOPT(SanitizeCoverageTraceGep, 1, 0) ///< Enable GEP instruction tracing
///< in sanitizer coverage.
CODEGENOPT(SanitizeCoverage8bitCounters, 1, 0) ///< Use 8-bit frequency counters
///< in sanitizer coverage.
CODEGENOPT(SanitizeCoverageTracePC, 1, 0) ///< Enable PC tracing
///< in sanitizer coverage.
CODEGENOPT(SanitizeCoverageTracePCGuard, 1, 0) ///< Enable PC tracing with guard
///< in sanitizer coverage.
CODEGENOPT(SanitizeCoverageInline8bitCounters, 1, 0) ///< Use inline 8bit counters.
CODEGENOPT(SanitizeCoverageInlineBoolFlag, 1, 0) ///< Use inline bool flag.
CODEGENOPT(SanitizeCoveragePCTable, 1, 0) ///< Create a PC Table.
CODEGENOPT(SanitizeCoverageControlFlow, 1, 0) ///< Collect control flow
CODEGENOPT(SanitizeCoverageNoPrune, 1, 0) ///< Disable coverage pruning.
CODEGENOPT(SanitizeCoverageStackDepth, 1, 0) ///< Enable max stack depth tracing
CODEGENOPT(SanitizeCoverageTraceLoads, 1, 0) ///< Enable tracing of loads.
CODEGENOPT(SanitizeCoverageTraceStores, 1, 0) ///< Enable tracing of stores.
CODEGENOPT(SanitizeBinaryMetadataCovered, 1, 0) ///< Emit PCs for covered functions.
CODEGENOPT(SanitizeBinaryMetadataAtomics, 1, 0) ///< Emit PCs for atomic operations.
CODEGENOPT(SanitizeBinaryMetadataUAR, 1, 0) ///< Emit PCs for start of functions
///< that are subject for use-after-return checking.
CODEGENOPT(SanitizeStats , 1, 0) ///< Collect statistics for sanitizers.
CODEGENOPT(DisableIntegratedAS, 1, 0) ///< -no-integrated-as

#undef CODEGENOPT
#undef ENUM_CODEGENOPT
47 changes: 47 additions & 0 deletions 47 flang/include/flang/Frontend/CodeGenOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#define FORTRAN_FRONTEND_CODEGENOPTIONS_H

#include "flang/Optimizer/OpenMP/Utils.h"
#include "clang/Basic/Sanitizers.h"
#include "llvm/Frontend/Debug/Options.h"
#include "llvm/Frontend/Driver/CodeGenOptions.h"
#include "llvm/Support/CodeGen.h"
Expand Down Expand Up @@ -148,6 +149,50 @@ class CodeGenOptions : public CodeGenOptionsBase {
/// OpenMP is enabled.
using DoConcurrentMappingKind = flangomp::DoConcurrentMappingKind;

/// Set of sanitizer checks that are non-fatal (i.e. execution should be
/// continued when possible).
clang::SanitizerSet SanitizeRecover;

/// Set of sanitizer checks that trap rather than diagnose.
clang::SanitizerSet SanitizeTrap;

/// Set of sanitizer checks that can merge handlers (smaller code size at
/// the expense of debuggability).
clang::SanitizerSet SanitizeMergeHandlers;

/// Set of thresholds in a range [0.0, 1.0]: the top hottest code responsible
/// for the given fraction of PGO counters will be excluded from sanitization
/// (0.0 [default] to skip none, 1.0 to skip all).
clang::SanitizerMaskCutoffs SanitizeSkipHotCutoffs;

/// Path to allowlist file specifying which objects
/// (files, functions) should exclusively be instrumented
/// by sanitizer coverage pass.
std::vector<std::string> SanitizeCoverageAllowlistFiles;

/// Path to ignorelist file specifying which objects
/// (files, functions) listed for instrumentation by sanitizer
/// coverage pass should actually not be instrumented.
std::vector<std::string> SanitizeCoverageIgnorelistFiles;

/// Path to ignorelist file specifying which objects
/// (files, functions) listed for instrumentation by sanitizer
/// binary metadata pass should not be instrumented.
std::vector<std::string> SanitizeMetadataIgnorelistFiles;

// Check if any one of SanitizeCoverage* is enabled.
bool hasSanitizeCoverage() const {
return SanitizeCoverageType || SanitizeCoverageIndirectCalls ||
SanitizeCoverageTraceCmp || SanitizeCoverageTraceLoads ||
SanitizeCoverageTraceStores || SanitizeCoverageControlFlow;
}

// Check if any one of SanitizeBinaryMetadata* is enabled.
bool hasSanitizeBinaryMetadata() const {
return SanitizeBinaryMetadataCovered || SanitizeBinaryMetadataAtomics ||
SanitizeBinaryMetadataUAR;
}

// Define accessors/mutators for code generation options of enumeration type.
#define CODEGENOPT(Name, Bits, Default)
#define ENUM_CODEGENOPT(Name, Type, Bits, Default) \
Expand All @@ -158,6 +203,8 @@ class CodeGenOptions : public CodeGenOptionsBase {
CodeGenOptions();
};

bool asanUseGlobalsGC(const llvm::Triple &T, const CodeGenOptions &CGOpts);

std::optional<llvm::CodeModel::Model> getCodeModel(llvm::StringRef string);

} // end namespace Fortran::frontend
Expand Down
1 change: 1 addition & 0 deletions 1 flang/include/flang/Support/LangOptions.def
Original file line number Diff line number Diff line change
Expand Up @@ -62,5 +62,6 @@ LANGOPT(OpenMPNoNestedParallelism, 1, 0)
LANGOPT(VScaleMin, 32, 0) ///< Minimum vscale range value
LANGOPT(VScaleMax, 32, 0) ///< Maximum vscale range value

LANGOPT(SanitizeAddressFieldPadding, 2, 0)
#undef LANGOPT
#undef ENUM_LANGOPT
11 changes: 10 additions & 1 deletion 11 flang/include/flang/Support/LangOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@
#include <string>
#include <vector>

#include "clang/Basic/Sanitizers.h"
#include "llvm/TargetParser/Triple.h"

namespace Fortran::common {

/// Bitfields of LangOptions, split out from LangOptions to ensure
/// that this large collection of bitfields is a trivial class type.
class LangOptionsBase {
Expand Down Expand Up @@ -72,6 +72,15 @@ class LangOptions : public LangOptionsBase {
/// host code generation.
std::string OMPHostIRFile;

/// Set of enabled sanitizers.
clang::SanitizerSet Sanitize;
/// Is at least one coverage instrumentation type enabled.
bool SanitizeCoverage = false;

/// Paths to files specifying which objects
/// (files, functions, variables) should not be instrumented.
std::vector<std::string> NoSanitizeFiles;

/// List of triples passed in using -fopenmp-targets.
std::vector<llvm::Triple> OMPTargetTriples;

Expand Down
29 changes: 29 additions & 0 deletions 29 flang/lib/Frontend/CodeGenOptions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,46 @@
//===----------------------------------------------------------------------===//

#include "flang/Frontend/CodeGenOptions.h"
#include "llvm/TargetParser/Triple.h"
#include <optional>
#include <string.h>

namespace Fortran::frontend {

using namespace llvm;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We generally do not use using namespace llvm in flang.


CodeGenOptions::CodeGenOptions() {
#define CODEGENOPT(Name, Bits, Default) Name = Default;
#define ENUM_CODEGENOPT(Name, Type, Bits, Default) set##Name(Default);
#include "flang/Frontend/CodeGenOptions.def"
}

// Check if ASan should use GC-friendly instrumentation for globals.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like this and much of the other code here has been copied from clang. If the code is identical to what is in clang, it should be shared rather than copied. Such code can be moved somewhere in llvm/include/llvm/Frontend and llvm/lib/Frontend/. See #136098 for some suggestions. That PR is still awaiting approval from the clang developers, but I don't anticipate any major objections.

// First of all, there is no point if -fdata-sections is off (expect for MachO,
// where this is not a factor). Also, on ELF this feature requires an assembler
// extension that only works with -integrated-as at the moment.
bool asanUseGlobalsGC(const Triple &T, const CodeGenOptions &CGOpts) {
if (!CGOpts.SanitizeAddressGlobalsDeadStripping)
return false;
switch (T.getObjectFormat()) {
case Triple::MachO:
case Triple::COFF:
return true;
case Triple::ELF:
return !CGOpts.DisableIntegratedAS;
case Triple::GOFF:
llvm::report_fatal_error("ASan not implemented for GOFF");
case Triple::XCOFF:
llvm::report_fatal_error("ASan not implemented for XCOFF.");
case Triple::Wasm:
case Triple::DXContainer:
case Triple::SPIRV:
case Triple::UnknownObjectFormat:
break;
}
return false;
}

std::optional<llvm::CodeModel::Model> getCodeModel(llvm::StringRef string) {
return llvm::StringSwitch<std::optional<llvm::CodeModel::Model>>(string)
.Case("tiny", llvm::CodeModel::Model::Tiny)
Expand Down
82 changes: 82 additions & 0 deletions 82 flang/lib/Frontend/CompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include "clang/Basic/AllDiagnostics.h"
#include "clang/Basic/DiagnosticDriver.h"
#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/Sanitizers.h"
#include "clang/Driver/Driver.h"
#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/OptionUtils.h"
Expand Down Expand Up @@ -256,6 +257,82 @@ parseOptimizationRemark(clang::DiagnosticsEngine &diags,
return result;
}

static void parseSanitizerKinds(llvm::StringRef FlagName,
const std::vector<std::string> &Sanitizers,
clang::DiagnosticsEngine &Diags,
clang::SanitizerSet &S) {
for (const auto &Sanitizer : Sanitizers) {
clang::SanitizerMask K =
clang::parseSanitizerValue(Sanitizer, /*AllowGroups=*/false);
if (K == clang::SanitizerMask())
Diags.Report(clang::diag::err_drv_invalid_value) << FlagName << Sanitizer;
else
S.set(K, true);
}
}

static llvm::SmallVector<llvm::StringRef, 4>
serializeSanitizerKinds(clang::SanitizerSet S) {
llvm::SmallVector<llvm::StringRef, 4> Values;
serializeSanitizerSet(S, Values);
return Values;
}

static clang::SanitizerMaskCutoffs
parseSanitizerWeightedKinds(llvm::StringRef FlagName,
const std::vector<std::string> &Sanitizers,
clang::DiagnosticsEngine &Diags) {
clang::SanitizerMaskCutoffs Cutoffs;
for (const auto &Sanitizer : Sanitizers) {
if (!parseSanitizerWeightedValue(Sanitizer, /*AllowGroups=*/false, Cutoffs))
Diags.Report(clang::diag::err_drv_invalid_value) << FlagName << Sanitizer;
}
return Cutoffs;
}

static bool parseSanitizerArgs(CompilerInvocation &res,
llvm::opt::ArgList &args,
clang::DiagnosticsEngine &diags) {
auto &LangOpts = res.getLangOpts();
auto &CodeGenOpts = res.getCodeGenOpts();

parseSanitizerKinds(
"-fsanitize-recover=",
args.getAllArgValues(clang::driver::options::OPT_fsanitize_recover_EQ),
diags, CodeGenOpts.SanitizeRecover);
parseSanitizerKinds(
"-fsanitize-trap=",
args.getAllArgValues(clang::driver::options::OPT_fsanitize_trap_EQ),
diags, CodeGenOpts.SanitizeTrap);
parseSanitizerKinds(
"-fsanitize-merge=",
args.getAllArgValues(
clang::driver::options::OPT_fsanitize_merge_handlers_EQ),
diags, CodeGenOpts.SanitizeMergeHandlers);

// Parse -fsanitize-skip-hot-cutoff= arguments.
CodeGenOpts.SanitizeSkipHotCutoffs = parseSanitizerWeightedKinds(
"-fsanitize-skip-hot-cutoff=",
args.getAllArgValues(
clang::driver::options::OPT_fsanitize_skip_hot_cutoff_EQ),
diags);

// Parse -fsanitize= arguments.
parseSanitizerKinds(
"-fsanitize=",
args.getAllArgValues(clang::driver::options::OPT_fsanitize_EQ), diags,
LangOpts.Sanitize);

LangOpts.NoSanitizeFiles =
args.getAllArgValues(clang::driver::options::OPT_fsanitize_ignorelist_EQ);
std::vector<std::string> systemIgnorelists = args.getAllArgValues(
clang::driver::options::OPT_fsanitize_system_ignorelist_EQ);
LangOpts.NoSanitizeFiles.insert(LangOpts.NoSanitizeFiles.end(),
systemIgnorelists.begin(),
systemIgnorelists.end());
return true;
}

static void parseCodeGenArgs(Fortran::frontend::CodeGenOptions &opts,
llvm::opt::ArgList &args,
clang::DiagnosticsEngine &diags) {
Expand Down Expand Up @@ -395,6 +472,10 @@ static void parseCodeGenArgs(Fortran::frontend::CodeGenOptions &opts,
opts.RecordCommandLine = a->getValue();
}

// -mlink-bitcode-file
for (auto *a : args.filtered(clang::driver::options::OPT_mlink_bitcode_file))
opts.BuiltinBCLibs.push_back(a->getValue());

// -mlink-builtin-bitcode
for (auto *a :
args.filtered(clang::driver::options::OPT_mlink_builtin_bitcode))
Expand Down Expand Up @@ -1500,6 +1581,7 @@ bool CompilerInvocation::createFromArgs(
success &= parseVectorLibArg(invoc.getCodeGenOpts(), args, diags);
success &= parseSemaArgs(invoc, args, diags);
success &= parseDialectArgs(invoc, args, diags);
success &= parseSanitizerArgs(invoc, args, diags);
success &= parseOpenMPArgs(invoc, args, diags);
success &= parseDiagArgs(invoc, args, diags);

Expand Down
Loading
Morty Proxy This is a proxified and sanitized view of the page, visit original site.