Skip to content

Commit f299de8

Browse files
committed
[Clang] implement OverflowBehaviorTypes
Signed-off-by: Justin Stitt <[email protected]>
1 parent d2fbca8 commit f299de8

File tree

67 files changed

+2923
-156
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

67 files changed

+2923
-156
lines changed

clang/docs/OverflowBehaviorTypes.rst

Lines changed: 603 additions & 0 deletions
Large diffs are not rendered by default.

clang/docs/ReleaseNotes.rst

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,22 @@ Lanai Support
221221
^^^^^^^^^^^^^^
222222
- The option ``-mcmodel={small,medium,large}`` is supported again.
223223

224+
- New option ``-Wundef-true`` added and enabled by default to warn when `true` is used in the C preprocessor without being defined before C23.
225+
226+
- New option ``-fprofile-continuous`` added to enable continuous profile syncing to file (#GH124353, `docs <https://clang.llvm.org/docs/UsersManual.html#cmdoption-fprofile-continuous>`_).
227+
The feature has `existed <https://clang.llvm.org/docs/SourceBasedCodeCoverage.html#running-the-instrumented-program>`_)
228+
for a while and this is just a user facing option.
229+
230+
- New option ``-ftime-report-json`` added which outputs the same timing data as ``-ftime-report`` but formatted as JSON.
231+
232+
- New option ``-Wnrvo`` added and disabled by default to warn about missed NRVO opportunities.
233+
234+
- New option ``-ignore-pch`` added to disable precompiled headers. It overrides ``-emit-pch`` and ``-include-pch``. (#GH142409, `PCHDocs <https://clang.llvm.org/docs/UsersManual.html#ignoring-a-pch-file>`_).
235+
236+
- New options ``-g[no-]key-instructions`` added, disabled by default. Reduces jumpiness of debug stepping for optimized code in some debuggers (not LLDB at this time). Not recommended for use without optimizations. DWARF only. Note both the positive and negative flags imply ``-g``.
237+
238+
- New option ``-foverflow-behavior-types`` added to enable parsing of the ``overflow_behavior`` type attribute.
239+
224240
Deprecated Compiler Flags
225241
-------------------------
226242

@@ -234,6 +250,10 @@ Removed Compiler Flags
234250
Attribute Changes in Clang
235251
--------------------------
236252

253+
- Introduced a new type attribute ``__attribute__((overflow_behavior))`` which
254+
currently accepts either ``wrap`` or ``no_wrap`` as an argument, enabling
255+
type-level control over overflow behavior.
256+
237257
Improvements to Clang's diagnostics
238258
-----------------------------------
239259
- Added a separate diagnostic group ``-Wfunction-effect-redeclarations``, for the more pedantic

clang/docs/SanitizerSpecialCaseList.rst

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,40 @@ precedence. Here are a few examples.
134134
fun:*bar
135135
fun:bad_bar=sanitize
136136
137+
Interaction with Overflow Behavior Types
138+
----------------------------------------
139+
140+
The ``overflow_behavior`` attribute provides a more granular, source-level
141+
control that takes precedence over the Sanitizer Special Case List. If a type
142+
is given an ``overflow_behavior`` attribute, it will override any matching
143+
``type:`` entry in a special case list.
144+
145+
This allows developers to enforce a specific overflow behavior for a critical
146+
type, even if a broader rule in the special case list would otherwise disable
147+
instrumentation for it.
148+
149+
.. code-block:: bash
150+
151+
$ cat ignorelist.txt
152+
# Disable signed overflow checks for all types by default.
153+
[signed-integer-overflow]
154+
type:*
155+
156+
$ cat foo.c
157+
// Force 'critical_type' to always have overflow checks,
158+
// overriding the ignorelist.
159+
typedef int __attribute__((overflow_behavior(no_wrap))) critical_type;
160+
161+
void foo(int x) {
162+
critical_type a = x;
163+
a++; // Overflow is checked here due to the 'no_wrap' attribute.
164+
165+
int b = x;
166+
b++; // Overflow is NOT checked here due to the ignorelist.
167+
}
168+
169+
For more details on overflow behavior types, see :doc:`OverflowBehaviorTypes`.
170+
137171
Format
138172
======
139173

clang/docs/UndefinedBehaviorSanitizer.rst

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,42 @@ This attribute may not be
380380
supported by other compilers, so consider using it together with
381381
``#if defined(__clang__)``.
382382

383+
Disabling Overflow Instrumentation with ``__attribute__((overflow_behavior(wrap)))``
384+
------------------------------------------------------------------------------------
385+
386+
For more fine-grained control over how integer overflow is handled, you can use
387+
the ``__attribute__((overflow_behavior(wrap)))`` attribute. This attribute can
388+
be applied to ``typedef`` declarations and integer types to specify that
389+
arithmetic operations on that type should wrap on overflow. This can be used to
390+
disable overflow sanitization for specific types, while leaving it enabled for
391+
all other types.
392+
393+
The ``overflow_behavior`` attribute not only affects UBSan instrumentation
394+
but also changes the fundamental overflow behavior of arithmetic operations
395+
on the annotated type. Operations on types marked with ``wrap`` will have
396+
well-defined wrapping semantics, while operations on types marked with
397+
``no_wrap`` will be checked for overflow (regardless of global flags like
398+
``-fwrapv``).
399+
400+
The attribute also affects implicit type promotion rules: when an overflow
401+
behavior type participates in arithmetic operations with standard integer
402+
types, the result maintains the overflow behavior type's characteristics,
403+
including its bit-width. This means annotated types can preserve narrower
404+
widths that would normally be promoted, allowing operations to stay within
405+
the constraints of the smallest annotated type in the expression.
406+
407+
For more information, see :doc:`OverflowBehaviorTypes`.
408+
409+
Enforcing Overflow Instrumentation with ``__attribute__((overflow_behavior(no_wrap)))``
410+
---------------------------------------------------------------------------------------
411+
412+
Conversely, you can use ``__attribute__((overflow_behavior(no_wrap)))`` to
413+
enforce overflow checks for a specific type, even when ``-fwrapv`` is enabled
414+
globally. This is useful for ensuring that critical calculations are always
415+
checked for overflow, regardless of the global compiler settings.
416+
417+
For more information, see :doc:`OverflowBehaviorTypes`.
418+
383419
Suppressing Errors in Recompiled Code (Ignorelist)
384420
--------------------------------------------------
385421

clang/docs/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ Using Clang as a Compiler
4040
SanitizerCoverage
4141
SanitizerStats
4242
SanitizerSpecialCaseList
43+
OverflowBehaviorTypes
4344
BoundsSafety
4445
BoundsSafetyAdoptionGuide
4546
BoundsSafetyImplPlans

clang/include/clang/AST/ASTContext.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#ifndef LLVM_CLANG_AST_ASTCONTEXT_H
1515
#define LLVM_CLANG_AST_ASTCONTEXT_H
1616

17+
#include "Type.h"
1718
#include "clang/AST/ASTFwd.h"
1819
#include "clang/AST/CanonicalType.h"
1920
#include "clang/AST/CommentCommandTraits.h"
@@ -259,6 +260,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
259260
mutable llvm::ContextualFoldingSet<DependentBitIntType, ASTContext &>
260261
DependentBitIntTypes;
261262
mutable llvm::FoldingSet<BTFTagAttributedType> BTFTagAttributedTypes;
263+
mutable llvm::FoldingSet<OverflowBehaviorType> OverflowBehaviorTypes;
262264
llvm::FoldingSet<HLSLAttributedResourceType> HLSLAttributedResourceTypes;
263265
llvm::FoldingSet<HLSLInlineSpirvType> HLSLInlineSpirvTypes;
264266

@@ -903,6 +905,8 @@ class ASTContext : public RefCountedBase<ASTContext> {
903905
bool isTypeIgnoredBySanitizer(const SanitizerMask &Mask,
904906
const QualType &Ty) const;
905907

908+
bool isUnaryOverflowPatternExcluded(const UnaryOperator *UO);
909+
906910
const XRayFunctionFilter &getXRayFilter() const {
907911
return *XRayFilter;
908912
}
@@ -1003,6 +1007,15 @@ class ASTContext : public RefCountedBase<ASTContext> {
10031007
comments::FullComment *getCommentForDecl(const Decl *D,
10041008
const Preprocessor *PP) const;
10051009

1010+
/// Attempts to merge two types that may be OverflowBehaviorTypes.
1011+
///
1012+
/// \returns A QualType if the types were handled, std::nullopt otherwise.
1013+
/// A null QualType indicates an incompatible merge.
1014+
std::optional<QualType>
1015+
tryMergeOverflowBehaviorTypes(QualType LHS, QualType RHS, bool OfBlockPointer,
1016+
bool Unqualified, bool BlockReturnType,
1017+
bool IsConditionalOperator);
1018+
10061019
/// Return parsed documentation comment attached to a given declaration.
10071020
/// Returns nullptr if no comment is attached. Does not look at any
10081021
/// redeclarations of the declaration.
@@ -1878,6 +1891,13 @@ class ASTContext : public RefCountedBase<ASTContext> {
18781891
QualType getBTFTagAttributedType(const BTFTypeTagAttr *BTFAttr,
18791892
QualType Wrapped) const;
18801893

1894+
QualType getOverflowBehaviorType(const OverflowBehaviorAttr *Attr,
1895+
QualType Wrapped) const;
1896+
1897+
QualType
1898+
getOverflowBehaviorType(OverflowBehaviorType::OverflowBehaviorKind Kind,
1899+
QualType Wrapped) const;
1900+
18811901
QualType getHLSLAttributedResourceType(
18821902
QualType Wrapped, QualType Contained,
18831903
const HLSLAttributedResourceType::Attributes &Attrs);

clang/include/clang/AST/ASTNodeTraverser.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -447,6 +447,9 @@ class ASTNodeTraverser
447447
void VisitBTFTagAttributedType(const BTFTagAttributedType *T) {
448448
Visit(T->getWrappedType());
449449
}
450+
void VisitOverflowBehaviorType(const OverflowBehaviorType *T) {
451+
Visit(T->getUnderlyingType());
452+
}
450453
void VisitHLSLAttributedResourceType(const HLSLAttributedResourceType *T) {
451454
QualType Contained = T->getContainedType();
452455
if (!Contained.isNull())

clang/include/clang/AST/PropertiesBase.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,8 @@ def AutoTypeKeyword : EnumPropertyType;
8181
def Bool : PropertyType<"bool">;
8282
def BuiltinTypeKind : EnumPropertyType<"BuiltinType::Kind">;
8383
def BTFTypeTagAttr : PropertyType<"const BTFTypeTagAttr *">;
84+
def OverflowBehaviorKind
85+
: EnumPropertyType<"OverflowBehaviorType::OverflowBehaviorKind">;
8486
def CallingConv : EnumPropertyType;
8587
def DeclarationName : PropertyType;
8688
def DeclarationNameKind : EnumPropertyType<"DeclarationName::NameKind">;

clang/include/clang/AST/RecursiveASTVisitor.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1157,6 +1157,9 @@ DEF_TRAVERSE_TYPE(CountAttributedType, {
11571157
DEF_TRAVERSE_TYPE(BTFTagAttributedType,
11581158
{ TRY_TO(TraverseType(T->getWrappedType())); })
11591159

1160+
DEF_TRAVERSE_TYPE(OverflowBehaviorType,
1161+
{ TRY_TO(TraverseType(T->getUnderlyingType())); })
1162+
11601163
DEF_TRAVERSE_TYPE(HLSLAttributedResourceType,
11611164
{ TRY_TO(TraverseType(T->getWrappedType())); })
11621165

@@ -1512,6 +1515,9 @@ DEF_TRAVERSE_TYPELOC(CountAttributedType,
15121515
DEF_TRAVERSE_TYPELOC(BTFTagAttributedType,
15131516
{ TRY_TO(TraverseTypeLoc(TL.getWrappedLoc())); })
15141517

1518+
DEF_TRAVERSE_TYPELOC(OverflowBehaviorType,
1519+
{ TRY_TO(TraverseTypeLoc(TL.getWrappedLoc())); })
1520+
15151521
DEF_TRAVERSE_TYPELOC(HLSLAttributedResourceType,
15161522
{ TRY_TO(TraverseTypeLoc(TL.getWrappedLoc())); })
15171523

clang/include/clang/AST/TypeBase.h

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1149,6 +1149,12 @@ class QualType {
11491149
/// Returns true if it is a WebAssembly Funcref Type.
11501150
bool isWebAssemblyFuncrefType() const;
11511151

1152+
/// Returns true if it is a OverflowBehaviorType of Wrap kind.
1153+
bool isWrapType() const;
1154+
1155+
/// Returns true if it is a OverflowBehaviorType of NoWrap kind.
1156+
bool isNoWrapType() const;
1157+
11521158
// Don't promise in the API that anything besides 'const' can be
11531159
// easily added.
11541160

@@ -2643,6 +2649,7 @@ class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase {
26432649
bool isSubscriptableVectorType() const;
26442650
bool isMatrixType() const; // Matrix type.
26452651
bool isConstantMatrixType() const; // Constant matrix type.
2652+
bool isOverflowBehaviorType() const; // __attribute__((no_sanitize))
26462653
bool isDependentAddressSpaceType() const; // value-dependent address space qualifier
26472654
bool isObjCObjectPointerType() const; // pointer to ObjC object
26482655
bool isObjCRetainableType() const; // ObjC object or block pointer
@@ -6688,6 +6695,46 @@ class BTFTagAttributedType : public Type, public llvm::FoldingSetNode {
66886695
}
66896696
};
66906697

6698+
class OverflowBehaviorType : public Type, public llvm::FoldingSetNode {
6699+
public:
6700+
enum OverflowBehaviorKind { Wrap, NoWrap };
6701+
6702+
private:
6703+
friend class ASTContext; // ASTContext creates these
6704+
6705+
QualType UnderlyingType;
6706+
OverflowBehaviorKind BehaviorKind;
6707+
6708+
OverflowBehaviorType(QualType Canon, QualType Underlying,
6709+
OverflowBehaviorKind Kind);
6710+
6711+
public:
6712+
QualType getUnderlyingType() const { return UnderlyingType; }
6713+
OverflowBehaviorKind getBehaviorKind() const { return BehaviorKind; }
6714+
6715+
bool isWrapKind() const { return BehaviorKind == OverflowBehaviorKind::Wrap; }
6716+
bool isNoWrapKind() const {
6717+
return BehaviorKind == OverflowBehaviorKind::NoWrap;
6718+
}
6719+
6720+
bool isSugared() const { return false; }
6721+
QualType desugar() const { return getUnderlyingType(); }
6722+
6723+
void Profile(llvm::FoldingSetNodeID &ID) {
6724+
Profile(ID, UnderlyingType, BehaviorKind);
6725+
}
6726+
6727+
static void Profile(llvm::FoldingSetNodeID &ID, QualType Underlying,
6728+
OverflowBehaviorKind Kind) {
6729+
ID.AddPointer(Underlying.getAsOpaquePtr());
6730+
ID.AddInteger((int)Kind);
6731+
}
6732+
6733+
static bool classof(const Type *T) {
6734+
return T->getTypeClass() == OverflowBehavior;
6735+
}
6736+
};
6737+
66916738
class HLSLAttributedResourceType : public Type, public llvm::FoldingSetNode {
66926739
public:
66936740
struct Attributes {
@@ -8684,6 +8731,10 @@ inline bool Type::isConstantMatrixType() const {
86848731
return isa<ConstantMatrixType>(CanonicalType);
86858732
}
86868733

8734+
inline bool Type::isOverflowBehaviorType() const {
8735+
return isa<OverflowBehaviorType>(CanonicalType);
8736+
}
8737+
86878738
inline bool Type::isDependentAddressSpaceType() const {
86888739
return isa<DependentAddressSpaceType>(CanonicalType);
86898740
}
@@ -8928,6 +8979,10 @@ inline bool Type::isIntegerType() const {
89288979
return IsEnumDeclComplete(ET->getOriginalDecl()) &&
89298980
!IsEnumDeclScoped(ET->getOriginalDecl());
89308981
}
8982+
8983+
if (const auto *OT = dyn_cast<OverflowBehaviorType>(CanonicalType))
8984+
return OT->getUnderlyingType()->isIntegerType();
8985+
89318986
return isBitIntType();
89328987
}
89338988

@@ -8990,7 +9045,7 @@ inline bool Type::isScalarType() const {
89909045
isa<MemberPointerType>(CanonicalType) ||
89919046
isa<ComplexType>(CanonicalType) ||
89929047
isa<ObjCObjectPointerType>(CanonicalType) ||
8993-
isBitIntType();
9048+
isOverflowBehaviorType() || isBitIntType();
89949049
}
89959050

89969051
inline bool Type::isIntegralOrEnumerationType() const {
@@ -9002,6 +9057,10 @@ inline bool Type::isIntegralOrEnumerationType() const {
90029057
if (const auto *ET = dyn_cast<EnumType>(CanonicalType))
90039058
return IsEnumDeclComplete(ET->getOriginalDecl());
90049059

9060+
if (const OverflowBehaviorType *OBT =
9061+
dyn_cast<OverflowBehaviorType>(CanonicalType))
9062+
return OBT->getUnderlyingType()->isIntegralOrEnumerationType();
9063+
90059064
return isBitIntType();
90069065
}
90079066

0 commit comments

Comments
 (0)