Skip to content
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
584 changes: 584 additions & 0 deletions clang/docs/OverflowBehaviorTypes.rst

Large diffs are not rendered by default.

7 changes: 6 additions & 1 deletion clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@ New Compiler Flags
------------------
- 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``).
- 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``).

- New option ``-foverflow-behavior-types`` added to enable parsing of the ``overflow_behavior`` type attribute and type specifiers.

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

- Introduced a new type attribute ``__attribute__((overflow_behavior))`` which
currently accepts either ``wrap`` or ``trap`` as an argument, enabling
type-level control over overflow behavior. There is also an accompanying type
specifier for each behavior kind via `__ob_wrap` and `__ob_trap`.

Improvements to Clang's diagnostics
-----------------------------------
- Added a separate diagnostic group ``-Wfunction-effect-redeclarations``, for the more pedantic
Expand Down
34 changes: 34 additions & 0 deletions clang/docs/SanitizerSpecialCaseList.rst
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,40 @@ precedence. Here are a few examples.
fun:*bar
fun:bad_bar=sanitize

Interaction with Overflow Behavior Types
----------------------------------------

The ``overflow_behavior`` attribute provides a more granular, source-level
control that takes precedence over the Sanitizer Special Case List. If a type
is given an ``overflow_behavior`` attribute, it will override any matching
``type:`` entry in a special case list.

This allows developers to enforce a specific overflow behavior for a critical
type, even if a broader rule in the special case list would otherwise disable
instrumentation for it.

.. code-block:: bash

$ cat ignorelist.txt
# Disable signed overflow checks for all types by default.
[signed-integer-overflow]
type:*

$ cat foo.c
// Force 'critical_type' to always have overflow checks,
// overriding the ignorelist.
typedef int __attribute__((overflow_behavior(trap))) critical_type;

void foo(int x) {
critical_type a = x;
a++; // Overflow is checked here due to the 'trap' attribute.

int b = x;
b++; // Overflow is NOT checked here due to the ignorelist.
}

For more details on overflow behavior types, see :doc:`OverflowBehaviorTypes`.

Format
======

Expand Down
36 changes: 36 additions & 0 deletions clang/docs/UndefinedBehaviorSanitizer.rst
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,42 @@ This attribute may not be
supported by other compilers, so consider using it together with
``#if defined(__clang__)``.

Disabling Overflow Instrumentation with ``__attribute__((overflow_behavior(wrap)))``
------------------------------------------------------------------------------------

For more fine-grained control over how integer overflow is handled, you can use
the ``__attribute__((overflow_behavior(wrap)))`` attribute. This attribute can
be applied to ``typedef`` declarations and integer types to specify that
arithmetic operations on that type should wrap on overflow. This can be used to
disable overflow sanitization for specific types, while leaving it enabled for
all other types.

The ``overflow_behavior`` attribute not only affects UBSan instrumentation
but also changes the fundamental overflow behavior of arithmetic operations
on the annotated type. Operations on types marked with ``wrap`` will have
well-defined wrapping semantics, while operations on types marked with
``trap`` will be checked for overflow (regardless of global flags like
``-fwrapv``).

The attribute also affects implicit type promotion rules: when an overflow
behavior type participates in arithmetic operations with standard integer
types, the result maintains the overflow behavior type's characteristics,
including its bit-width. This means annotated types can preserve narrower
widths that would normally be promoted, allowing operations to stay within
the constraints of the smallest annotated type in the expression.

For more information, see :doc:`OverflowBehaviorTypes`.

Enforcing Overflow Instrumentation with ``__attribute__((overflow_behavior(trap)))``
---------------------------------------------------------------------------------------

Conversely, you can use ``__attribute__((overflow_behavior(trap)))`` to
enforce overflow checks for a specific type, even when ``-fwrapv`` is enabled
globally. This is useful for ensuring that critical calculations are always
checked for overflow, regardless of the global compiler settings.

For more information, see :doc:`OverflowBehaviorTypes`.

Suppressing Errors in Recompiled Code (Ignorelist)
--------------------------------------------------

