@@ -8,22 +8,31 @@ OverflowBehaviorTypes
8
8
Introduction
9
9
============
10
10
11
- Clang provides a type attribute that allows developers to have fine-grained control
12
- over the overflow behavior of integer types. The `` overflow_behavior ``
13
- attribute can be used to specify how arithmetic operations on a given integer
11
+ Clang provides overflow behavior types that allow developers to have fine-grained control
12
+ over the overflow behavior of integer types. Overflow behavior can be specified using
13
+ either attribute syntax or keyword syntax to control how arithmetic operations on a given integer
14
14
type should behave upon overflow. This is particularly useful for projects that
15
15
need to balance performance and safety, allowing developers to enable or
16
16
disable overflow checks for specific types.
17
17
18
- The attribute can be enabled using the compiler option
18
+ Overflow behavior types can be enabled using the compiler option
19
19
``-foverflow-behavior-types ``.
20
20
21
- The attribute syntax is as follows:
21
+ There are two syntax options for specifying overflow behavior:
22
+
23
+ **Attribute syntax: **
22
24
23
25
.. code-block :: c++
24
26
25
27
__attribute__((overflow_behavior(behavior)))
26
28
29
+ **Keyword syntax: **
30
+
31
+ .. code-block :: c++
32
+
33
+ __wrap // equivalent to __attribute__((overflow_behavior(wrap)))
34
+ __no_wrap // equivalent to __attribute__((overflow_behavior(no_wrap)))
35
+
27
36
Where ``behavior `` can be one of the following:
28
37
29
38
* ``wrap ``: Specifies that arithmetic operations on the integer type should
@@ -50,7 +59,9 @@ characteristics of result types across all scenarios are described under `Promot
50
59
Examples
51
60
========
52
61
53
- Here is an example of how to use the ``overflow_behavior `` attribute with a ``typedef ``:
62
+ Here are examples using both syntax options:
63
+
64
+ **Using attribute syntax with a typedef: **
54
65
55
66
.. code-block :: c++
56
67
@@ -60,7 +71,17 @@ Here is an example of how to use the ``overflow_behavior`` attribute with a ``ty
60
71
return a + 1; // Overflow is checked for this operation.
61
72
}
62
73
63
- Here is an example of how to use the ``overflow_behavior `` attribute with a type directly:
74
+ **Using keyword syntax with a typedef: **
75
+
76
+ .. code-block :: c++
77
+
78
+ typedef unsigned int __no_wrap non_wrapping_uint;
79
+
80
+ non_wrapping_uint add_one(non_wrapping_uint a) {
81
+ return a + 1; // Overflow is checked for this operation.
82
+ }
83
+
84
+ **Using attribute syntax with a type directly: **
64
85
65
86
.. code-block :: c++
66
87
@@ -69,6 +90,15 @@ Here is an example of how to use the ``overflow_behavior`` attribute with a type
69
90
return a * 1337; // Potential overflow is not checked and is well-defined
70
91
}
71
92
93
+ **Using keyword syntax with a type directly: **
94
+
95
+ .. code-block :: c++
96
+
97
+ int mul_alot(int n) {
98
+ int __wrap a = n;
99
+ return a * 1337; // Potential overflow is not checked and is well-defined
100
+ }
101
+
72
102
"Well-defined" overflow is consistent with two's complement wrap-around
73
103
semantics and won't be removed via eager compiler optimizations (like some
74
104
undefined behavior might).
@@ -91,7 +121,7 @@ variety of scenarios is detailed below.
91
121
92
122
.. code-block :: c++
93
123
94
- typedef char __attribute__((overflow_behavior(no_wrap))) no_wrap_char;
124
+ typedef char __no_wrap no_wrap_char;
95
125
no_wrap_char c;
96
126
unsigned long ul;
97
127
auto result = c + ul; // result is no_wrap_char
@@ -103,8 +133,8 @@ variety of scenarios is detailed below.
103
133
104
134
.. code-block :: c++
105
135
106
- typedef unsigned char __attribute__((overflow_behavior(wrap))) u8_wrap;
107
- typedef unsigned short __attribute__((overflow_behavior(wrap))) u16_wrap;
136
+ typedef unsigned char __wrap u8_wrap;
137
+ typedef unsigned short __wrap u16_wrap;
108
138
u8_wrap a;
109
139
u16_wrap b;
110
140
auto result = a + b; // result is u16_wrap
@@ -143,13 +173,13 @@ promotion rules:
143
173
144
174
.. code-block :: c++
145
175
146
- unsigned short __attribute__((overflow_behavior(no_wrap))) a = 0; // u16 __no_wrap
176
+ unsigned short __no_wrap a = 0; // u16 __no_wrap
147
177
148
178
// Normally, arithmetic that is less-than-int is promoted to at least int.
149
179
// Following traditional C promotion rules: u16 + s32 results in s32
150
180
// However, since `a ` is an OBT, our special promotion rules apply: u16 __no_wrap + s32 results in u16 __no_wrap
151
181
152
- a + 1; // result is short __attribute__((overflow_behavior(no_wrap)))
182
+ a + 1; // result is short __no_wrap
153
183
154
184
Conversion Semantics
155
185
====================
@@ -174,9 +204,6 @@ the **destination type**:
174
204
175
205
.. code-block :: c++
176
206
177
- #define __wrap __attribute__((overflow_behavior(wrap)))
178
- #define __no_wrap __attribute__((overflow_behavior(no_wrap)))
179
-
180
207
// Examples of constant conversion behavior
181
208
short x1 = (int __wrap)100000; // Warning: truncation to standard type
182
209
short __wrap x2 = (int)100000; // No warning: wrapping destination (also no UBSan truncation warning)
@@ -202,15 +229,15 @@ version.
202
229
.. code-block :: c++
203
230
204
231
char x = 1;
205
- int __attribute__((overflow_behavior(wrap))) a = x; // x converted to int __attribute__((overflow_behavior(wrap)))
232
+ int __wrap a = x; // x converted to int __wrap
206
233
207
234
When assigning one overflow behavior type to another, the left-hand side's type
208
235
is always used - just like with traditional integer types.
209
236
210
237
.. code-block :: c++
211
238
212
- long __attribute__((overflow_behavior(wrap))) x = __LONG_MAX__;
213
- int __attribute__((overflow_behavior(no_wrap))) a = x; // x converted to int __attribute__((overflow_behavior(no_wrap)))
239
+ long __wrap x = __LONG_MAX__;
240
+ int __no_wrap a = x; // x converted to int __no_wrap
214
241
215
242
For the purposes of truncation warnings from UBSAN or ``-Wconversion ``, the
216
243
left-hand side's overflow behavior determines the instrumentation and
@@ -236,9 +263,6 @@ conversion, the behavior depends on the **destination type**:
236
263
237
264
.. code-block :: c++
238
265
239
- #define __wrap __attribute__((overflow_behavior(wrap)))
240
- #define __no_wrap __attribute__((overflow_behavior(no_wrap)))
241
-
242
266
// C++ narrowing conversion behavior
243
267
constexpr short __wrap x1 = {(int)100000}; // OK: wrapping destination
244
268
constexpr short x2 = {(int)100000}; // Error: standard destination
@@ -274,7 +298,7 @@ type of an OBT parameter is not enough to precisely pick an overload candidate.
274
298
275
299
.. code-block :: c++
276
300
277
- void foo(__attribute__((overflow_behavior(no_wrap))) int a);
301
+ void foo(int __no_wrap a);
278
302
void foo(short a);
279
303
280
304
void bar(int a) {
@@ -287,7 +311,7 @@ candidates are not implicitly convertible.
287
311
288
312
.. code-block :: c++
289
313
290
- void foo(__attribute__((overflow_behavior(no_wrap))) int a);
314
+ void foo(int __no_wrap a);
291
315
void foo(char *a);
292
316
293
317
void bar(int a) {
@@ -300,8 +324,8 @@ certain contexts.
300
324
301
325
.. code-block :: c++
302
326
303
- void foo(__attribute__((overflow_behavior(no_wrap))) int a);
304
- void foo(__attribute__((overflow_behavior(wrap))) int a);
327
+ void foo(int __no_wrap a);
328
+ void foo(int __wrap a);
305
329
306
330
void bar(int a) {
307
331
foo(a); // call to 'foo' is ambiguous
@@ -323,7 +347,7 @@ behavior kind.
323
347
324
348
.. code-block :: c++
325
349
326
- typedef int __attribute__((overflow_behavior(wrap))) wrap_int;
350
+ typedef int __wrap wrap_int;
327
351
328
352
int foo(wrap_int x) {
329
353
return _Generic(x, int: 1, char: 2, default: 3); // returns 3
@@ -353,12 +377,12 @@ specialization purposes, enabling precise type-based template selection.
353
377
};
354
378
355
379
template<>
356
- struct TypeProcessor<int __attribute__((overflow_behavior(wrap))) > {
380
+ struct TypeProcessor<int __wrap > {
357
381
static constexpr int value = 2; // __wrap int specialization
358
382
};
359
383
360
384
template<>
361
- struct TypeProcessor<int __attribute__((overflow_behavior(no_wrap))) > {
385
+ struct TypeProcessor<int __no_wrap > {
362
386
static constexpr int value = 3; // __no_wrap int specialization
363
387
};
364
388
@@ -420,7 +444,7 @@ overflow behavior.
420
444
421
445
.. code-block :: c++
422
446
423
- typedef int __attribute__((overflow_behavior(wrap))) wrapping_int;
447
+ typedef int __wrap wrapping_int;
424
448
425
449
void some_function(int);
426
450
@@ -434,7 +458,7 @@ integer type.
434
458
435
459
.. code-block :: c++
436
460
437
- typedef int __attribute__((overflow_behavior(wrap))) wrapping_int;
461
+ typedef int __wrap wrapping_int;
438
462
439
463
void some_function(int);
440
464
@@ -460,7 +484,7 @@ loss of the specified overflow behavior. This is the main warning in the
460
484
461
485
.. code-block :: c++
462
486
463
- typedef int __attribute__((overflow_behavior(wrap))) wrapping_int;
487
+ typedef int __wrap wrapping_int;
464
488
465
489
void some_function() {
466
490
wrapping_int w = 1;
@@ -473,7 +497,7 @@ Here's another example showing function parameter conversion with a ``no_wrap``
473
497
474
498
.. code-block :: c++
475
499
476
- typedef int __attribute__((overflow_behavior(no_wrap))) safe_int;
500
+ typedef int __no_wrap safe_int;
477
501
478
502
void bar(int x); // Function expects standard int
479
503
@@ -489,8 +513,8 @@ integer type.
489
513
490
514
.. code-block :: c++
491
515
492
- typedef int __attribute__((overflow_behavior(wrap))) wrapping_int;
493
- typedef int __attribute__((overflow_behavior(no_wrap))) safe_int;
516
+ typedef int __wrap wrapping_int;
517
+ typedef int __no_wrap safe_int;
494
518
495
519
void some_function() {
496
520
wrapping_int w = 1;
@@ -516,7 +540,7 @@ allowing developers to control assignment-specific warnings separately.
516
540
517
541
.. code-block :: c++
518
542
519
- typedef int __attribute__((overflow_behavior(wrap))) wrapping_int;
543
+ typedef int __wrap wrapping_int;
520
544
521
545
void some_function() {
522
546
wrapping_int w = 1;
@@ -540,7 +564,7 @@ explicit ``overflow_behavior`` attribute.
540
564
541
565
.. code-block :: c++
542
566
543
- typedef unsigned int __attribute__((overflow_behavior(wrap))) wrapping_uint;
567
+ typedef unsigned int __wrap wrapping_uint;
544
568
545
569
void some_function(unsigned int);
546
570
@@ -564,8 +588,8 @@ types when passed to any varargs function.
564
588
565
589
#include <cstdio>
566
590
567
- typedef int __attribute__((overflow_behavior(wrap))) wrap_int;
568
- typedef unsigned int __attribute__((overflow_behavior(no_wrap))) nowrap_uint;
591
+ typedef int __wrap wrap_int;
592
+ typedef unsigned int __no_wrap nowrap_uint;
569
593
570
594
void example() {
571
595
wrap_int wi = 42;
@@ -582,14 +606,14 @@ format string functions without requiring special format specifiers, while
582
606
still maintaining their overflow behavior semantics in arithmetic operations.
583
607
584
608
The format string checker uses the underlying type to determine compatibility,
585
- so ``int __attribute__((overflow_behavior(wrap))) `` is fully compatible with
609
+ so ``int __wrap `` is fully compatible with
586
610
``%d ``, ``%i ``, ``%x ``, etc., just like a regular ``int `` would be.
587
611
588
612
-Woverflow-behavior-attribute-ignored
589
613
-------------------------------------
590
614
591
- This warning is issued when the `` overflow_behavior `` attribute is applied to
592
- a type that is not an integer type.
615
+ This warning is issued when attempting to create an overflow behavior type from
616
+ a non- integer type.
593
617
594
618
.. code-block :: c++
595
619
0 commit comments