﻿# How PVS\-Studio helps enhance quality of embedded projects

Embedded development comes with a wide variety of custom configurations, compilers, and build systems, which can make standard analysis approaches difficult to apply\. To address this challenge, PVS\-Studio provides a dedicated mechanism designed specifically for such environments\. Let's take a closer look at how it works and see how you can use it in real cases\.

![1399_PVS_embedded/image1.png](https://import.viva64.com/docx/blog/1399_PVS_embedded/image1.png)

## Features of embedded systems

Embedded development in C and C\+\+ powers an enormous range of devices—from electric kettles and toothbrushes to safety\-critical systems such as medical equipment and aircraft control software\. In these areas, the quality of software directly affects human safety\. As a result, the code must be as reliable, predictable, and resilient to external factors as possible\.

The need for thorough code verification in embedded systems continues to grow for several reasons:

* Embedded systems interact directly with users and external data, so they must correctly handle all input\.
* Memory is often severely limited, making careful resource management essential\.
* The software must remain stable under all operating conditions and provide a high level of fault tolerance\.
* Many other factors also contribute to these requirements\.

Embedded software targets a wide variety of platforms and use cases\. Each project may rely on a different compiler, toolchain, or build system\. The situation often becomes more challenging due to a "zoo" of custom\-built scripts that are difficult to maintain\.

[PVS\-Studio](https://pvs-studio.com) static analyzer offers several mechanisms specifically designed for embedded projects\. They collect all the necessary information for analysis directly from the compilation process as it runs\.

## Specialized analysis mechanisms

All of the mechanisms described here follow the same general workflow\. You start them before building your project, and they monitor every run of supported compilers throughout the build process:

* C and C\+\+ compilers from the GNU Compiler Collection \(gcc\.exe, g\+\+\.exe\) and compatible derivatives;
* Clang C and C\+\+ compilers \(clang\.exe\) and compatible derivatives;
* Borland C\+\+;
* QCC;
* Keil MDK ARM Compiler 5/6;
* IAR C/C\+\+ Compiler for ARM;
* Texas Instruments ARM Compiler;
* GNU Arm Embedded Toolchain;
* Texas Instruments Code Composer Studio, C6000\-CGT, C2000\-CGT \(support is coming in October\);
* GNU toolchain for RISC\-V\.


> \*\*Note\\\.\*\* If you'd like us to support a compiler that isn't currently supported, we'd be happy to evaluate adding it\\\. You can send us a request to support a specific compiler or contact us about any issues you're experiencing via our \[feedback form\]\(https://pvs\-studio\.com/en/about\-feedback/\)\\\.

After monitoring finishes, the server generates intermediate files and then runs the static analyzer\.

Each mechanism targets a specific environment or use case\. Let's look at them one by one\.

### Compilation monitoring CLMonitor\.exe \(for Windows\)

CLMonitor\.exe is a monitoring server that tracks compiler runs\. Start it before building your project\. Once monitoring is enabled, the server intercepts every run of supported compilers\.

The compilation monitoring system follows a straightforward workflow, illustrated below:

![1399_PVS_embedded/image2.png](https://import.viva64.com/docx/blog/1399_PVS_embedded/image2.png)

**How to start compilation monitoring**

To start the monitoring process, run the following command:

```cpp
CLMonitor.exe monitor
```

CLMonitor\.exe will run in the background and track all supported compilers\. To stop the process, run one of the commands described below\.

You can also track only compiler runs that were started by a specific process identified by its PID\. To do this, start `CLMonitor.exe` in the trace mode with the `trace` and `--parentProcessID` \(`-p`\) arguments\.

The command for running `CLMonitor.exe` in this mode may look like this:

```cpp
CLMonitor.exe trace –-parentProcessID 10256
```

If you want `CLMonitor.exe` to track only the build started from the same console, you can run `CLMonitor.exe` with the `--attach` \(`-a`\) argument:

```cpp
CLMonitor.exe monitor –-attach
```

**Building the project**

After starting compilation monitoring, build your project using the usual workflow\. Once the project build is complete, stop compilation monitoring so that you can analyze the collected data\.

**How to stop compilation monitoring**

You can run the analysis immediately after building the project using the following command:

```cpp
CLMonitor.exe analyze -l D:\ptest.plog
```

You can also pass additional parameters when starting the analysis:

* `-l` is the path to the final analyzer report file;
* `-u` is the path to the [suppress file](https://pvs-studio.com/en/docs/manual/0032/);
* `-c` is the path to the [`.pvsconfig`](https://pvs-studio.com/en/docs/manual/6630/) analysis configuration file;
* `--intermodular` enables the [intermodular analysis](https://pvs-studio.com/en/blog/posts/cpp/0851/) mode\.

If you encounter issues while building the project and need to stop compilation monitoring without analyzing the resulting files, you can do so using the following command:

```cpp
CLMonitor.exe abortTrace
```

The `CLMonitor.exe` monitoring server enables saving captured compilation data in a separate dump file\. This allows you to run the analysis without rebuilding the project\.

To save the dump file, use the following command:

```cpp
CLMonitor.exe saveDump -d D:\monitoring.zip
```

where `-d` is the path to the final dump file\.

To run the analysis using a saved dump file, use the following command:

```cpp
CLMonitor.exe analyzeFromDump -l d:\ptest.plog -d d:\monitoring.zip
```

This command supports all the flags described above that are used to start the analysis\.

### The Wrap Compilers interception mode \(for Windows\)

As we continue the discussion of embedded system specifics, it's worth mentioning another challenge involved in analyzing embedded projects\. Such projects often consist of quickly compiling C source files, and `CLMonitor.exe` may not have enough time to detect all source files\.

To ensure the interception of all compilation processes, the monitoring server can switch to a more aggressive mode using the [Image File Execution Options](https://learn.microsoft.com/en-us/previous-versions/windows/desktop/xperf/image-file-execution-options) \(IFEO\) mechanism on Windows\.

The [Wrap Compilers](https://pvs-studio.com/en/docs/manual/0031/#wrapcompilers) intercept mode runs a special handler before each compilation process begins\. It sends the necessary information to the monitoring server and then continues running the compiler\.


> \*\*Note\\\.\*\* This mode requires access to editing the path in the Windows Registry:
> 
> \`HKEY\_LOCAL\_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\`\\\.
> 
> You can grant the required access to the monitoring server by running it as administrator or by giving it write permissions to the registry branch above—or for the entire registry\\\.

To enable the interception mode in the console version of the monitoring tool, pass the `--wrapCompilers` \(`-W`\) flag to the monitoring server with a list of compilers, for example:

```cpp
CLMonitor.exe trace --wrapCompilers gcc.exe,g++.exe
```

### Compiler tracing \(for Linux\)

The `compile_commands.json` file is used to analyze projects on the Linux system\. You can find more information on the relevant [documentation page](https://pvs-studio.com/en/docs/manual/6557/)\.

If generating the `compile_commands.json` file is not possible, you can use the compilation trace mode\. To do so, install the `strace` utility of the 4\.7 version or later\. It enables the analyzer to collect essential information about project compilation during the build process\.

You can build the project and track its compilation process using the following command:

```cpp
pvs-studio-analyzer trace -- build_command -o /path/to/strace_out
```

where:

* `build_command` is the command used to build the project;
* `-o` is the path to the compilation trace file\. If no flag is specified, a file named `strace_out` is saved in the CWD\.

As a result of the tracing, a file named `strace_out` will be created by default\.

Once you have obtained the `strace_out` compilation trace file, you can run the analysis using the following command:

```cpp
pvs-studio-analyzer analyze -f /path/to/strace_out
```

You can also pass additional parameters when starting the analysis:

* `-f` is the path to the file containing the compilation trace results;
* `-l` is the path to the final analyzer report file;
* `-u` is the path to the [suppress file](https://pvs-studio.com/en/docs/manual/0032/);
* `-c` is the path to the [`.pvsconfig`](https://pvs-studio.com/en/docs/manual/6630/) analysis configuration file;
* `--intermodular` enables the [intermodular analysis](https://pvs-studio.com/en/blog/posts/cpp/0851/) mode\.

### Visual Studio Code

You can also use compilation monitoring with the [PVS\-Studio plugin](https://pvs-studio.com/en/docs/manual/6646/) for Visual Studio Code\.

To start compilation monitoring, use the **PVS\-Studio: Run compiler monitoring for C and C\+\+** command in the Visual Studio Code Command Palette \(`Ctrl + Shift + P`\)\.

When monitoring starts, the plugin window containing the table will display an indicator showing that monitoring is running:

![1399_PVS_embedded/image3.png](https://import.viva64.com/docx/blog/1399_PVS_embedded/image3.png)

Once compiler calls are intercepted, their number will be displayed in the monitoring indicator, and the start button will appear\.

![1399_PVS_embedded/image4.png](https://import.viva64.com/docx/blog/1399_PVS_embedded/image4.png)

You can start the project analysis by clicking the button or using the **PVS\-Studio: Stop monitoring and start analysis** command in the Visual Studio Code command palette\.

The first time you run monitoring on a project, the plugin will prompt you to edit the `./.PVS-Studio/CLMonitorAnalyzerConfig.jsonc` configuration file\.

![1399_PVS_embedded/image5.png](https://import.viva64.com/docx/blog/1399_PVS_embedded/image5.png)

Click **Edit** to set the following parameters:

* the path to a monitoring dump file \(by default, `./.PVS-Studio/lastMonitoring.zip`\);
* the path to the configuration file or directory containing `.pvsconfig` files\.

Click **Continue** to run the analysis using the default settings\.

If the source code files and the build configuration haven't been changed, you can use the dump file to run the analysis\. To do this, select the **PVS\-Studio: Start analysis from compiler monitoring dump file** command from the Visual Studio Code command palette\.

In PVS\-Studio plugin for Visual Studio Code, you can use the Wrap Compilers mode\. To enable it, open the **Monitoring \(C and C\+\+\)** tab in the plugin settings and specify the names of the compiler executable files you want to monitor\.

![1399_PVS_embedded/image6.png](https://import.viva64.com/docx/blog/1399_PVS_embedded/image6.png)


> \*\*Note\\\.\*\* To enable monitoring in this mode, restart Visual Studio Code with administrator privileges\\\.

## A standard for improving reliability

Fixing bugs in embedded systems after a device ships is both difficult and expensive\. This may require product recalls, firmware updates, reshipping, or replacing devices entirely in the worst case\. Such issues come at a high cost, both financially and in terms of reputation\.

To minimize risks, errors must be detected and fixed at the development stage\. When there are many errors, it's much more effective to classify and track them using industry standards\.

For example, the IEC 61508\-7 industry standard requires using a subset of the C and C\+\+ languages, coding standards, and static code analyzers when designing systems with a high safety integrity level \(SIL\)\.

The automotive industry relies on the ISO 26262, which establishes functional safety requirements for road vehicles\. The standard also specifies requirements for verifying software modules and recommends using static code analysis as part of the verification process\.

MISRA C and MISRA C\+\+ have become the industry standard for defining safe subsets of the C and C\+\+ languages\.

The [MISRA standards](https://pvs-studio.com/en/docs/manual/6966/) provide guidelines for developing safe and reliable C and C\+\+ software in safety\-critical fields, including automotive, aerospace, medical devices, and industrial automation\. These are industries where the cost of failure is exceptionally high\.

MISRA improves software safety by preventing bugs and vulnerabilities and by restricting complex language features that can cause unexpected program behavior\.

Its authors have scrutinized international C and C\+\+ standards and listed every possible way to make a mistake\. The MISRA C and MISRA C\+\+ standards provide guidelines to help reduce errors, improve code readability, and enhance maintainability\.

Manually enforcing code quality in large projects is both difficult and time\-consuming\. For this reason, MISRA strongly encourages the use of automated code quality tools\.

PVS\-Studio supports code analysis to ensure compliance with multiple MISRA standards\. At the time of writing, it covers the following Mandatory and Required rules:

* MISRA C 2012 — 80%;
* MISRA C 2023 — 85%;
* MISRA C\+\+ 2008 — 33%;
* MISRA C\+\+ 2023 — 35%\.

In the PVS\-Studio 7\.41 release, we completed work on covering the MISRA C 2023 standard, achieving 85% coverage\. We're not stopping there: This year, we've already begun expanding our support for the MISRA C\+\+ 2023 standard\.


> For more information on the classification of warnings according to the MISRA C and MISRA C\\\+\\\+ standards, see the relevant section of the \[documentation\]\(https://pvs\-studio\.com/en/pvs\-studio/sast/misra/\)\\\.



When working with MISRA standards, the [MISRA Compliance](https://pvs-studio.com/en/docs/manual/6966/#misra_compliance) report is particularly useful\. It assesses whether a project is compliant with MISRA C and/or MISRA C\+\+, considering all deviations and re\-categorizations\.


> Learn more about the MISRA Compliance report in the relevant section of the \[documentation\]\(https://pvs\-studio\.com/en/docs/manual/6966/\)\\\.

## Dangerous code fragments in embedded projects

We've looked at several ways to analyze projects for embedded systems using PVS\-Studio\. Now let's take a look at some real errors the analyzer found in open\-source embedded projects\.

We'll use several popular real\-time operating systems \(RTOSs\) as examples\. An RTOS is a specialized OS designed to ensure tasks are completed within strict timing constraints\. These systems are widely used in microcontrollers, industrial equipment, electronic devices, and other embedded applications\.

### RT\-Thread

[RT\-Thread](https://github.com/RT-Thread/rt-thread), which originated in China in 2006, is developed by the RT\-Thread Development Team\. It's widely used in IoT devices, home appliances, and industrial equipment\. It offers a well\-developed ecosystem with a wide range of built\-in components, coming close to being a full\-fledged OS\.

The project was checked as of the [cfda3b3](https://github.com/RT-Thread/rt-thread/tree/cfda3b3d1a9935dd14dcb55e43065ca143d68fcf) commit\.

**Fragment N1**

PVS\-Studio warnings:

[V1031](https://pvs-studio.com/en/docs/warnings/v1031/) The 'memcmp' function is not declared\. Passing data to or from this function can be affected\. dhcp\_server\_raw\.c 151

[V1031](https://pvs-studio.com/en/docs/warnings/v1031/) The 'strchr' function is not declared\. Passing data to or from this function can be affected\. dhcp\_server\_raw\.c 718

[V647](https://pvs-studio.com/en/docs/warnings/v647/) The value of 'int' type is assigned to the pointer of 'char' type\. Consider inspecting the assignment: 'p \= strchr\(str\_tmp, '\.'\)'\. dhcp\_server\_raw\.c 718

```cpp
#include <stdio.h>
#include <stdint.h>
// ....
static struct dhcp_client_node *
dhcp_client_find_by_mac
  (struct dhcp_server *dhcpserver, const u8_t *chaddr, u8_t hlen)
{
  struct dhcp_client_node *node;

  for (node = dhcpserver->node_list; node != NULL; node = node->next)
  {
    if (memcmp(node->chaddr, chaddr, hlen) == 0)               // <=
    {
      return node;
    }
  }

  return NULL;
}
// ....
void dhcpd_start(const char *netif_name)
{
  // ....
  char str_tmp[4 * 4 + 4] = DHCPD_SERVER_IP;
  char *p = str_tmp;
  ip4_addr_t ip_start, ip_end;

  p = strchr(str_tmp, '.');      // <=
  if (p)
  {
    p = strchr(p + 1, '.');      // <=
    if (p)
    {
      p = strchr(p + 1, '.');    // <=
    }
  }
  // ....
}
```

Two interesting warnings stem from the same mistake, which fundamentally changes the behavior of the entire source file\. The analyzer reports that the `memcmp` and `strchr` functions aren't declared\. A quick look at the included headers shows that the file is missing `<string.h>`\.

This code still compiles in C because an undeclared function is assumed to return `int` by default\. As a result, the analyzer also reports a second issue: an `int` value is assigned to a `char` pointer\.

Such code can lead to incorrect program behavior, as demonstrated in the article "[A nice 64\-bit error in C](https://pvs-studio.com/en/blog/posts/cpp/0033/)"\. The fix is straightforward: simply add `#include <string.h>` at the beginning of the file\.

**Fragment N2**

PVS\-Studio warning: [V614](https://pvs-studio.com/en/docs/warnings/v614/) Potentially uninitialized pointer 'GPIOx' used\. HAL\_GPIO\.c 48

```cpp
typedef enum
{
    GPIOA,
    GPIOB,
    GPIOC,
    GPIOD,
}enum_GPIOx_t;

void HAL_GPIO_IRQHandler(enum_GPIOx_t fe_GPIO, uint32_t fu32_GPIO_Pin)
{
  GPIO_TypeDef *GPIOx;              // <=

  switch (fe_GPIO)
  {
    case GPIOA:
    case GPIOB:
    {
      GPIOx = GPIOAB;
    }break;

    case GPIOC:
    case GPIOD:
    {
      GPIOx = GPIOCD;
    }break;

    default: break;                 // <=
  }

  if (fe_GPIO == GPIOB || fe_GPIO == GPIOD )
  {
    fu32_GPIO_Pin <<= 16;
  }

  if (GPIOx->RIS & fu32_GPIO_Pin)   // <=
  {
    GPIOx->IC = fu32_GPIO_Pin;

    /* user can call your application process function here */
    /* ...... */
  }
}
```

The analyzer warns that an uninitialized pointer is being used\. The `GPIOx` variable is declared, but it's assigned a value in only four `switch` branches\. In the `default` branch, it remains uninitialized, so using the pointer afterward results in undefined behavior\.

In C, the `enum` parameter can receive any integer value\. If this happens, execution enters the `default` branch, and the pointer remains uninitialized\.

To fix the issue, we'll add appropriate handling to the `default` branch\. For example, return from the function when `fe_GPIO` contains an unknown value:

```cpp
default:
    return;
```

**Fragment N3**

PVS\-Studio warning: [V570](https://pvs-studio.com/en/docs/warnings/v570/) The 'RTC\_DateStruct\-\>RTC\_WeekDay' variable is assigned to itself\. hk32f0xx\_rtc\.c 986

```cpp
void RTC_GetDate(uint32_t RTC_Format, RTC_DateTypeDef *RTC_DateStruct)
{
  uint32_t tmpreg = 0;
  // ....
  /* Check the input parameters format */
  if (RTC_Format == RTC_Format_BIN)
  {
    /* Convert the structure parameters to Binary format */
    RTC_DateStruct->RTC_Year = 
                        (uint8_t)RTC_Bcd2ToByte(RTC_DateStruct->RTC_Year);
    RTC_DateStruct->RTC_Month = 
                        (uint8_t)RTC_Bcd2ToByte(RTC_DateStruct->RTC_Month);
    RTC_DateStruct->RTC_Date = 
                        (uint8_t)RTC_Bcd2ToByte(RTC_DateStruct->RTC_Date);
    RTC_DateStruct->RTC_WeekDay = 
                        (uint8_t)(RTC_DateStruct->RTC_WeekDay);  // <=
  }
}
```

This error is quite interesting\. I reformatted the code snippet because the original was too wide, which makes the issue immediately obvious here\. Developers most likely copied the lines converting the value type from `BCD` to `binary`, but in the last line they forgot to call `RTC_Bcd2ToByte` \(this is a [classic mistake](https://pvs-studio.com/en/blog/posts/cpp/0260/)\)\. As a result, `RTC_WeekDay` is assigned to itself, which is pointless\.

The fixed code:

```cpp
RTC_DateStruct->RTC_WeekDay = 
                    (uint8_t) RTC_Bcd2ToByte(RTC_DateStruct->RTC_WeekDay);
```

**Fragment N4**

PVS\-Studio warning: [V595](https://pvs-studio.com/en/docs/warnings/v595/) The 'cond' pointer was utilized before it was verified against nullptr\. Check lines: 346, 353\. pthread\_cond\.c 346

```cpp
rt_err_t _pthread_cond_timedwait(pthread_cond_t *cond,
                                 pthread_mutex_t *mutex,
                                 rt_int32_t timeout)
{
  rt_err_t result = RT_EOK;
  rt_sem_t sem;
  rt_int32_t time;

  sem = &(cond->sem);    // <=
  if (sem == RT_NULL)
  {
      return -RT_ERROR;
  }
  time = timeout;

  if (!cond || !mutex)   // <=
  {
    return -RT_ERROR;
  }
  // ....
}
```

Developers used the `cond` pointer before checking it for `NULL`\. Such errors are [quite common](https://pvs-studio.com/en/blog/examples/v595/) in projects\.

Two options are possible here:

1. The check is redundant because a valid object is always passed to the function input\.
1. The check is necessary, but the compiler might remove it during optimization because it recognizes that the pointer is used further up in the code\. In this case, a dereference of a null pointer occurs, resulting in undefined behavior\. [This article](https://pvs-studio.com/en/blog/posts/cpp/0306/) provides a more detailed look at a similar case, where the address of an object is obtained relative to a null pointer, followed by dereferencing the pointer\.

To fix the error, we'll add a check at the beginning of the function\. For example:

```cpp
rt_err_t _pthread_cond_timedwait(pthread_cond_t *cond,
                                 pthread_mutex_t *mutex,
                                 rt_int32_t timeout)
{
  rt_err_t result = RT_EOK;
  rt_sem_t sem;
  rt_int32_t time;

  if (!cond || !mutex)
  {
    return -RT_ERROR;
  }

  sem = &(cond->sem);
  if (sem == RT_NULL)
  {
      return -RT_ERROR;
  }
  time = timeout;

  // ....
}
```

### FreeRTOS

[FreeRTOS](https://github.com/freertos) was created by Richard Barry in 2003\. Since 2017, it has been developed under Amazon Web Services\. Its small kernel footprint and excellent portability across dozens of hardware platforms have made it a popular choice for microcontroller\-based devices\.

The project was checked as of the [c73a397](https://github.com/FreeRTOS/FreeRTOS/tree/c73a397a418b1d5935dcc4233e651cf1773a57ca) commit\.

**Fragment N1**

PVS\-Studio warning: [V557](https://pvs-studio.com/en/docs/warnings/v557/) Array overrun is possible\. The value of 'uxTimerID' index could reach 21\. TimerDemo\.c 1167

```cpp
static uint8_t ucAutoReloadTimerCounters[configTIMER_QUEUE_LENGTH + 1] = { 0 };
// ....

static void prvAutoReloadTimerCallback( TimerHandle_t pxExpiredTimer )
{
  size_t uxTimerID;

  uxTimerID = ( size_t ) pvTimerGetTimerID( pxExpiredTimer );

  if( uxTimerID <= ( configTIMER_QUEUE_LENGTH + 1 ) )     // <=
  {
    ( ucAutoReloadTimerCounters[ uxTimerID ] )++;
  // ....
}
```

This error is particularly sneaky and often slips through code reviews\. Few reviewers stop to check an index boundary when the code appears to work correctly\. Tests are also unlikely to catch it, which makes the error even harder to find\. However, accessing an array out of bounds results in undefined behavior\.

The issue stems from using a non\-strict comparison `<=` to set the bounds of the `uxTimerID` index\. As a result, `uxTimerID` can take the `configTIMER_QUEUE_LENGTH + 1` value, which is also the size of the array\. Accessing an element at that index results in going outside the array bounds\.

The fixed code:

```cpp
if( uxTimerID < ( configTIMER_QUEUE_LENGTH + 1 ) )
```

**Fragment N2**

PVS\-Studio warning: [V547](https://pvs-studio.com/en/docs/warnings/v547/) Expression 'i \+ 1 \> \(4 \+ 32\)' is always false\. trcSnapshotRecorder\.c 831

```cpp
static uint8_t writeInt8(void * buffer, uint8_t i, uint8_t value)
{
  TRACE_ASSERT(buffer != (void*)0, "writeInt8: buffer == NULL", 0);

  if (i >= MAX_ARG_SIZE)
  {
    return 255;
  }

  ((uint8_t*)buffer)[i] = value;

  if (i + 1 > MAX_ARG_SIZE)
  {
    return 255;
  }

  return ((uint8_t) (i + 1));
}
```

The error is that the second check, `if (i + 1 > MAX_ARG_SIZE)`, is always false after the first check, `if (i >= MAX_ARG_SIZE)`\.

Once `i` passes the first check, `i + 1` can no longer exceed `MAX_ARG_SIZE`\. It's likely that one of the checks is redundant, or the second condition was intended to be different\.

### Zephyr

[Zephyr](https://github.com/zephyrproject-rtos/zephyr) launched in 2016 with Intel's support and is now being developed under the Linux Foundation\. It targets IoT, embedded devices, and automotive systems, and features a modular architecture with a wide range of built\-in subsystems\.

The project was checked as of the [c6da464](https://github.com/zephyrproject-rtos/zephyr/tree/c6da46432a348b5a07e40e48692428eb01c968c3) commit\.

**Fragment N1**

PVS\-Studio warning: [V547](https://pvs-studio.com/en/docs/warnings/v547/) Expression 'conv\-\>pad0\_value \> 0' is always true\. cbprintf\_complete\.c 1224

```cpp
static char *encode_float(/*....*/)
{
  // ....
  if ((decexp < 0) && (precision > 0)) {
    conv->pad0_value = -decexp;
    if (conv->pad0_value > precision) {
      conv->pad0_value = precision;
    }

    precision -= conv->pad0_value;
    conv->pad_postdp = (conv->pad0_value > 0); // <=
  }
  // ....
}
```

The analyzer reports that `conv->pad0_value > 0` is always true\. As a result, the `conv->pad_postdp` variable always receives the same value\. Here's why the condition is always true:

1. As soon as execution enters the first `if` block, `conv->pad0_value` is assigned the `-decexp` value\. Since `decexp < 0`, the result is always positive\.
1. If execution enters the nested `if` block, the value remains positive because `precision > 0`\.
1. As a result, `conv->pad0_value` is always greater than zero\.

Most likely, the condition is redundant and can be removed\. Alternatively, the initialization of `pad0_value` needs to be moved outside the `if` block\. The final decision is up to the developers\.

**Fragment N2**

PVS\-Studio warning: [V557](https://pvs-studio.com/en/docs/warnings/v557/) Array overrun is possible\. The value of 'keep\_cnt \+\+' index could reach 16\. cbprintf\_packaged\.c 1143

```cpp
int cbprintf_package_convert(/*....*/)
{
  // ....
  __ASSERT_NO_MSG(keep_cnt < sizeof(keep_str_pos));
  if (keep_cnt < sizeof(keep_str_pos)) {
    keep_str_pos[keep_cnt++] = arg_idx;
    keep_str_pos[keep_cnt++] = arg_pos;
  }
  // ....
}
```

This is a particularly interesting case\. The developers correctly checked the array bounds but overlooked how the post\-increment operator affects the index\. Here's what happens:

1. the `keep_cnt < sizeof(keep_str_pos)` condition allows `keep_cnt` to reach `N - 1`, where `N` is the array size;
1. the first post\-increment accesses the array at the `N - 1` index and increments `keep_cnt` to `N`;
1. the second post\-increment accesses the array at the `N` index and increments `keep_cnt` to `N + 1`\.

Accessing outside the array bounds results in undefined behavior\. We can fix the code by rewriting the condition as follows:

```cpp
if (keep_cnt + 1 < sizeof(keep_str_pos))
```

**Fragment N3**

PVS\-Studio warning: [V779](https://pvs-studio.com/en/docs/warnings/v779/) Unreachable code detected\. It is possible that an error is present\. sched\.c 345

```cpp
#define z_except_reason(reason) do { \
    __EXCEPT_LOC();              \
    z_fatal_error(reason, NULL); \
  } while (false)

#define k_panic()  z_except_reason(K_ERR_KERNEL_PANIC)

void z_thread_halt(/*....*/)
{
  // ....
  if ((thread == _current) && !arch_is_in_isr()) {
    if (z_is_thread_essential(thread)) {
      k_spin_unlock(&_sched_spinlock, key);
      k_panic();                                   // <=
      key = k_spin_lock(&_sched_spinlock);         // <=
    }
    // ....
}
```

The analyzer detected unreachable code\. The `k_panic` macro calls `z_fatal_error`, which terminates the system and never returns the control flow\. As a result, the line that follows it is never executed\.

Unfortunately, it's hard to recommend the right solution without more information\. It's possible that this line simply doesn't belong here\.

**Fragment N4**

PVS\-Studio warning: [V795](https://pvs-studio.com/en/docs/warnings/v795/) Please note that the size of the 'time\_t' type is not 64 bits\. After year 2038, the program will work incorrectly\. clock\.c 47

```cpp
static void timespec_from_ticks(uint64_t ticks, struct timespec *ts)
{
  uint64_t elapsed_secs = ticks / CONFIG_SYS_CLOCK_TICKS_PER_SEC;
  uint64_t nremainder = ticks % CONFIG_SYS_CLOCK_TICKS_PER_SEC;

  *ts = (struct timespec){
    .tv_sec = (time_t)elapsed_secs,
    /* For ns 32 bit conversion can be used since its smaller than 1sec. */
    .tv_nsec = (int32_t)k_ticks_to_ns_floor32(nremainder),
  };
}
```

The problems of the future are already knocking at the door\. In just 12 years, on January 19, 2038, this project will run into the classic [Year 2038 problem](https://en.wikipedia.org/wiki/Year_2038_problem)\.

The root cause is that `time_t` will no longer behave as expected\. Its behavior will depend on the platform because the type stores the number of seconds since January 1, 1970\. After the cutoff date, the value will overflow, causing incorrect time calculations\.

## How to fix issues

To keep dangerous code patterns out of your codebase, it's important to take a comprehensive approach to software quality\. This may include code reviews, manual and automated testing, dynamic analysis, and other verification techniques\.

Static code analysis is one of the most effective and cost\-efficient ways to catch issues early in the development process\. [Try PVS\-Studio](https://pvs-studio.com/en/pvs-studio/try-free/) on your project for free and [explore pricing](https://pvs-studio.com/en/order/) for the full version\. 

If you're still looking for a reason to adopt static analysis, here are [five reasons why it is important for business](https://pvs-studio.com/en/blog/posts/1046/)\.

## Additional links:

* [Why do you need the MISRA Compliance report and how to generate one in PVS\-Studio?](https://pvs-studio.com/en/blog/posts/cpp/0863/)
* [What is MISRA and how to cook it](https://pvs-studio.com/en/blog/posts/cpp/0702/) 
* [How to run PVS\-Studio on Linux and macOS](https://pvs-studio.com/en/docs/manual/0036/)
* [Build\-system independent analysis \(C and C\+\+\)](https://pvs-studio.com/en/docs/manual/0031/)