Expand Down
1 change: 1 addition & 0 deletions clang/docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ Using Clang as a Compiler
SanitizerCoverage
SanitizerStats
SanitizerSpecialCaseList
OverflowBehaviorTypes
BoundsSafety
BoundsSafetyAdoptionGuide
BoundsSafetyImplPlans
Expand Down
25 changes: 25 additions & 0 deletions clang/include/clang/AST/ASTContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#ifndef LLVM_CLANG_AST_ASTCONTEXT_H
#define LLVM_CLANG_AST_ASTCONTEXT_H

#include "Type.h"
#include "clang/AST/ASTFwd.h"
#include "clang/AST/CanonicalType.h"
#include "clang/AST/CommentCommandTraits.h"
Expand Down Expand Up @@ -291,6 +292,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
mutable llvm::ContextualFoldingSet<DependentBitIntType, ASTContext &>
DependentBitIntTypes;
mutable llvm::FoldingSet<BTFTagAttributedType> BTFTagAttributedTypes;
mutable llvm::FoldingSet<OverflowBehaviorType> OverflowBehaviorTypes;
llvm::FoldingSet<HLSLAttributedResourceType> HLSLAttributedResourceTypes;
llvm::FoldingSet<HLSLInlineSpirvType> HLSLInlineSpirvTypes;

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

bool isUnaryOverflowPatternExcluded(const UnaryOperator *UO);

