diff options
author | Ziqing Luo <ziqing@udel.edu> | 2023-02-08 14:06:37 -0800 |
---|---|---|
committer | Ziqing Luo <ziqing@udel.edu> | 2023-02-08 14:12:03 -0800 |
commit | 829bcb06ec43ab4b56b95ff040ec9d36feeaf06a (patch) | |
tree | 6608c7c245a389295ba0591e5dbf84194314ce94 /clang/lib/Lex/Preprocessor.cpp | |
parent | a1507668807e6108c12ffecf3740cb339b15018d (diff) | |
download | llvm-829bcb06ec43ab4b56b95ff040ec9d36feeaf06a.zip llvm-829bcb06ec43ab4b56b95ff040ec9d36feeaf06a.tar.gz llvm-829bcb06ec43ab4b56b95ff040ec9d36feeaf06a.tar.bz2 |
[-Wunsafe-buffer-usage] Add unsafe buffer checking opt-out pragmas
Add a pair of clang pragmas:
- `#pragma clang unsafe_buffer_usage begin` and
- `#pragma clang unsafe_buffer_usage end`,
which specify the start and end of an (unsafe buffer checking) opt-out
region, respectively.
Behaviors of opt-out regions conform to the following rules:
- No nested nor overlapped opt-out regions are allowed. One cannot
start an opt-out region with `... unsafe_buffer_usage begin` but never
close it with `... unsafe_buffer_usage end`. Mis-use of the pragmas
will be warned.
- Warnings raised from unsafe buffer operations inside such an opt-out
region will always be suppressed. This behavior CANNOT be changed by
`clang diagnostic` pragmas or command-line flags.
- Warnings raised from unsafe operations outside of such opt-out
regions may be reported on declarations inside opt-out
regions. These warnings are NOT suppressed.
- An un-suppressed unsafe operation warning may be attached with
notes. These notes are NOT suppressed as well regardless of whether
they are in opt-out regions.
The implementation maintains a separate sequence of location pairs
representing opt-out regions in `Preprocessor`. The `UnsafeBufferUsage`
analyzer reads the region sequence to check if an unsafe operation is
in an opt-out region. If it is, discard the warning raised from the
operation immediately.
This is a re-land after I reverting it at 9aa00c8a306561c4e3ddb09058e66bae322a0769.
The compilation error should be resolved.
Reviewed by: NoQ
Differential revision: https://reviews.llvm.org/D140179
Diffstat (limited to 'clang/lib/Lex/Preprocessor.cpp')
-rw-r--r-- | clang/lib/Lex/Preprocessor.cpp | 69 |
1 files changed, 69 insertions, 0 deletions
diff --git a/clang/lib/Lex/Preprocessor.cpp b/clang/lib/Lex/Preprocessor.cpp index fe9adb5..924a7e6 100644 --- a/clang/lib/Lex/Preprocessor.cpp +++ b/clang/lib/Lex/Preprocessor.cpp @@ -1462,6 +1462,75 @@ void Preprocessor::emitFinalMacroWarning(const Token &Identifier, Diag(*A.FinalAnnotationLoc, diag::note_pp_macro_annotation) << 2; } +bool Preprocessor::isSafeBufferOptOut(const SourceManager &SourceMgr, + const SourceLocation &Loc) const { + // Try to find a region in `SafeBufferOptOutMap` where `Loc` is in: + auto FirstRegionEndingAfterLoc = llvm::partition_point( + SafeBufferOptOutMap, + [&SourceMgr, + &Loc](const std::pair<SourceLocation, SourceLocation> &Region) { + return SourceMgr.isBeforeInTranslationUnit(Region.second, Loc); + }); + + if (FirstRegionEndingAfterLoc != SafeBufferOptOutMap.end()) { + // To test if the start location of the found region precedes `Loc`: + return SourceMgr.isBeforeInTranslationUnit(FirstRegionEndingAfterLoc->first, + Loc); + } + // If we do not find a region whose end location passes `Loc`, we want to + // check if the current region is still open: + if (!SafeBufferOptOutMap.empty() && + SafeBufferOptOutMap.back().first == SafeBufferOptOutMap.back().second) + return SourceMgr.isBeforeInTranslationUnit(SafeBufferOptOutMap.back().first, + Loc); + return false; +} + +bool Preprocessor::enterOrExitSafeBufferOptOutRegion( + bool isEnter, const SourceLocation &Loc) { + if (isEnter) { + if (isPPInSafeBufferOptOutRegion()) + return true; // invalid enter action + InSafeBufferOptOutRegion = true; + CurrentSafeBufferOptOutStart = Loc; + + // To set the start location of a new region: + + if (!SafeBufferOptOutMap.empty()) { + auto *PrevRegion = &SafeBufferOptOutMap.back(); + assert(PrevRegion->first != PrevRegion->second && + "Shall not begin a safe buffer opt-out region before closing the " + "previous one."); + } + // If the start location equals to the end location, we call the region a + // open region or a unclosed region (i.e., end location has not been set + // yet). + SafeBufferOptOutMap.emplace_back(Loc, Loc); + } else { + if (!isPPInSafeBufferOptOutRegion()) + return true; // invalid enter action + InSafeBufferOptOutRegion = false; + + // To set the end location of the current open region: + + assert(!SafeBufferOptOutMap.empty() && + "Misordered safe buffer opt-out regions"); + auto *CurrRegion = &SafeBufferOptOutMap.back(); + assert(CurrRegion->first == CurrRegion->second && + "Set end location to a closed safe buffer opt-out region"); + CurrRegion->second = Loc; + } + return false; +} + +bool Preprocessor::isPPInSafeBufferOptOutRegion() { + return InSafeBufferOptOutRegion; +} +bool Preprocessor::isPPInSafeBufferOptOutRegion(SourceLocation &StartLoc) { + StartLoc = CurrentSafeBufferOptOutStart; + return InSafeBufferOptOutRegion; +} + ModuleLoader::~ModuleLoader() = default; CommentHandler::~CommentHandler() = default; |