Skip to content

Commit cdc7493

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

File tree

74 files changed

+3318
-169
lines changed

Some content is hidden

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

74 files changed

+3318
-169
lines changed

clang/docs/OverflowBehaviorTypes.rst

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

clang/docs/ReleaseNotes.rst

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,7 @@ New Compiler Flags
259259
------------------
260260
- New option ``-fno-sanitize-debug-trap-reasons`` added to disable emitting trap reasons into the debug info when compiling with trapping UBSan (e.g. ``-fsanitize-trap=undefined``).
261261
- New option ``-fsanitize-debug-trap-reasons=`` added to control emitting trap reasons into the debug info when compiling with trapping UBSan (e.g. ``-fsanitize-trap=undefined``).
262-
262+
- New option ``-foverflow-behavior-types`` added to enable parsing of the ``overflow_behavior`` type attribute and type specifiers.
263263

264264
Lanai Support
265265
^^^^^^^^^^^^^^
@@ -284,6 +284,11 @@ Attribute Changes in Clang
284284
- New format attributes ``gnu_printf``, ``gnu_scanf``, ``gnu_strftime`` and ``gnu_strfmon`` are added
285285
as aliases for ``printf``, ``scanf``, ``strftime`` and ``strfmon``. (#GH16219)
286286

287+
- Introduced a new type attribute ``__attribute__((overflow_behavior))`` which
288+
currently accepts either ``wrap`` or ``trap`` as an argument, enabling
289+
type-level control over overflow behavior. There is also an accompanying type
290+
specifier for each behavior kind via `__ob_wrap` and `__ob_trap`.
291+
287292
Improvements to Clang's diagnostics
288293
-----------------------------------
289294
- 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(trap))) critical_type;
160+
161+
void foo(int x) {
162+
critical_type a = x;
163+
a++; // Overflow is checked here due to the 'trap' 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+
``trap`` 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(trap)))``
410+
---------------------------------------------------------------------------------------
411+
412+
Conversely, you can use ``__attribute__((overflow_behavior(trap)))`` 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: 25 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"
@@ -291,6 +292,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
291292
mutable llvm::ContextualFoldingSet<DependentBitIntType, ASTContext &>
292293
DependentBitIntTypes;
293294
mutable llvm::FoldingSet<BTFTagAttributedType> BTFTagAttributedTypes;
295+
mutable llvm::FoldingSet<OverflowBehaviorType> OverflowBehaviorTypes;
294296
llvm::FoldingSet<HLSLAttributedResourceType> HLSLAttributedResourceTypes;
295297
llvm::FoldingSet<HLSLInlineSpirvType> HLSLInlineSpirvTypes;
296298