const XRayFunctionFilter &getXRayFilter() const {
return *XRayFilter;
}
Expand Down Expand Up @@ -1038,6 +1042,15 @@ class ASTContext : public RefCountedBase<ASTContext> {
comments::FullComment *getCommentForDecl(const Decl *D,
const Preprocessor *PP) const;

/// Attempts to merge two types that may be OverflowBehaviorTypes.
///
/// \returns A QualType if the types were handled, std::nullopt otherwise.
/// A null QualType indicates an incompatible merge.
std::optional<QualType>
tryMergeOverflowBehaviorTypes(QualType LHS, QualType RHS, bool OfBlockPointer,
bool Unqualified, bool BlockReturnType,
bool IsConditionalOperator);

/// Return parsed documentation comment attached to a given declaration.
/// Returns nullptr if no comment is attached. Does not look at any
/// redeclarations of the declaration.
Expand Down Expand Up @@ -1913,6 +1926,13 @@ class ASTContext : public RefCountedBase<ASTContext> {
QualType getBTFTagAttributedType(const BTFTypeTagAttr *BTFAttr,
QualType Wrapped) const;

QualType getOverflowBehaviorType(const OverflowBehaviorAttr *Attr,
QualType Wrapped) const;

QualType
getOverflowBehaviorType(OverflowBehaviorType::OverflowBehaviorKind Kind,
QualType Wrapped) const;

QualType getHLSLAttributedResourceType(
QualType Wrapped, QualType Contained,
const HLSLAttributedResourceType::Attributes &Attrs);
Expand Down Expand Up @@ -2610,6 +2630,11 @@ class ASTContext : public RefCountedBase<ASTContext> {
/// types.
bool areCompatibleVectorTypes(QualType FirstVec, QualType SecondVec);

/// Return true if two OverflowBehaviorTypes are compatible for assignment.
/// This checks both the underlying type compatibility and the overflow
/// behavior kind (trap vs wrap).
bool areCompatibleOverflowBehaviorTypes(QualType LHS, QualType RHS);

/// Return true if the given types are an RISC-V vector builtin type and a
/// VectorType that is a fixed-length representation of the RISC-V vector
/// builtin type for a specific vector-length.
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/AST/ASTNodeTraverser.h
Original file line number Diff line number Diff line change
Expand Up @@ -447,6 +447,9 @@ class ASTNodeTraverser
void VisitBTFTagAttributedType(const BTFTagAttributedType *T) {
Visit(T->getWrappedType());
}
void VisitOverflowBehaviorType(const OverflowBehaviorType *T) {
Visit(T->getUnderlyingType());
}
void VisitHLSLAttributedResourceType(const HLSLAttributedResourceType *T) {
QualType Contained = T->getContainedType();
if (!Contained.isNull())
Expand Down
2 changes: 2 additions & 0 deletions clang/include/clang/AST/PropertiesBase.td
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ def AutoTypeKeyword : EnumPropertyType;
def Bool : PropertyType<"bool">;
def BuiltinTypeKind : EnumPropertyType<"BuiltinType::Kind">;
def BTFTypeTagAttr : PropertyType<"const BTFTypeTagAttr *">;
def OverflowBehaviorKind
: EnumPropertyType<"OverflowBehaviorType::OverflowBehaviorKind">;
def CallingConv : EnumPropertyType;
def DeclarationName : PropertyType;
def DeclarationNameKind : EnumPropertyType<"DeclarationName::NameKind">;
Expand Down
6 changes: 6 additions & 0 deletions clang/include/clang/AST/RecursiveASTVisitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -1157,6 +1157,9 @@ DEF_TRAVERSE_TYPE(CountAttributedType, {
DEF_TRAVERSE_TYPE(BTFTagAttributedType,
{ TRY_TO(TraverseType(T->getWrappedType())); })

DEF_TRAVERSE_TYPE(OverflowBehaviorType,
{ TRY_TO(TraverseType(T->getUnderlyingType())); })

DEF_TRAVERSE_TYPE(HLSLAttributedResourceType,
{ TRY_TO(TraverseType(T->getWrappedType())); })

Expand Down Expand Up @@ -1512,6 +1515,9 @@ DEF_TRAVERSE_TYPELOC(CountAttributedType,
DEF_TRAVERSE_TYPELOC(BTFTagAttributedType,
{ TRY_TO(TraverseTypeLoc(TL.getWrappedLoc())); })

DEF_TRAVERSE_TYPELOC(OverflowBehaviorType,
{ TRY_TO(TraverseTypeLoc(TL.getWrappedLoc())); })

DEF_TRAVERSE_TYPELOC(HLSLAttributedResourceType,
{ TRY_TO(TraverseTypeLoc(TL.getWrappedLoc())); })

Expand Down
58 changes: 57 additions & 1 deletion clang/include/clang/AST/TypeBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -1149,6 +1149,12 @@ class QualType {
/// Returns true if it is a WebAssembly Funcref Type.
bool isWebAssemblyFuncrefType() const;

/// Returns true if it is a OverflowBehaviorType of Wrap kind.
bool isWrapType() const;

/// Returns true if it is a OverflowBehaviorType of Trap kind.
bool isTrapType() const;

// Don't promise in the API that anything besides 'const' can be
// easily added.

Expand Down Expand Up @@ -2643,6 +2649,7 @@ class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase {
bool isSubscriptableVectorType() const;
bool isMatrixType() const; // Matrix type.
bool isConstantMatrixType() const; // Constant matrix type.
bool isOverflowBehaviorType() const; // __attribute__((no_sanitize))
bool isDependentAddressSpaceType() const; // value-dependent address space qualifier
bool isObjCObjectPointerType() const; // pointer to ObjC object
bool isObjCRetainableType() const; // ObjC object or block pointer
Expand Down Expand Up @@ -6690,6 +6697,44 @@ class BTFTagAttributedType : public Type, public llvm::FoldingSetNode {
}
};

class OverflowBehaviorType : public Type, public llvm::FoldingSetNode {
public:
enum OverflowBehaviorKind { Wrap, Trap };

private:
friend class ASTContext; // ASTContext creates these

QualType UnderlyingType;
OverflowBehaviorKind BehaviorKind;

OverflowBehaviorType(QualType Canon, QualType Underlying,
OverflowBehaviorKind Kind);

public:
QualType getUnderlyingType() const { return UnderlyingType; }
OverflowBehaviorKind getBehaviorKind() const { return BehaviorKind; }

bool isWrapKind() const { return BehaviorKind == OverflowBehaviorKind::Wrap; }
bool isTrapKind() const { return BehaviorKind == OverflowBehaviorKind::Trap; }

bool isSugared() const { return false; }
QualType desugar() const { return getUnderlyingType(); }

void Profile(llvm::FoldingSetNodeID &ID) {
Profile(ID, UnderlyingType, BehaviorKind);
}

static void Profile(llvm::FoldingSetNodeID &ID, QualType Underlying,
OverflowBehaviorKind Kind) {
ID.AddPointer(Underlying.getAsOpaquePtr());
ID.AddInteger((int)Kind);
}

static bool classof(const Type *T) {
return T->getTypeClass() == OverflowBehavior;
}
};

class HLSLAttributedResourceType : public Type, public llvm::FoldingSetNode {
public:
struct Attributes {
Expand Down Expand Up @@ -8693,6 +8738,10 @@ inline bool Type::isConstantMatrixType() const {
return isa<ConstantMatrixType>(CanonicalType);
}

inline bool Type::isOverflowBehaviorType() const {
return isa<OverflowBehaviorType>(CanonicalType);
}

inline bool Type::isDependentAddressSpaceType() const {
return isa<DependentAddressSpaceType>(CanonicalType);
}
Expand Down Expand Up @@ -8937,6 +8986,10 @@ inline bool Type::isIntegerType() const {
return IsEnumDeclComplete(ET->getOriginalDecl()) &&
!IsEnumDeclScoped(ET->getOriginalDecl());
}

if (const auto *OT = dyn_cast<OverflowBehaviorType>(CanonicalType))
return OT->getUnderlyingType()->isIntegerType();

return isBitIntType();
}

Expand Down Expand Up @@ -8999,7 +9052,7 @@ inline bool Type::isScalarType() const {
isa<MemberPointerType>(CanonicalType) ||
isa<ComplexType>(CanonicalType) ||
isa<ObjCObjectPointerType>(CanonicalType) ||
isBitIntType();
isOverflowBehaviorType() || isBitIntType();
}

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

if (const auto *OBT = dyn_cast<OverflowBehaviorType>(CanonicalType))
return OBT->getUnderlyingType()->isIntegralOrEnumerationType();

return isBitIntType();
}

Expand Down
28 changes: 28 additions & 0 deletions clang/include/clang/AST/TypeLoc.h
Original file line number Diff line number Diff line change
Expand Up @@ -1082,6 +1082,34 @@ class BTFTagAttributedTypeLoc
QualType getInnerType() const { return getTypePtr()->getWrappedType(); }
};

struct OverflowBehaviorLocInfo {
SourceLocation AttrLoc;
};

class OverflowBehaviorTypeLoc
: public ConcreteTypeLoc<UnqualTypeLoc, OverflowBehaviorTypeLoc,
OverflowBehaviorType, OverflowBehaviorLocInfo> {
public:
TypeLoc getWrappedLoc() const { return getInnerTypeLoc(); }

/// The no_sanitize type attribute.
OverflowBehaviorType::OverflowBehaviorKind getBehaviorKind() const {
return getTypePtr()->getBehaviorKind();
}

SourceRange getLocalSourceRange() const;

void initializeLocal(ASTContext &Context, SourceLocation loc) {
setAttrLoc(loc);
}

SourceLocation getAttrLoc() const { return getLocalData()->AttrLoc; }

void setAttrLoc(SourceLocation loc) { getLocalData()->AttrLoc = loc; }

QualType getInnerType() const { return getTypePtr()->getUnderlyingType(); }
};

struct HLSLAttributedResourceLocInfo {
SourceRange Range;
TypeSourceInfo *ContainedTyInfo;
Expand Down
13 changes: 13 additions & 0 deletions clang/include/clang/AST/TypeProperties.td
Original file line number Diff line number Diff line change
Expand Up @@ -652,6 +652,19 @@ let Class = BTFTagAttributedType in {
}]>;
}

let Class = OverflowBehaviorType in {
def : Property<"behaviorKind", OverflowBehaviorKind> {
let Read = [{ node->getBehaviorKind() }];
}
def : Property<"underlyingType", QualType> {
let Read = [{ node->getUnderlyingType() }];
}

def : Creator<[{
return ctx.getOverflowBehaviorType(behaviorKind, underlyingType);
}]>;
}

let Class = HLSLAttributedResourceType in {
def : Property<"resClass", UInt32> {
let Read = [{ static_cast<uint32_t>(node->getAttrs().ResourceClass) }];
Expand Down
7 changes: 7 additions & 0 deletions clang/include/clang/Basic/Attr.td
Original file line number Diff line number Diff line change
Expand Up @@ -5280,3 +5280,10 @@ def NonString : InheritableAttr {
let Subjects = SubjectList<[Var, Field]>;
let Documentation = [NonStringDocs];
}

def OverflowBehavior : TypeAttr {
let Spellings = [Clang<"overflow_behavior">];
let Args = [IdentifierArgument<"BehaviorKind">];
let Subjects = SubjectList<[Var, TypedefName, Field]>;
let Documentation = [Undocumented];
}
Loading