﻿# Annotating C and C\+\+ entities in JSON format

The user annotation mechanism is a way of marking up types and functions in JSON format in order to provide the analyzer with additional information\. Due to this information, the analyzer can find more errors in code\. The mechanism works only for C and C\+\+ languages\.

## Quick start

Let's say that the project requires that we forbid calling a function because it's unwanted:

```cpp
void DeprecatedFunction(); // should not be used

void foo()
{
  DeprecatedFunction();    // unwanted call site
}
```

In order for the analyzer to issue the [V2016](https://pvs-studio.com/en/docs/warnings/v2016/) warning in the place where this function is called, we should create a special JSON file with the following contents:

```cpp
{
  "version": 5,
  "annotations": [
    {
      "type": "function",
      "name": "DeprecatedFunction",
      "attributes": [ "dangerous" ]
    }
  ]
}
```

After that, just connect the file \(you can find all the options for connecting it [here](https://pvs-studio.com/en/docs/manual/6810/#how_to_enable)\):

```cpp
//V_PVS_ANNOTATIONS, language: cpp, path: %path/to/annotations.json%

void DeprecatedFunction();

void foo()
{
  DeprecatedFunction();    // <= V2016 will be issued here
}
```

**Note\.** The [V2016](https://pvs-studio.com/en/docs/warnings/v2016/) diagnostic rule is disabled by default\. In order for the analyzer to issue warnings, enable the diagnostic rule in the [settings](https://pvs-studio.com/en/docs/manual/0013/)\.

## Ways to register the annotation file

You can learn more about how to enable the annotation file in [this](https://pvs-studio.com/en/docs/manual/6810/#how_to_enable) documentation\.

## Structure of the annotation file

The file content is a JSON object consisting of two mandatory fields: `version` and `annotations`\. 

The `version` field takes an integer\-type value and specifies the version of the mechanism\. Depending on the value, the markup file can be processed differently\. Currently, only one value is supported — `1`\.

The `annotations` field is an array of "annotation" objects:

```cpp
{
  "version": 5,
  "annotations":
  [
    {
      ...
    },
    {
      ...
    }
  ]
}
```

Annotations can be of two types:

* type annotations; 
* function annotations;

If an annotation is declared directly in the `annotations` array, it's **a top\-level annotation**\. Otherwise, it is **a nested annotation**\.

## Type annotations

The type annotation object consists of the following fields\.

### The "type" field

The mandatory field\. It takes a string with one of the values: `"record"`, `"class"`, `"struct"`, or `"union"`\. The last three options are aliases for "record" and have been added for convenience\.

### The "name" field

The mandatory field\. It takes a string with the fully qualified name of an entity\. The analyzer searches for this entity starting from the global scope\. If the entity is in the global scope, the `"::"` character at the beginning of the name can be omitted\.

### The "members" field

The optional field\. An array of nested annotation objects\.

### The "attributes" field

The optional field\. An array of strings that specifies the properties of an entity\. Attributes available for type annotations are as follows:

#### Smart pointers

* `"unique_ptr"` — the type has the [`std::unique_ptr`](https://en.cppreference.com/w/cpp/memory/unique_ptr) interface;
* `"shared_ptr"` — the type has the [`std::shared_ptr`](https://en.cppreference.com/w/cpp/memory/shared_ptr) interface;
* `"auto_ptr"` — the type has the [`std::auto_ptr`](https://en.cppreference.com/w/cpp/memory/auto_ptr) interface;

#### Containers

* `"string"` — the type has the [`std::basic_string`](https://en.cppreference.com/w/cpp/string/basic_string) interface;
* `"string_view"` — the type has the [`std::basic_string_view`](https://en.cppreference.com/w/cpp/string/basic_string_view) interface;
* `"array"` — the type has the [`std::array`](https://en.cppreference.com/w/cpp/container/array) interface;
* `"vector"` — the type has the [`std::vector`](https://en.cppreference.com/w/cpp/container/vector) interface;
* `"map"` — the type has the [`std::map`](https://en.cppreference.com/w/cpp/container/map) interface;
* `"set"` — the type has the [`std::set`](https://en.cppreference.com/w/cpp/container/set) interface;
* `"list"` — the type has the [`std::list`](https://en.cppreference.com/w/cpp/container/list) interface;
* `"iterator"` — the type has the [`std::iterator`](https://en.cppreference.com/w/cpp/iterator/iterator.html) interface;
* `"unordered"` — in combination with `"set"` or `"map"` sets the type interface to [`std::unordered_set`](https://en.cppreference.com/w/cpp/container/unordered_set) or [`std::unordered_map`](https://en.cppreference.com/w/cpp/container/unordered_map), respectively\. 
* `"multi"` — in combination with `"set"` or `"map"` sets the type interface to [`std::multiset`](https://en.cppreference.com/w/cpp/container/multiset) or [`std::multimap`](https://en.cppreference.com/w/cpp/container/multimap), respectively\. If "unordered" is included, the type is given the [`std::unordered_multiset`](https://en.cppreference.com/w/cpp/container/unordered_multiset) or [`std::unordered_multimap`](https://en.cppreference.com/w/cpp/container/unordered_multimap) semantics\.



#### Other types

* `"nullable"` — the type has the semantics of a nullable type\. Objects of these types can have one of two states: "valid" or "invalid"\. Accessing an object in the "invalid" state results in an error\. Pointers, iterators, and [`std::optional`](https://en.cppreference.com/w/cpp/utility/optional) are examples of such types\.
* `"exception"` — a type used to create an object that will be thrown as an exception\. See an example of its usage [here](https://pvs-studio.com/en/docs/manual/6743/#exception_annotation)\.



#### Semantics

* `"cheap_to_copy"` — an object of the type can be passed to a function by copy with zero overhead;
* `"expensive_to_copy"` — an object of the type should be passed to a function only by pointer/reference;
* `"copy_on_write"` — the type has the [copy\-on\-write](https://en.wikipedia.org/wiki/Copy-on-write) semantics\.



## Function annotations

The function annotation object consists of the following fields:

### The "type" field

The mandatory field\. It takes a string with the `function` value\. Also, the `ctor` value is available for nested function annotations \(in the `members` field of type annotations\)\. It indicates that a custom\-type constructor is being annotated\.

### The "name" field

It takes a string with a function name\. The field is mandatory if `type` has the "function" value, otherwise it should be omitted\. The analyzer searches for the annotated entity by this name, starting from the global scope\.

For top\-level annotations, the fully qualified name is specified\. For nested annotations, the unqualified name is specified\.

If the function is in the global scope, the scope resolution operator \(`"::"`\) at the beginning of the name can be omitted\.

### The "params" field

The optional field\. An array of objects that describes formal parameters\. Along with _name_, this field specifies the signature of the function by which the analyzer compares the annotation with its declaration in the program code\. In the case of member functions, the analyzer also considers the _qualifiers_ field\.

Each object contains the following fields:

* `"type"` \(mandatory\) — a type of a formal parameter as a string\. For example, the first formal parameter of the _memset_ function has the _void \*_ type\. That's what should be written in the string\. It's possible to omit unnecessary parameters and annotate several function overloads with a single annotation\. For this purpose, use a wildcard character:
  * The `"*"` character means that 0 or more parameters of any type can take its place\. It should be the last in the list of parameters\.
  * The `"?"` character denotes that a parameter of any type can take its place\.
* `"attributes"` \(optional\) — an array of strings that specifies the properties of a parameter\. Possible parameter attributes are described below\.
* `"constraint"` \(optional\) — an object that contains the data about the parameter constraints\. If the analyzer detects the possible violation of constraints, a user gets the [V1108](https://pvs-studio.com/en/docs/warnings/v1108/) warning\. The possible object fields are described further in the documentation\.

If the annotation is to be applied to all overloads regardless of the parameters, the field can be omitted:

```cpp
// Code
void foo();      // dangerous
void foo(int);   // dangerous
void foo(float); // dangerous

// Annotation
{
  ....
  "type": "function",
  "name": "foo",
  "attributes": [ "dangerous" ]
  ....
}
```

If an overload that takes no parameters is needed, specify an empty array explicitly:

```cpp
// Code
void foo();      // dangerous
void foo(int);   // ok
void foo(float); // ok

// Annotation
{
  ....
  "type": "function",
  "name": "foo",
  "attributes": [ "dangerous" ],
  "params": []
  ....
}
```

#### Possible parameter attribute values

|\\\#|Attribute name|Attribute description|
|---|---|---|
|1|\`immutable\`|It indicates to the analyzer that the passed argument has not been modified after the function call\\\. For example, the \[\`printf\`\]\(https://en\.cppreference\.com/w/cpp/io/c/fprintf\) function has side effects \\\(printing to \`stdout\`\\\) but does not modify passed arguments\\\.|
|2|\`not\_null\`|It is valid only for \`nullable\`\\\-type parameters\\\. An argument in the "valid" state should be passed to the function\\\.|
|3|\`unique\_arg\`|The arguments passed should be different\\\. For example, it doesn't make sense to pass two identical arguments to \[\`std::swap\`\]\(https://en\.cppreference\.com/w/cpp/algorithm/swap\)\\\.|
|4|\`format\_arg\`|The parameter denotes a format string\\\. The analyzer checks the arguments according to the \[\`printf\`\]\(https://en\.cppreference\.com/w/cpp/io/c/fprintf\) format specification\\\.|
|5|\`pointer\_to\_free\`|A pointer by which memory is released in the function by using \[\`free\`\]\(https://en\.cppreference\.com/w/c/memory/free\)\\\. The pointer can be null\\\.|
|6|\`pointer\_to\_gfree\`|A pointer by which memory is released in the function by using \[\`g\_free\`\]\(https://docs\.gtk\.org/glib/func\.free\.html\)\\\. The pointer can be null\\\.|
|7|\`pointer\_to\_delete\`|A pointer by which memory is released in the function by using \`operator delete\`\\\. The pointer can be null\\\.|
|8|\`pointer\_to\_delete\[\]\`|A pointer by which memory is released in the function by using \`operator delete\[\]\`\\\. The pointer can be null\\\.|
|9|\`pointer\_to\_unmap\`|A pointer by which memory is released in the function by using '\[munmap\]\(https://man7\.org/linux/man\-pages/man3/munmap\.3p\.html\)'\\\. The pointer can be null\\\.|
|10|\`taint\_source\`|Data returned via a parameter is from a tainted source\\\.|
|11|\`taint\_sink\`|Data passed via a parameter can lead to vulnerability exploitation if it is obtained from a tainted source\\\.|
|12|\`non\_empty\_string\`|The parameter that must take any non\\\-empty string\\\.|
|13 |\`lower\_bound\`|The parameter represents the lower boundary of some range, e\\\.g\\\. the second parameter of the \[\`std::clamp\`\]\(https://en\.cppreference\.com/w/cpp/algorithm/clamp\)\\\.|
|14|\`upper\_bound\`|The parameter represents the upper boundary of some range, e\\\.g\\\. the third parameter of the \[\`std::clamp\`\]\(https://en\.cppreference\.com/w/cpp/algorithm/clamp\)\\\.|
|15|\`in\_range\_value\`|The value passed to the parameter is checked to be within range, e\\\.g\\\. the first parameter of the \[\`std::clamp\`\]\(https://en\.cppreference\.com/w/cpp/algorithm/clamp\)\\\. The range is specified by parameters annotated as 'lower\\\_bound' and 'upper\\\_bound'\\\.|

#### Possible fields of parameter constraints

All constraint fields are optional\. A list of fields that set certain conditions of constraints is provided below\.

Here are the fields that set the list of allowed and disallowed values of the parameter:

* The `allowed` field is string arrays\. It sets the list of allowed integral values that the function parameter can receive\. If values are not on this list, they are disallowed by default\.
* The `disallowed` field is string arrays\. It sets the list of disallowed integral values that the function parameter can receive\. If values are not on this list, they are allowed by default\.

Each string in the array is an interval from the minimum to the maximum bounds, **inclusively**\. The string with intervals is set in the format `"x..y"`, where `x` and `y` are the left and right bounds, respectively\. A user can remove one of the bounds\. Then the string will look like this: `"x.."` or `"..y"`\. The interval is from `x` to plus infinity and from minus infinity to `y`, respectively\.

Here are examples of intervals:

* `"0..10"` is a string that sets the interval from 0 to 10, inclusively\.
* `"..10"` is a string that sets the interval from minus infinity to 10, inclusively\.
* `"0.."` is a string that sets the interval from 0 to plus infinity\.

An array can contain multiple intervals\. When the analyzer reads the intervals, it normalizes all intervals in the array\. The process merges overlapping and adjacent intervals, placing them in ascending order\.

If the `allowed` and `disallowed` fields are set at the same time, the analyzer subtracts the "disallowed" intervals from "allowed" to obtain a set of allowed values\. If the values in the `disallowed` field completely cover the values in the `allowed` field, the analyzer issues the [V019](https://pvs-studio.com/en/docs/warnings/v019/) warning\.

### The "returns" field

The optional field\. An object in which only the `attributes` field \(an array of strings\) can be used to specify the attributes of the return value\.

#### Possible attribute values of the returned result

|\\\#|Attribute name|Attribute description|
|---|---|---|
|1|\`not\_null\`|The function always returns an object of a \`nullable\`\\\-type in the "valid" state\\\.|
|2|\`maybe\_null\`|The function may return an object of a \`nullable\`\\\-type in the "invalid" state\\\. An object should be checked before dereferencing\\\.|
|3|\`taint\_source\`|The function may return data from a tainted source\\\.|
|4|\`always\_null\`|The function always returns a \`nullable\` object in the "invalid" state\\\.|

### The "template\_params" field

The optional field\. An array of strings that enables specifying the template parameters of the function\. The field is required when template parameters are used in a function signature:

```cpp
// Code
template <typename T1, class T2>
void MySwap(T1 &lhs, T2 &rhs);

// Annotation
{
  ....
  "template_params": [ "typename T1", "class T2" ],
  "name": "MySwap",
  "params": [
    { "type": "T1 &", attributes: [ "unique_arg" ] },
    { "type": "T2 &", attributes: [ "unique_arg" ] }
  ]
  ....
}
```

### The "qualifiers" field

The optional field\. It enables us to apply the annotation only to a member function with a specific set of `cvref` qualifiers\. It's available only for nested annotations that have the `type` field set to "function"\. Along with `name` and `params`, the field specifies the signature of the non\-static member function by which the analyzer compares the annotation with its declaration in the program code\. The field takes an array of strings with the following possible values: `"const"`, `"volatile"`, `"&"`, or `"&&"`\.

**Example:**

```cpp
// Code
struct Foo
{
  void Bar();                // don't need to annotate this overload
  void Bar() const;          // want to annotate this overload
  void Bar() const volatile; // and this one
};

// Annotation
{
  ....
  "type": "record",
  "name": "Foo",
  "members": [
    {
      "type": "function",
      "name": "Bar",
      "qualifiers": [ "const" ]
    },
    {
      "type": "function",
      "name": "Bar",
      "qualifiers": [ "const", "volatile" ]
    }
  ]
  ....
}
```

If the annotation is to be applied to all qualified and unqualified versions, the field should be omitted:

```cpp
// Code
struct Foo
{
  void Bar();       // want to annotate this overload
  void Bar() const; // and this one
};

// Annotation
{
  ....
  "type": "record",
  "name": "Foo",
  "members": [
    {
      "type": "function",
      "name": "Bar",
    }
  ]
  ....
}
```

If the annotation is to be applied only to the unqualified version, the field value should be an empty array:

```cpp
// Code
struct Foo
{
  void Bar();       // want to annotate this overload
  void Bar() const; // but NOT this one
};

// Annotation
{
  ....
  "type": "record",
  "name": "Foo",
  "members": [
    {
      "type": "function",
      "name": "Bar",
      "qualifiers": []
    }
  ]
  ....
}
```

### The "attributes" field

The optional field\. It's an array of strings that sets the properties of an entity\.

#### Possible function and constructor attributes 

|\\\#|Attribute name|Attribute description|Note|
|---|---|---|---|
|1|\`pure\`|The function is \[pure\]\(https://en\.wikipedia\.org/wiki/Pure\_function\)\\\.|A function is pure when it has no side effects, does not modify the passed arguments, and the result of the function is the same when it's called with the same set of arguments\\\.|
|2|\`noreturn\`|The function does not return control to the caller function\\\.||
|3|\`nodiscard\`|The result of the function should be used\\\.||
|4|\`nullable\_uninitialized\`|A custom \`nullable\`\\\-type member function puts the object in the "invalid" state\\\.||
|5|\`nullable\_initialized\`|A custom \`nullable\`\\\-type member function puts the object in the "valid" state\\\.||
|6|\`nullable\_potentially\_initialized\`|A custom \`nullable\`\\\-type member function puts the object in the "potentially valid" state\\\.||
|7|\`nullable\_checker\`|The function checks the state of the user \`nullable\` type\\\. If the function returns \_true\_, the object is considered to be in a "valid" state; if not, it is "invalid"\\\. The result of the function is to be implicitly converted to the \`bool\` type\\\.||
|8|\`nullable\_getter\`|The function performs access to internal data of the user \`nullable\` type\\\. The object must be in the "valid" state\\\.||
|9|\`nullable\_resetter\`|The function of a custom \`nullable\` type modifies an object state\\\. If the function doesn't take parameters, the object will be set to an invalid state\\\. If the function takes one or more parameters, the object's new state and value are determined based on the arguments passed\\\.||
|10|\`dangerous\`|The function is marked as dangerous, and the program code must not contain its call\\\.|It can also be used to mark a function as deprecated\\\.<br>In order for the analyzer to issue warnings, enable the \[V2016\]\(https://pvs\-studio\.com/en/docs/warnings/v2016/\) diagnostic rule in the \[settings\]\(https://pvs\-studio\.com/en/docs/manual/0013/\)\\\.|
|11|\`memory\_allocator\`|The function that allocates memory\\\.||
|12|\`alloc\-group \(\.\.\.\.\)\`|The attribute that specifies allocator/deallocator pairs\\\.|One or more tags are specified inside the parentheses, separated by commas\\\. Memory allocated by an allocator from group N can be freed by any deallocator from that group\\\.<br>The \`stdlib\` group name is used for compatibility of functions with the standard library\\\.|
|13|\`constructor\_like\`|The function, which initializes class data members and handled by analyzer as a class constructor \\\(initializer\\\)\\\.||

An applicability table of different attributes with function annotations is below:

|\\\#|Attribute|Free function|Constructor|Member function|
|---|---|---|---|---|
|1|pure|✓|✕|✓|
|2|noreturn|✓|✕|✓|
|3|nodiscard|✓|✓|✓|
|4|nullable\\\_uninitialized|✕|✓|✓|
|5|nullable\\\_initialized|✕|✓|✓|
|6|nullable\\\_potentially\\\_initialized|✕|✓|✓|
|7|nullable\\\_checker|✕|✕|✓|
|8|nullable\\\_getter|✕|✕|✓|
|9|nullable\\\_resetter|✕|✕|✓|
|10|dangerous|✓|✕|✓|
|11|memory\\\_allocator|✓|✕|✓|
|12|alloc\\\-group \\\(\\\.\\\.\\\.\\\.\\\)|✓|✕|✓|
|13|constructor\\\_like|✓|✕|✓|

## JSON Schema

[JSON Schema](https://files.pvs-studio.com/media/custom_annotations/v1/cpp-annotations.schema.json) comes bundled with the distribution or is available at the link\.

JSON schemas are supplied with the distribution and are also available at the links below:

* [V1 \(supported since version 7\.31\)](https://files.pvs-studio.com/media/custom_annotations/v1/cpp-annotations.schema.json);
* [V2 \(supported since version 7\.33\)](https://files.pvs-studio.com/media/custom_annotations/v2/cpp-annotations.schema.json);
* [V3 \(supported since version 7\.39\)](https://files.pvs-studio.com/media/custom_annotations/v3/cpp-annotations.schema.json);
* [V4 \(supported since version 7\.43\)](https://files.pvs-studio.com/media/custom_annotations/v4/cpp-annotations.schema.json);
* [V5 \(supported since version 8\.0\)](https://files.pvs-studio.com/media/custom_annotations/v5/cpp-annotations.schema.json)\.

## Examples

### How to annotate user nullable type

Let's say there is a user `nullable` type as follows:

```cpp
constexpr struct MyNullopt { /* .... */ } my_nullopt;

template <typename T>
class MyOptional
{
public:
  MyOptional();
  MyOptional(MyNullopt);

  MyOptional(T &&val);

  template <typename U>
  MyOptional(U &&val);

public:
  bool HasValue() const;

  T& Value();
  const T& Value() const;

  void SetValue(T val);

  void Reset();
  void Reset(T &&val);

private:
  /* implementation */
};
```

Code notes:

* The default constructor and the constructor of the `MyNullopt` type initialize the object in the "invalid" state\.
* The constructor that takes a parameter of the `T&&` type initialize the object in the "potentially valid" state\.
* The constructor template that takes a parameter of the `U&&` type initializes the object in the "valid" state\.
* The `HasValue` member function checks the state of a `nullable`\-type object\. If the object is in the "valid" state, true is returned; otherwise, false\. The function does not change the state of a `nullable`\-type object\.
* Overloads of `Value` member functions return the underlying object\. Functions do not change the state of a `nullable`\-type object\.
* The `SetValue` member function modify the state of the underlying object and sets the object to a "potentially valid" state\.
* Overloads of the `Reset` member function modify the state of the underlying object\. The parameterless override sets the object to an invalid state\. The overload with parameters sets the object to a state evaluated based on the values of the passed arguments\.

Then the annotation of the class and its member functions looks as follows:

```cpp
{
  "version": 5,
  "language": "cpp",
  "annotations": [
    {
      "type": "class",
      "name": "MyOptional",
      "attributes": [ "nullable" ],
      "members": [
        {
          "type": "ctor",
          "attributes": [ "nullable_uninitialized" ]
        },
        {
          "type": "ctor",
          "attributes": [ "nullable_uninitialized" ],
          "params": [
            {
              "type": "MyNullopt"
            }
          ]
        },
        {
          "type": "ctor",
          "attributes": [ "nullable_potentially_initialized" ],
          "params": [
            {
              "type": "T &&val"
            }
          ]
        },
        {
          "type": "ctor",
          "template_params": [ "typename U" ],
          "attributes": [ "nullable_initialized" ],
          "params": [
            {
              "type": "U &&val"
            }
          ]
        },
        {
          "type": "function",
          "name": "HasValue",
          "attributes": [ "nullable_checker", "pure", "nodiscard" ]
        },
        {
          "type": "function",
          "name": "Value",
          "attributes": [ "nullable_getter", "nodiscard" ]
        },
        {
          "type": "function",
          "name": "SetValue",
          "attributes": [ "nullable_potentially_initialized" ]
        },
        {
          "type": "function",
          "name": "Reset",
          "attributes": [ "nullable_resetter" ]
        }
      ]
    }
  ]
}
```

### How to add an "always valid" contract for the nullable\-type function parameter

Suppose the following code:

```cpp
namespace Foo
{
  template <typaname CharT>
  size_t my_strlen(const CharT *ptr);
}
```

The `Foo::my_strlen` function has the following properties:

* The first parameter must always be non\-zero, i\.e\., in the "valid" state\.
* The function is pure and does not modify anything\.

Then the function annotation looks as follows:

```cpp
{
  "version": 5,
  "annotations":
  [
    {
      "type": "function",
      "name": "Foo::my_strlen",
      "attributes": [ "pure" ],
      "template_params": [ "typename CharT" ],
      "params": [
        {
          "type": "const CharT *",
          "attributes": [ "not_null" ]
        }
      ]
    }
  ]
}
```

### How to mark up a user\-formatted I/O function

Let's say there is the _Foo::LogAtError_ function:

```cpp
namespace Foo
{
  void LogAtError(const char *, ...);
}
```

It is known that:

* It takes a format string as its first parameter according to the `printf` specification\. The argument must not be null\.
* The arguments matching the format string, starting with the second one, are passed\.
* The function does not modify the passed arguments\.
* The function does not return control after it is called\.

The analyzer can check if the passed arguments match the format string\. Also, it can determine that the code is unreachable after calling the function\. To do this, we need to mark up the function as follows:

```cpp
{
  "version": 5,
  "annotations": [
    {
      "type": "function",
      "name": "Foo::LogAtError",
      "attributes": [ "noreturn" ],
      "params": [
        {
          "type": "const char *",
          "attributes" : [ "format_arg", "not_null", "immutable" ]
        },
        {
          "type": "...",
          "attributes": [ "immutable" ]
        }
      ]
    }
  ]
}
```

### How to use a wildcard character to annotate multiple overloads

Suppose that, in the previous example, a programmer added some overloads to the `Foo::LogAtExit` function:

```cpp
namespace Foo
{
  void LogAtExit(const     char *fmt, ...);
  void LogAtExit(const  char8_t *fmt, ...);
  void LogAtExit(const  wchar_t *fmt, ...);
  void LogAtExit(const char16_t *fmt, ...);
  void LogAtExit(const char32_t *fmt, ...);
}
```

In this case, it is not necessary to write annotations for all overloads\. One, using the wildcard character, is enough:

```cpp
{
  "version": 5,
  "annotations": [
    {
      "type": "function",
      "name": "Foo::LogAtExit",
      "attributes": [ "noreturn" ],
      "params": [
        {
          "type": "?",
          "attributes" : [ "format_arg", "not_null", "immutable" ]
        },
        {
          "type": "...",
          "attributes": [ "immutable" ]
        }
      ]
    }
  ]
}
```

### How to mark a function as dangerous \(or deprecated\)

Suppose there are two overloads of the `Foo::Bar function`:

```cpp
namespace Foo
{
  void Bar(int i);
  void Bar(double d);
}
```

We need to forbid the first overload\. To do this, mark up the function as follows:

```cpp
{
  "version": 5,
  "annotations": [
    {
      "type": "function",
      "name": "Foo::Bar",
      "attributes": [ "dangerous" ],
      "params": [
        {
          "type": "int"
        }
      ]
    }
  ]
}
```

### How to mark a function as a source/sink of tainted data

Let's say there is a function that returns external data via the out parameter and return value\.

```cpp
std::string ReadStrFromStream(std::istream &input, std::string &str)
{
  ....
  input >> str; 
  return str;
  ....
}
```

To mark the function as a source of tainted data, do the following:

```cpp
{
  "version": 5,
  "annotations": [
    {
      "type": "function",
      "name": "ReadStrFromStream",
      "params": [
        {
          "type": "std::istream &input"
        },
        {
          "type": "std::string &str",
          "attributes": [ "taint_source" ]
        }
      ],
      "returns": { "attributes": [ "taint_source" ] }
    }
  ]
}
```

Let's assume there is a function where some vulnerability can be exploited if tainted data is put into it\.

```cpp
void DoSomethingWithData(std::string &str)
{
  .... // Some vulnerability
}
```

To mark the function as a sink of tainted data, add the following annotation:

```cpp
{
  "version": 5,
  "annotations": [
    {
      {
      "type": "function",
      "name": "DoSomethingWithData",
      "params": [ { "type": "std::string &str",
                    "attributes": [ "taint_sink" ] }]
      }
    }
  ]
}
```

### How to annotate a user\-defined exception that must be created with the explanatory message

The C\+\+ analyzer can issue the [V1116](https://pvs-studio.com/en/docs/warnings/v1116/) warning if it detects that an exception object is created with the empty message\. By default, this diagnostic rule works only with exception types from the C\+\+ standard library\. To support user\-defined exception types, add a special annotation\.

Suppose there is a class that defines objects to be used for throwing exceptions:

```cpp
class MyException: public std::runtime_error
{
public:
  MyException(const std::string& what_arg )
  : std::runtime_error(what_arg){}

   MyException(const char *what_arg)
   : std::runtime_error(what_arg){}
};
```

In the annotation, define the exception type with the `exception` attribute\. Next, define constructors and set the `non_empty_string` attribute for each constructor parameter that should take the message\.

For example, the annotation for the `MyException` class might look as follows:

```cpp
{
  "version": 5,
  "language": "cpp",
  "annotations": [
   {
    "type": "class",
    "name": "MyException",
    "attributes": ["exception"],
    "members": [
     {
     "type": "ctor",
     "params": [{ "type": "const char*",
                    "attributes": ["non_empty_string"]}]
     },
     {
     "type": "ctor",
     "params": [{ "type": "const std::string&", 
                  "attributes": ["non_empty_string"]}]
     }
    ]
   }
  ]
}
```

### How to markup user containers and their iterators

The C\+\+ analyzer includes the [V783](https://pvs-studio.com/en/docs/warnings/v783/) diagnostic rule, which issues a warning when it detects the use of an invalid \(or potentially invalid\) iterator\. By default, this rule works only with containers from the standard C\+\+ library\.

Suppose there is the `MyIterator` class, which implements iterator behavior, and the `MyContainer` container class with methods that return it:

```cpp
class MyIterator{....};
class MyContainer
{
public:
  typedef MyIterator Iterator;
  std::list<MyIterator> vec;
  Iterator Begin();
  Iterator Find(int i);
  Iterator Find(Iterator it);
  Iterator End();
....
};
```

To support this implementation, annotate the `MyIterator` type with the `iterator` attribute\. Then, mark the `Begin`, `Find`, and `End` methods of the `MyContainer` class with the corresponding `returns` attributes, for example:

```cpp
{
  "version": 5,
  "language": "cpp",
  "annotations": [
    {
      "type": "class",
      "name": "MyIterator",
      "attributes": [ "iterator" ]
    },
    {
      "type": "class",
      "name": "MyContainer",
      "members": [
        {
          "type": "function",
          "name": "Begin",
          "returns": { "attributes": [ "maybe_null" ] }
        },
        {
          "type": "function",
          "name": "End",
          "returns": { "attributes": [ "always_null" ] }
        },
        {
          "type": "function",
          "name": "Find",
          "returns": { "attributes": [ "maybe_null" ] }
        }
      ]
    }
  ]
}
```

### How to annotate allocator/deallocator pairs

The diagnostic rule [V611](https://pvs-studio.com/en/docs/warnings/v611/) in C and C\+\+ analyzer may issue a warning indicating that memory may be allocated and freed using incompatible methods\. By default, this rule does not work with user annotated functions\.

The code example: 

```cpp
void my_free(void *);
void *my_unique_malloc(size_t);

void foo(size_t count)
{
  int *ptr = (int *) my_unique_malloc(count * sizeof(int)); 

  if (!ptr) return;

  my_free(ptr);            // <= V611
}
```

The annotation:

```cpp
{
  "version": 5,
  "annotations": [
    {
      "type": "function",
      "name": "my_unique_malloc",
      "attributes": [ "memory_allocator" ]
    },
    {
      "type": "function",
      "name": "my_free",      
      "params": [
        {
          "type": "void *",
          "attributes": [ "pointer_to_free" ]
        }
      ]
    }    
  ]
}
```

To specify that `my_unique_malloc` and `my_free` belong to the same logical group, add the `alloc-group` attribute with the same tag\. Here is an example that uses the `myAllocGroup` tag:

```cpp
{
  "version": 5,
  "annotations": [
    {
      "type": "function",
      "name": "my_unique_malloc",
      "attributes": [ "memory_allocator", "alloc-group(myAllocGroup)" ]      
    },
    {
      "type": "function",
      "name": "my_free",
      "attributes": [ "alloc-group (myAllocGroup)" ],    
      "params": [
        {
          "type": "void *",
          "attributes": [ "pointer_to_free" ]
        }
      ]
    }    
  ]
}
```

Now the analyzer knows that `my_unique_malloc` and `my_free` are a pair, and will issue no false positives from the [V611](https://pvs-studio.com/en/docs/warnings/v611/) diagnostic rule\.

The group name can be arbitrary\. Most importantly, the name has to be the same for all functions of one logical allocation/deallocation group\.

**Note\. **The `stdlib` group name is reserved by the analyzer\. This tag is used to assign a user annotated function to the standard library \(`stdlib.h` for C, `cstdlib` for C\+\+\), for example:

```cpp
#include <cstdlib>

void *my_unique_malloc(size_t);

void foo(size_t count)
{
  int *ptr = (int *) my_unique_malloc(count * sizeof(int)); 

  if (!ptr) return;

  free(ptr);            
}
```

If you want your allocation function to be considered compatible with `free` from the standard library, add the function to the `stdlib` group:

```cpp
{
  "version": 5,
  "annotations": [
    {
      "type": "function",
      "name": "my_unique_malloc",
      "attributes": [ "memory_allocator", "alloc-group (stdlib)" ]      
    }    
  ]
}
```