xref: /llvm-project/clang/docs/FunctionEffectAnalysis.rst (revision 48adfaf3b290d97260eabb53254de9ada313cd0e)
1========================
2Function Effect Analysis
3========================
4
5.. contents::
6  :depth: 3
7  :local:
8
9
10Introduction
11============
12
13Clang Function Effect Analysis is a language extension which can warn about "unsafe"
14constructs. The feature is currently tailored for the Performance Constraint attributes
15``nonblocking`` and ``nonallocating``; functions with these attributes are verified as not
16containing any language constructs or calls to other functions which violate the constraint.
17(See :doc:`AttributeReference`.)
18
19
20The ``nonblocking`` and ``nonallocating`` attributes
21====================================================
22
23Attribute syntax
24----------------
25
26The ``nonblocking`` and ``nonallocating`` attributes apply to function types, allowing them to be
27attached to functions, blocks, function pointers, lambdas, and member functions.
28
29.. code-block:: c++
30
31  // Functions
32  void nonblockingFunction() [[clang::nonblocking]];
33  void nonallocatingFunction() [[clang::nonallocating]];
34
35  // Function pointers
36  void (*nonblockingFunctionPtr)() [[clang::nonblocking]];
37
38  // Typedefs, type aliases.
39  typedef void (*NBFunctionPtrTypedef)() [[clang::nonblocking]];
40  using NBFunctionPtrTypeAlias_gnu = __attribute__((nonblocking)) void (*)();
41  using NBFunctionPtrTypeAlias_std = void (*)() [[clang::nonblocking]];
42
43  // C++ methods
44  struct Struct {
45    void NBMethod() [[clang::nonblocking]];
46  };
47
48  // C++ lambdas
49  auto nbLambda = []() [[clang::nonblocking]] {};
50
51  // Blocks
52  void (^nbBlock)() = ^() [[clang::nonblocking]] {};
53
54The attribute applies only to the function itself. In particular, it does not apply to any nested
55functions or declarations, such as blocks, lambdas, and local classes.
56
57This document uses the C++/C23 syntax ``[[clang::nonblocking]]``, since it parallels the placement
58of the ``noexcept`` specifier, and the attributes have other similarities to ``noexcept``. The GNU
59``__attribute__((nonblocking))`` syntax is also supported. Note that it requires a different
60placement on a C++ type alias.
61
62Like ``noexcept``, ``nonblocking`` and ``nonallocating`` have an optional argument, a compile-time
63constant boolean expression. By default, the argument is ``true``, so ``[[clang::nonblocking]]``
64is equivalent to ``[[clang::nonblocking(true)]]``, and declares the function type as never blocking.
65
66
67Attribute semantics
68-------------------
69
70Together with ``noexcept``, the ``nonallocating`` and ``nonblocking`` attributes define an ordered
71series of performance constraints. From weakest to strongest:
72
73- ``noexcept`` (as per the C++ standard): The function type will never throw an exception.
74- ``nonallocating``: The function type will never allocate memory on the heap or throw an
75  exception.
76- ``nonblocking``: The function type will never block on a lock, allocate memory on the heap,
77  or throw an exception.
78
79``nonblocking`` includes the ``nonallocating`` guarantee.
80
81While ``nonblocking`` and ``nonallocating`` are conceptually a superset of ``noexcept``, neither
82attribute implicitly specifies ``noexcept``. Further, ``noexcept`` has a specified runtime behavior of
83aborting if an exception is thrown, while the ``nonallocating`` and ``nonblocking`` attributes are
84mainly for compile-time analysis and have no runtime behavior, except in code built
85with Clang's :doc:`RealtimeSanitizer`. Nonetheless, Clang emits a
86warning if, in C++, a function is declared ``nonblocking`` or ``nonallocating`` without
87``noexcept``. This diagnostic is controlled by ``-Wperf-constraint-implies-noexcept``.
88
89``nonblocking(true)`` and ``nonallocating(true)`` apply to function *types*, and by extension, to
90function-like declarations. When applied to a declaration with a body, the compiler verifies the
91function, as described in the section "Analysis and warnings", below.
92
93``blocking`` and ``allocating`` are synonyms for ``nonblocking(false)`` and
94``nonallocating(false)``, respectively. They can be used on a function-like declaration to
95explicitly disable any potential inference of ``nonblocking`` or ``nonallocating`` during
96verification. (Inference is described later in this document). ``nonblocking(false)`` and
97``nonallocating(false)`` are legal, but superfluous  when applied to a function *type*
98that is not part of a declarator: ``float (int) [[nonblocking(false)]]`` and
99``float (int)`` are identical types.
100
101For functions with no explicit performance constraint, the worst is assumed: the function
102allocates memory and potentially blocks, unless it can be inferred otherwise. This is detailed in the
103discussion of verification.
104
105The following example describes the meanings of all permutations of the two attributes and arguments:
106
107.. code-block:: c++
108
109  void nb1_na1() [[clang::nonblocking(true)]] [[clang::nonallocating(true)]];
110  // Valid; nonallocating(true) is superfluous but doesn't contradict the guarantee.
111
112  void nb1_na0() [[clang::nonblocking(true)]] [[clang::nonallocating(false)]];
113  // error: 'allocating' and 'nonblocking' attributes are not compatible
114
115  void nb0_na1() [[clang::nonblocking(false)]] [[clang::nonallocating(true)]];
116  // Valid; the function does not allocate memory, but may lock for other reasons.
117
118  void nb0_na0() [[clang::nonblocking(false)]] [[clang::nonallocating(false)]];
119  // Valid.
120
121
122Type conversions
123----------------
124
125A performance constraint can be removed or weakened via an implicit conversion. An attempt to add
126or strengthen a performance constraint is unsafe and results in a warning. The rules for this
127are comparable to that for ``noexcept`` in C++17 and later.
128
129.. code-block:: c++
130
131  void unannotated();
132  void nonblocking() [[clang::nonblocking]];
133  void nonallocating() [[clang::nonallocating]];
134
135  void example()
136  {
137    // It's fine to remove a performance constraint.
138    void (*fp_plain)();
139    fp_plain = unannotated;
140    fp_plain = nonblocking;
141    fp_plain = nonallocating;
142
143    // Adding/spoofing nonblocking is unsafe.
144    void (*fp_nonblocking)() [[clang::nonblocking]];
145    fp_nonblocking = nullptr;
146    fp_nonblocking = nonblocking;
147    fp_nonblocking = unannotated;
148    // ^ warning: attribute 'nonblocking' should not be added via type conversion
149    fp_nonblocking = nonallocating;
150    // ^ warning: attribute 'nonblocking' should not be added via type conversion
151
152    // Adding/spoofing nonallocating is unsafe.
153    void (*fp_nonallocating)() [[clang::nonallocating]];
154    fp_nonallocating = nullptr;
155    fp_nonallocating = nonallocating;
156    fp_nonallocating = nonblocking; // no warning because nonblocking includes nonallocating
157    fp_nonallocating = unannotated;
158    // ^ warning: attribute 'nonallocating' should not be added via type conversion
159  }
160
161Virtual methods
162---------------
163
164In C++, when a virtual method has a performance constraint, overriding methods in
165subclasses inherit the constraint.
166
167.. code-block:: c++
168
169  struct Base {
170    virtual void unsafe();
171    virtual void safe() noexcept [[clang::nonblocking]];
172  };
173
174  struct Derived : public Base {
175    void unsafe() [[clang::nonblocking]] override;
176    // It's okay for an overridden method to be more constrained
177
178    void safe() noexcept override;
179    // This method is implicitly declared `nonblocking`, inherited from Base.
180  };
181
182Redeclarations, overloads, and name mangling
183--------------------------------------------
184
185The ``nonblocking`` and ``nonallocating`` attributes, like ``noexcept``, do not factor into
186argument-dependent lookup and overloaded functions/methods.
187
188First, consider that ``noexcept`` is integral to a function's type:
189
190.. code-block:: c++
191
192  void f1(int);
193  void f1(int) noexcept;
194  // error: exception specification in declaration does not match previous
195  //   declaration
196
197Unlike ``noexcept``, a redeclaration of ``f2`` with an added or stronger performance constraint is
198legal and propagates the attribute to the previous declaration:
199
200.. code-block:: c++
201
202  int f2();
203  int f2() [[clang::nonblocking]]; // redeclaration with stronger constraint is OK.
204
205This greatly eases adoption by making it possible to annotate functions in external libraries
206without modifying library headers.
207
208A redeclaration with a removed or weaker performance constraint produces a warning, paralleling
209the behavior of ``noexcept``:
210
211.. code-block:: c++
212
213  int f2() { return 42; }
214  // warning: attribute 'nonblocking' on function does not match previous declaration
215
216In C++14, the following two declarations of `f3` are identical (a single function). In C++17 they
217are separate overloads:
218
219.. code-block:: c++
220
221  void f3(void (*)());
222  void f3(void (*)() noexcept);
223
224Similarly, the following two declarations of `f4` are separate overloads. This pattern may pose
225difficulties due to ambiguity:
226
227.. code-block:: c++
228
229  void f4(void (*)());
230  void f4(void (*)() [[clang::nonblocking]]);
231
232The attributes have no effect on the mangling of function and method names.
233
234Objective-C
235-----------
236
237The attributes are currently unsupported on Objective-C methods.
238
239Analysis and warnings
240=====================
241
242Constraints
243-----------
244
245Functions declared ``nonallocating`` or ``nonblocking``, when defined, are verified according to the
246following rules. Such functions:
247
2481. May not allocate or deallocate memory on the heap. The analysis follows the calls to
249   ``operator new`` and ``operator delete`` generated by the ``new`` and ``delete`` keywords, and
250   treats them like any other function call. The global ``operator new`` and ``operator delete``
251   aren't declared ``nonblocking`` or ``nonallocating`` and so they are considered unsafe. (This
252   is correct because most memory allocators are not lock-free. Note that the placement form of
253   ``operator new`` is implemented inline in libc++'s ``<new>`` header, and is verifiably
254   ``nonblocking``, since it merely casts the supplied pointer to the result type.)
255
2562. May not throw or catch exceptions. To throw, the compiler must allocate the exception on the
257   heap. (Also, many subclasses of ``std::exception`` allocate a string). Exceptions are
258   deallocated when caught.
259
2603. May not make any indirect function call, via a virtual method, function pointer, or
261   pointer-to-member function, unless the target is explicitly declared with the same
262   ``nonblocking`` or ``nonallocating`` attribute (or stronger).
263
2644. May not make direct calls to any other function, with the following exceptions:
265
266  a. The callee is also explicitly declared with the same ``nonblocking`` or ``nonallocating``
267     attribute (or stronger).
268  b. The callee is defined in the same translation unit as the caller, does not have the ``false``
269     form of the required attribute, and can be verified to have the same attribute or stronger,
270     according to these same rules.
271  c. The callee is a built-in function that is known not to block or allocate.
272  d. The callee is declared ``noreturn`` and, if compiling C++, the callee is also declared
273     ``noexcept``. This special case excludes functions such as ``abort()`` and ``std::terminate()``
274     from the analysis. (The reason for requiring ``noexcept`` in C++ is that a function declared
275     ``noreturn`` could be a wrapper for ``throw``.)
276
2775. May not invoke or access an Objective-C method or property, since ``objc_msgSend()`` calls into
278   the Objective-C runtime, which may allocate memory or otherwise block.
279
2806. May not access thread-local variables. Typically, thread-local variables are allocated on the
281   heap when first accessed.
282
283Functions declared ``nonblocking`` have an additional constraint:
284
2857. May not declare static local variables (e.g. Meyers singletons). The compiler generates a lock
286   protecting the initialization of the variable.
287
288Violations of any of these rules result in warnings, in the ``-Wfunction-effects`` category:
289
290.. code-block:: c++
291
292  void notInline();
293
294  void example() [[clang::nonblocking]]
295  {
296    auto* x = new int;
297    // warning: function with 'nonblocking' attribute must not allocate or deallocate
298    //   memory
299
300    if (x == nullptr) {
301      static Logger* logger = createLogger();
302      // warning: function with 'nonblocking' attribute must not have static local variables
303
304      throw std::runtime_warning{ "null" };
305      // warning: 'nonblocking" function 'example' must not throw exceptions
306    }
307    notInline();
308    // warning: 'function with 'nonblocking' attribute must not call non-'nonblocking' function
309    //   'notInline'
310    // note (on notInline()): declaration cannot be inferred 'nonblocking' because it has no
311    //   definition in this translation unit
312  }
313
314Inferring ``nonblocking`` or ``nonallocating``
315----------------------------------------------
316
317In the absence of a ``nonblocking`` or ``nonallocating`` attribute (whether ``true`` or ``false``),
318a function that is called from a performance-constrained function may be analyzed to
319infer whether it has a desired attribute. This analysis happens when the function is not a virtual
320method, and it has a visible definition within the current translation unit (i.e. its body can be
321traversed).
322
323.. code-block:: c++
324
325  void notInline();
326  int implicitlySafe() { return 42; }
327  void implicitlyUnsafe() { notInline(); }
328
329  void example() [[clang::nonblocking]]
330  {
331    int x = implicitlySafe(); // OK
332    implicitlyUnsafe();
333    // warning: function with 'nonblocking' attribute must not call non-'nonblocking' function
334    //   'implicitlyUnsafe'
335    // note (on implicitlyUnsafe): function cannot be inferred 'nonblocking' because it calls
336    //   non-'nonblocking' function 'notInline'
337    // note (on notInline()): declaration cannot be inferred 'nonblocking' because it has no
338    //   definition in this translation unit
339  }
340
341Lambdas and blocks
342------------------
343
344As mentioned earlier, the performance constraint attributes apply only to a single function and not
345to any code nested inside it, including blocks, lambdas, and local classes. It is possible for a
346nonblocking function to schedule the execution of a blocking lambda on another thread. Similarly, a
347blocking function may create a ``nonblocking`` lambda for use in a realtime context.
348
349Operations which create, destroy, copy, and move lambdas and blocks are analyzed in terms of the
350underlying function calls. For example, the creation of a lambda with captures generates a function
351call to an anonymous struct's constructor, passing the captures as parameters.
352
353Implicit function calls in the AST
354----------------------------------
355
356The ``nonblocking`` / ``nonallocating`` analysis occurs at the Sema phase of analysis in Clang.
357During Sema, there are some constructs which will eventually become function calls, but do not
358appear as function calls in the AST. For example, ``auto* foo = new Foo;`` becomes a declaration
359containing a ``CXXNewExpr`` which is understood as a function call to the global ``operator new``
360(in this example), and a ``CXXConstructExpr``, which, for analysis purposes, is a function call to
361``Foo``'s constructor. Most gaps in the analysis would be due to incomplete knowledge of AST
362constructs which become function calls.
363
364Disabling diagnostics
365---------------------
366
367Function effect diagnostics are controlled by ``-Wfunction-effects``.
368
369A construct like this can be used to exempt code from the checks described here:
370
371.. code-block:: c++
372
373  #define NONBLOCKING_UNSAFE(...)                                    \
374    _Pragma("clang diagnostic push")                                 \
375    _Pragma("clang diagnostic ignored \"-Wunknown-warning-option\"") \
376    _Pragma("clang diagnostic ignored \"-Wfunction-effects\"")       \
377    __VA_ARGS__                                                      \
378    _Pragma("clang diagnostic pop")
379
380Disabling the diagnostic allows for:
381
382- constructs which do block, but which in practice are used in ways to avoid unbounded blocking,
383  e.g. a thread pool with semaphores to coordinate multiple realtime threads;
384- using libraries which are safe but not yet annotated;
385- incremental adoption in a large codebase.
386
387Adoption
388========
389
390There are a few common issues that arise when adopting the ``nonblocking`` and ``nonallocating``
391attributes.
392
393C++ exceptions
394--------------
395
396Exceptions pose a challenge to the adoption of the performance constraints. Common library functions
397which throw exceptions include:
398
399+----------------------------------+-----------------------------------------------------------------------+
400| Method                           | Alternative                                                           |
401+==================================+=======================================================================+
402| ``std::vector<T>::at()``         | ``operator[](size_t)``, after verifying that the index is in range.   |
403+----------------------------------+-----------------------------------------------------------------------+
404| ``std::optional<T>::value()``    | ``operator*``, after checking ``has_value()`` or ``operator bool()``. |
405+----------------------------------+-----------------------------------------------------------------------+
406| ``std::expected<T, E>::value()`` | Same as for ``std::optional<T>::value()``.                            |
407+----------------------------------+-----------------------------------------------------------------------+
408
409
410``std::function<R(Args...)>``
411-----------------------------
412
413``std::function<R(Args...)>`` is generally incompatible with ``nonblocking`` and ``nonallocating``
414code, because a typical implementation may allocate heap memory in the constructor.
415
416Alternatives:
417
418- ``std::function_ref`` (available in C++26 or as ``llvm::function_ref``). This is appropriate and
419  optimal when a functor's lifetime does not need to extend past the function that created it.
420
421- ``inplace_function`` from WG14. This solves the allocation problem by giving the functor wrapper
422  a fixed size known at compile time and using an inline buffer.
423
424While these alternatives both address the heap allocation of ``std::function``, they are still
425obstacles to ``nonblocking/nonallocating`` verification, for reasons detailed in the next section.
426
427
428Interactions with type-erasure techniques
429-----------------------------------------
430
431``std::function<R(Args...)>`` illustrates a common C++ type-erasure technique. Using template
432argument deduction, it decomposes a function type into its return and parameter types. Additional
433components of the function type, including ``noexcept``, ``nonblocking``, ``nonallocating``, and any
434other attributes, are discarded.
435
436Standard library support for these components of a function type is not immediately forthcoming.
437
438Code can work around this limitation in either of two ways:
439
4401. Avoid abstractions like ``std::function`` and instead work directly with the original lambda type.
441
4422. Create a specialized alternative, e.g. ``nonblocking_function_ref<R(Args...)>`` where all function
443   pointers used in the implementation and its interface are ``nonblocking``.
444
445As an example of the first approach, when using a lambda as a *Callable* template parameter, the
446attribute is preserved:
447
448.. code-block:: c++
449
450  std::sort(vec.begin(), vec.end(),
451    [](const Elem& a, const Elem& b) [[clang::nonblocking]] { return a.mem < b.mem; });
452
453Here, the type of the ``Compare`` template parameter is an anonymous class generated from the
454lambda, with an ``operator()`` method holding the ``nonblocking`` attribute.
455
456A complication arises when a *Callable* template parameter, instead of being a lambda or class
457implementing ``operator()``, is a function pointer:
458
459.. code-block:: c++
460
461  static bool compare_elems(const Elem& a, const Elem& b) [[clang::nonblocking]] {
462    return a.mem < b.mem; };
463
464  std::sort(vec.begin(), vec.end(), compare_elems);
465
466Here, the type of ``compare_elems`` is decomposed to ``bool(const Elem&, const Elem&)``, without
467``nonblocking``, when forming the template parameter. This can be solved using the second approach,
468creating a specialized alternative which explicitly requires the attribute. In this case, it's
469possible to use a small wrapper to transform the function pointer into a functor:
470
471.. code-block:: c++
472
473  template <typename>
474  class nonblocking_fp;
475
476  template <typename R, typename... Args>
477  class nonblocking_fp<R(Args...)> {
478  public:
479    using impl_t = R (*)(Args...) [[clang::nonblocking]];
480
481  private:
482    impl_t mImpl{ nullptr_t };
483  public:
484    nonblocking_fp() = default;
485    nonblocking_fp(impl_t f) : mImpl{ f } {}
486
487    R operator()(Args... args) const
488    {
489      return mImpl(std::forward<Args>(args)...);
490    }
491  };
492
493  // deduction guide (like std::function's)
494  template< class R, class... ArgTypes >
495  nonblocking_fp( R(*)(ArgTypes...) ) -> nonblocking_fp<R(ArgTypes...)>;
496
497  // --
498
499  // Wrap the function pointer in a functor which preserves ``nonblocking``.
500  std::sort(vec.begin(), vec.end(), nonblocking_fp{ compare_elems });
501
502Now, the ``nonblocking`` attribute of ``compare_elems`` is verified when it is converted to a
503``nonblocking`` function pointer, as the argument to ``nonblocking_fp``'s constructor. The template
504parameter is the functor class ``nonblocking_fp``.
505
506
507Static local variables
508----------------------
509
510Static local variables are often used for lazily-constructed globals (Meyers singletons). Beyond the
511compiler's use of a lock to ensure thread-safe initialization, it is dangerously easy to
512inadvertently trigger initialization, involving heap allocation, from a ``nonblocking`` or
513``nonallocating`` context.
514
515Generally, such singletons need to be replaced by globals, and care must be taken to ensure their
516initialization before they are used from ``nonblocking`` or ``nonallocating`` contexts.
517
518
519Annotating libraries
520--------------------
521
522It can be surprising that the analysis does not depend on knowledge of any primitives; it simply
523assumes the worst, that all function calls are unsafe unless explicitly marked as safe or able to be
524inferred as safe. With ``nonblocking``, this appears to suffice for all but the most primitive of
525spinlocks.
526
527At least for an operating system's C functions, it is possible to define an override header which
528redeclares safe common functions (e.g. ``pthread_self()``) with the addition of ``nonblocking``.
529This may help in adopting the feature incrementally.
530
531It also helps that many of the functions in the standard C libraries (notably ``<math.h>``)
532are treated as built-in functions by Clang, which the diagnosis understands to be safe.
533
534Much of the C++ standard library consists of inline templated functions which work well with
535inference. A small number of primitives may need explicit ``nonblocking/nonallocating`` attributes.
536