@@ -938,6 +940,8 @@ class ASTContext : public RefCountedBase<ASTContext> {
938940
bool isTypeIgnoredBySanitizer(const SanitizerMask &Mask,
939941
const QualType &Ty) const;
940942

943+
bool isUnaryOverflowPatternExcluded(const UnaryOperator *UO);
944+
941945
const XRayFunctionFilter &getXRayFilter() const {
942946
return *XRayFilter;
943947
}
@@ -1038,6 +1042,15 @@ class ASTContext : public RefCountedBase<ASTContext> {
10381042
comments::FullComment *getCommentForDecl(const Decl *D,
10391043
const Preprocessor *PP) const;
10401044

1045+
/// Attempts to merge two types that may be OverflowBehaviorTypes.
1046+
///
1047+
/// \returns A QualType if the types were handled, std::nullopt otherwise.
1048+
/// A null QualType indicates an incompatible merge.
1049+
std::optional<QualType>
1050+
tryMergeOverflowBehaviorTypes(QualType LHS, QualType RHS, bool OfBlockPointer,
1051+
bool Unqualified, bool BlockReturnType,
1052+
bool IsConditionalOperator);
1053+
10411054
/// Return parsed documentation comment attached to a given declaration.
10421055
/// Returns nullptr if no comment is attached. Does not look at any
10431056
/// redeclarations of the declaration.
@@ -1913,6 +1926,13 @@ class ASTContext : public RefCountedBase<ASTContext> {
19131926
QualType getBTFTagAttributedType(const BTFTypeTagAttr *BTFAttr,
19141927
QualType Wrapped) const;
19151928

1929+
QualType getOverflowBehaviorType(const OverflowBehaviorAttr *Attr,
1930+
QualType Wrapped) const;
1931+
1932+
QualType
1933+
getOverflowBehaviorType(OverflowBehaviorType::OverflowBehaviorKind Kind,
1934+
QualType Wrapped) const;
1935+
19161936
QualType getHLSLAttributedResourceType(
19171937
QualType Wrapped, QualType Contained,
19181938
const HLSLAttributedResourceType::Attributes &Attrs);
@@ -2610,6 +2630,11 @@ class ASTContext : public RefCountedBase<ASTContext> {
26102630
/// types.
26112631
bool areCompatibleVectorTypes(QualType FirstVec, QualType SecondVec);
26122632

2633+
/// Return true if two OverflowBehaviorTypes are compatible for assignment.
2634+
/// This checks both the underlying type compatibility and the overflow
2635+
/// behavior kind (trap vs wrap).
2636+
bool areCompatibleOverflowBehaviorTypes(QualType LHS, QualType RHS);
2637+
26132638
/// Return true if the given types are an RISC-V vector builtin type and a
26142639
/// VectorType that is a fixed-length representation of the RISC-V vector
26152640
/// builtin type for a specific vector-length.

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: 57 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 Trap kind.
1156+
bool isTrapType() 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
@@ -6690,6 +6697,44 @@ class BTFTagAttributedType : public Type, public llvm::FoldingSetNode {
66906697
}
66916698
};
66926699

6700+
class OverflowBehaviorType : public Type, public llvm::FoldingSetNode {
6701+
public:
6702+
enum OverflowBehaviorKind { Wrap, Trap };
6703+
6704+
private:
6705+
friend class ASTContext; // ASTContext creates these
6706+
6707+
QualType UnderlyingType;
6708+
OverflowBehaviorKind BehaviorKind;
6709+
6710+
OverflowBehaviorType(QualType Canon, QualType Underlying,
6711+
OverflowBehaviorKind Kind);
6712+
6713+
public:
6714+
QualType getUnderlyingType() const { return UnderlyingType; }
6715+
OverflowBehaviorKind getBehaviorKind() const { return BehaviorKind; }
6716+
6717+
bool isWrapKind() const { return BehaviorKind == OverflowBehaviorKind::Wrap; }
6718+
bool isTrapKind() const { return BehaviorKind == OverflowBehaviorKind::Trap; }
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+
66936738
class HLSLAttributedResourceType : public Type, public llvm::FoldingSetNode {
66946739
public:
66956740
struct Attributes {
@@ -8693,6 +8738,10 @@ inline bool Type::isConstantMatrixType() const {
86938738
return isa<ConstantMatrixType>(CanonicalType);
86948739
}
86958740

8741+
inline bool Type::isOverflowBehaviorType() const {
8742+
return isa<OverflowBehaviorType>(CanonicalType);
8743+
}
8744+
86968745
inline bool Type::isDependentAddressSpaceType() const {
86978746
return isa<DependentAddressSpaceType>(CanonicalType);
86988747
}
@@ -8937,6 +8986,10 @@ inline bool Type::isIntegerType() const {
89378986
return IsEnumDeclComplete(ET->getOriginalDecl()) &&
89388987
!IsEnumDeclScoped(ET->getOriginalDecl());
89398988
}
8989+
8990+
if (const auto *OT = dyn_cast<OverflowBehaviorType>(CanonicalType))
8991+
return OT->getUnderlyingType()->isIntegerType();
8992+
89408993
return isBitIntType();
89418994
}
89428995

@@ -8999,7 +9052,7 @@ inline bool Type::isScalarType() const {
89999052
isa<MemberPointerType>(CanonicalType) ||
90009053
isa<ComplexType>(CanonicalType) ||
90019054
isa<ObjCObjectPointerType>(CanonicalType) ||
9002-
isBitIntType();
9055+
isOverflowBehaviorType() || isBitIntType();
90039056
}
90049057

90059058
inline bool Type::isIntegralOrEnumerationType() const {
@@ -9011,6 +9064,9 @@ inline bool Type::isIntegralOrEnumerationType() const {
90119064
if (const auto *ET = dyn_cast<EnumType>(CanonicalType))
90129065
return IsEnumDeclComplete(ET->getOriginalDecl());
90139066

9067+
if (const auto *OBT = dyn_cast<OverflowBehaviorType>(CanonicalType))
9068+
return OBT->getUnderlyingType()->isIntegralOrEnumerationType();
9069+
90149070
return isBitIntType();
90159071
}
90169072

0 commit comments

Comments
 (0)