﻿# Bugs in the Wild West: Top 10 C and C\+\+ errors of 2025

All year long, we've been riding across the vast plains of open\-source code, investigating crimes, taking out vulnerabilities, and collecting trophies\. Today, we decided to step into the dustiest saloon: an experienced sheriff leans against the bar and reminisces about ten most daring and dangerous bugs in the Wild West\.

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

## Want an interesting story?

For the entire year, we've been battling various bugs from C and C\+\+ open\-source projects\. We caught each one, interrogated it, and recorded its misdeeds in the file\. Now, it's time to recall the most notorious cases\.

Today, I'll tell you a story about the 10 most interesting bugs we encountered in different corners of the Wild West\. For each of these fragments, we have a separate file—a full article\. And for the most dedicated, we've selected 5 most popular articles on C and C\+\+ projects posted this year:

* [How frivolous use of polymorphic allocators can imbitter your life](https://pvs-studio.com/en/blog/posts/cpp/1212/)
* [C\+\+ programmer's guide to undefined behavior](https://pvs-studio.com/en/blog/posts/cpp/1215/)
* [History of C and C\+\+\. Part two: standardization of C and C\+\+, Qt, Clang, and Unreal Engine](https://pvs-studio.com/en/blog/posts/cpp/1224/)
* [std::array in C\+\+ is faster than array in C\. Sometimes](https://pvs-studio.com/en/blog/posts/cpp/1231/)
* [Safe array handling? Never heard of it Never heard of it](https://pvs-studio.com/en/blog/posts/cpp/1241/)

You can find the complete list of articles from our blog on our website via the [link](https://pvs-studio.com/en/blog/posts/)\.

## Sit down, traveler, the story will be a long one

**N10**

Once, we had a case about a missing horse\. The mare was always in the stable, but whenever we wanted to ride to town, it seemed to vanish into thin air\.

The PVS\-Studio warning: [V674](https://pvs-studio.com/en/docs/warnings/v674/) The literal '0\.5f' of 'float' type is being implicitly cast to 'unsigned char' type while calling the 'SetRenderColor' function\. Inspect the second argument\. [grenade\_bugbait\.cpp](https://github.com/ValveSoftware/source-sdk-2013/blob/68c8b82fdcb41b8ad5abde9fe1f0654254217b8e/src/game/server/hl2/grenade_bugbait.cpp#L168) 168

```cpp
typedef unsigned char byte;

inline void CBaseEntity::SetRenderColor( byte r, byte g, byte b, byte a )
{
  m_clrRender.Init( r, g, b, a );
}

void CGrenadeBugBait::BugBaitTouch( CBaseEntity *pOther )
{
  ....
  if ( pSporeExplosion )
  {
    ....
    pSporeExplosion->SetRenderColor( 0.0f, 0.5f, 0.25f, 0.15f ); // <=
    ....
  }
  ....
}
```

The `SetRenderColor` function sets the **RGBA** color values, where each parameter is of the `unsigned char` type with a possible value range of `[0 .. 255]`\. When attempting to pass arguments of the `float` type, the fractional part will be truncated\. Therefore, `r`, `g`, `b`, `a` function parameters will have values equal to `0`\.

Unfortunately, the repository lacks blame information, so I have two scenarios on how this error appeared in the code\.

1. The function once processed colors in a floating\-point representation\. The processing was later changed to integers, but not all call sites were updated\.
1. The developer mistakenly believed that `SetRenderColor` handled floating\-point numbers and set them accordingly\.

Here are similar warnings:

* V674 The literal '0\.5f' of 'float' type is being implicitly cast to 'unsigned char' type while calling the 'SetRenderColor' function\. Inspect the second argument\. weapon\_bugbait\.cpp 171
* V674 The literal '25\.6' of 'double' type is being implicitly cast to 'int' type while calling the 'SetScrollRate' function\. Inspect the first argument\. grenade\_tripmine\.cpp 179


> We detected this bug in the Source SDK project\\\. You can find the full article at the \[link\]\(https://pvs\-studio\.com/en/blog/posts/cpp/1281/\)\\\.



**N9**

We once had to ride a hundred same trails across the prairie\. It so happened that we turned onto one we had already ridden\. Only this time, it led somewhere completely different\.

The PVS\-Studio warning: [V517](https://pvs-studio.com/en/docs/warnings/v517/) The use of 'if \(A\) \{\.\.\.\} else if \(A\) \{\.\.\.\}' pattern was detected\. There is a probability of logical error presence\. Check lines: 2903, 3053\. [erl\_bif\_info\.c 2903](https://github.com/erlang/otp/blob/maint-28/erts/emulator/beam/erl_bif_info.c#L2903)

```cpp
BIF_RETTYPE system_info_1(BIF_ALIST_1)
{
  ....
  if (is_tuple(BIF_ARG_1)) {                                    // L2778
    ....
  } else if (BIF_ARG_1 == am_scheduler_id) {                    // L2782
    ....
  }
  ....
  else if (BIF_ARG_1 == am_garbage_collection) {                // L2903
    ....
  } else if (BIF_ARG_1 == am_fullsweep_after) {                 // L2921
    ....
  }
  else if (BIF_ARG_1 == am_garbage_collection) {                // L3053
    ....
  } else if (BIF_ARG_1 == am_instruction_counts) {              // L3056
    ....
  }
  ....
  else if (ERTS_IS_ATOM_STR("halt_flush_timeout", BIF_ARG_1)) { // L3552
    ....
  }
}
```

The analyzer has detected several branches with identical checks in a function containing a huge number of `if-else if` statements—[roughly 800 lines](https://github.com/erlang/otp/blob/maint-28/erts/emulator/beam/erl_bif_info.c#L2771-L3564)\. Each of them, however, has different logic: [the first check](https://github.com/erlang/otp/blob/maint-28/erts/emulator/beam/erl_bif_info.c#L2903-L2920) and [second check](https://github.com/erlang/otp/blob/maint-28/erts/emulator/beam/erl_bif_info.c#L3053-L3054)\. Given the number of branches and the 150\-line gap between the duplicates, it's hardly surprising that this could happen\. Static analysis helps prevent such cases\.


> We detected this bug in the Erlang project; you can find the full article at the \[link\]\(https://pvs\-studio\.com/en/blog/posts/cpp/1305/\)\\\.



**N8**

I knew a sheriff who had only one verdict for all crimes: "Not guilty\." He was a strange one\.

The PVS\-Studio warning: [V523](https://pvs-studio.com/en/docs/warnings/v523/) The 'then' statement is equivalent to the subsequent code fragment\. [cmComputeLinkInformation\.cxx 1748](https://gitlab.kitware.com/cmake/cmake/-/blob/v4.1.0/Source/cmComputeLinkInformation.cxx#L1748)

```cpp
bool cmComputeLinkInformation::CheckImplicitDirItem(LinkEntry const& entry)
{
  BT<std::string> const& item = entry.Item;

  // We only switch to a pathless item if the link type may be
  // enforced.  Fortunately only platforms that support link types
  // seem to have magic per-architecture implicit link directories.
  if (!this->LinkTypeEnabled) {
    return false;
  }

  // Check if this item is in an implicit link directory.
  std::string dir = cmSystemTools::GetFilenamePath(item.Value);
  if (!cm::contains(this->ImplicitLinkDirs, dir)) {
    // Only libraries in implicit link directories are converted to
    // pathless items.
    return false;
  }

  // Only apply the policy below if the library file is one that can
  // be found by the linker.
  std::string file = cmSystemTools::GetFilenameName(item.Value);
  if (!this->ExtractAnyLibraryName.find(file)) {
    return false;
  }

  return false;
}
```

The analyzer hints that there is definitely something wrong with the `CheckImplicitDirItem` function:

* the `then` branch of the last `if` statement duplicates the code below \(`return false;`\);
* every branch of the function execution ends with `false` return;
* when called from `[AddFullItem](https://gitlab.kitware.com/cmake/cmake/-/blob/v4.1.0/Source/cmComputeLinkInformation.cxx#L1685)`, it'll never trigger an early return;
* the full function body can be replaced with `return false;`, as this won't change the program behavior\.

Note that the function is written using the "[early return](https://szymonkrajewski.pl/why-should-you-return-early/)" pattern that helps reduce code nesting: the most positive result is placed at the end of the function, and the rest of the code—in case of divergence from the function purpose—should terminate the function as early as possible\.

In our example, we can assume that the most "positive" result of the function is that an object of the `LinkEntry` type has passed all the necessary checks with a `true` return value\.

Here's an option how to fix the code:

```cpp
....
std::string file = cmSystemTools::GetFilenameName(item.Value);
if (!this->ExtractAnyLibraryName.find(file)) {
  return false;
}
return true;
```


> We detected this bug in the CMake project; you can find the full article at the \[link\]\(https://pvs\-studio\.com/en/blog/posts/cpp/1277/\)\\\.



**N7**

Once in a village, I saw a desperate player who bet all his gold on the card that wasn't even in the deck\. The judge just threw up his hands, and the gold remained lying on the table\.

The PVS\-Studio warning:

[V783](https://pvs-studio.com/en/docs/warnings/v783/) Dereferencing of the invalid iterator 'shades\.end\(\)' might take place\. [ColorHelper\.cpp 194](https://github.com/microsoft/terminal/blob/fc0a06c3b6cae2ede1326eef202a800244365ebd/src/cascadia/TerminalApp/ColorHelper.cpp#L194)

```cpp
winrt::Windows::UI::Color ColorHelper::GetAccentColor(
    const winrt::Windows::UI::Color& color
)
{
    ....
    auto shades = std::map<float, HSL>();
    ....

    // 3f is quite nice if the whole non-client area is painted
    constexpr auto readability = 1.75f;
    for (auto shade : shades)
    {
        if (shade.first >= readability)
        {
            return HslToRgb(shade.second);
        }
    }
    return HslToRgb(shades.end()->second);    // <=
}
```

Is it possible that none of the shades will meet the readability criteria? We can't say for sure, but it's quite likely\. This is a _textbook case_ of [undefined behavior](https://pvs-studio.com/en/blog/terms/0066/)—no need to flash any psychic paper to prove it, since dereferencing `std::map::end()` causes exactly that, as this iterator points just past the last element in a `std::map`\.


> We detected this bug in the Windows Terminal project; you can find the full article at the \[link\]\(https://pvs\-studio\.com/en/blog/posts/cpp/1267/\)\\\.



**N6**

I once made a deal with a fellow traveler to split a treasure we found\. He nodded, turned around, and vanished like a mirage\. No one has seen him since\.

The PVS\-Studio warning: [V758](https://pvs-studio.com/en/docs/warnings/v758/) The 'graph' reference becomes invalid when smart pointer returned by a function is destroyed\. [utils\.cpp 391](https://github.com/opencv/opencv/blob/12b64b0e2abd91f235cf3cc49df0f0f985aa0fee/modules/calib3d/src/usac/utils.cpp#L391)

```cpp
template<typename T>
struct Ptr : public std::shared_ptr<T>;
// ....
Ptr<FlannNeighborhoodGraph> FlannNeighborhoodGraph::create(
  const Mat &points, int points_size,
  int k_nearest_neighbors_, bool get_distances,
  int flann_search_params_, int num_kd_trees) 
{           
    return makePtr<FlannNeighborhoodGraphImpl>(points, points_size,
                               k_nearest_neighbors_, get_distances,
                               flann_search_params_, num_kd_trees);
}

void Utils::densitySort (const Mat &points, int knn, 
                         Mat &sorted_points, std::vector<int> &sorted_mask) 
{
  // ....
  // get neighbors
  FlannNeighborhoodGraph &graph =                                  // <=
    *FlannNeighborhoodGraph::create(points, points_size, knn,
                                    true /*get distances */, 6, 1);

  std::vector<double> sum_knn_distances (points_size, 0);
  for (int p = 0; p < points_size; p++) {
    const std::vector<double> &dists = graph.getNeighborsDistances(p);
    for (int k = 0; k < knn; k++)
      sum_knn_distances[p] += dists[k];
  }
  // ....
}
```

<details>
   <summary>A bit more context on Ptr</summary>

```cpp
template<typename T>
struct Ptr : public std::shared_ptr<T>
{
  inline Ptr(const std::shared_ptr<T>& o) 
    CV_NOEXCEPT : std::shared_ptr<T>(o) {}
  inline Ptr(std::shared_ptr<T>&& o) 
    CV_NOEXCEPT : std::shared_ptr<T>(std::move(o)) {}
  typename std::add_lvalue_reference<T>::type operator*() const 
    CV_NOEXCEPT { return *std::shared_ptr<T>::get(); }
  // ....
}

template<typename _Tp, typename ... A1> static inline
Ptr<_Tp> makePtr(const A1&... a1)
{
  static_assert( !has_custom_delete<_Tp>::value,
                 "Can't use this makePtr with custom DefaultDeleter");
  return (Ptr<_Tp>)std::make_shared<_Tp>(a1...);
}
```


</details>
Using smart pointers doesn't resolve the issues of dangling references and memory access here\. Let's dig into this\. This is how the code works\.

1. The `create` function creates and returns a smart pointer to the `FlannNeighborhoodGraphImpl` type, and its object reference count is one\.
1. The `graph` reference is created for the value of this smart pointer while the object reference count remains unchanged\.
1. Since the pointer is a temporary object, the reference counter will reach null after initialization is done, releasing the managed object\. Now, the reference points to a destroyed object\.
1. The `for` loop references an invalid reference\.

As a result, the code that seemed correct leads to undefined behavior\. Moreover, PVS\-Studio isn't the only tool that detects this issue; the sanitizer does this as well\. Here's the [proof](https://godbolt.org/z/rxf3xEc37)\.

To fix this, we need to save the smart pointer so that the `FlannNeighborhoodGraph` object remains until the end of the block\. For example, we can do [like this](https://godbolt.org/z/rxf3xEc37):

```cpp
std::vector<double> sum_knn_distances (points_size, 0);

{
  // get neighbors
  auto graph = FlannNeighborhoodGraph::create(points, points_size, knn,
                                              true /*get distances */, 6, 1);

  for (int p = 0; p < points_size; p++) {
    const std::vector<double> &dists = graph->getNeighborsDistances(p);
    for (int k = 0; k < knn; k++) 
      sum_knn_distances[p] += dists[k];
  }
}
```

We also limited the `graph` scope to free the resource after the loop execution\.


> We detected this bug in the OpenCV project; you can find the full article at the \[link\]\(https://pvs\-studio\.com/en/blog/posts/cpp/1321/\)\\\.



**N5**

Once, a local expert drew a map of a river crossing, but he ran out of charcoal\. So, the most dangerous section, drawn with the last bits of charcoal, washed away with the first rain\. That's where everyone kept disappearing\.

The PVS\-Studio warnings:

[V629](https://pvs-studio.com/en/docs/warnings/v629/) Consider inspecting the '1 << \(brake\-\>type \+ 1\)' expression\. Bit shifting of the 32\-bit value with a subsequent expansion to the 64\-bit type\. [phpdbg\_bp\.c 1209](https://github.com/php/php-src/blob/c998c36b97d13cf936a9f5c4180d1104a6db6b80/sapi/phpdbg/phpdbg_bp.c#L1209)

[V784](https://pvs-studio.com/en/docs/warnings/v784/) The size of the bit mask is less than the size of the first operand\. This will cause the loss of higher bits\. [phpdbg\_bp\.c 1209](https://github.com/php/php-src/blob/c998c36b97d13cf936a9f5c4180d1104a6db6b80/sapi/phpdbg/phpdbg_bp.c#L1209) 

```cpp
uint64_t flags
....
PHPDBG_API void phpdbg_delete_breakpoint(zend_ulong num)
{
  ....     
  if ((brake = phpdbg_find_breakbase_ex(num, &table, &numkey, &strkey))) {
      int type = brake->type;
      char *name = NULL;
      size_t name_len = 0L;

      switch (type) {
        ....
        default: {
          if (zend_hash_num_elements(table) == 1) {
            PHPDBG_G(flags) &= ~(1<<(brake->type+1));              // <=
          }
        }
      }
    ....
  }
}
```

Math guys, no time to relax\. The `flags` variable is of the `unsigned long int` type, while `brake->type` is of the `int` type\. The code is designed to remove a specific bit from `flags`\. Now, let's take a closer look at what's really going on:

1. The `1` constant of the `int` type is shifted left by a certain number of bits\. Most often, the `int` type is of 32 bits\. We hope that the shift isn't by 32 or more bits, otherwise we get [undefined behavior](https://en.cppreference.com/w/c/language/operator_arithmetic.html#Shift_operators)\.
1. The result of the shift is bitwise inverted\. The result of the inversion still has the `int` type\.
1. The result of the inversion is expanded to a 64\-bit unsigned type due to the left operand\. Since the original type is signed, sign extension will occur\. This means that for positive numbers, the 32 most significant bits will contain zero bits, and for negative numbers, they'll contain ones\.
1. The bitwise "AND" applies the conversion result to `flags`\. The loss of significant bits in `flags` will occur when the right operand is positive\. It'll only be so when there is a 31\-bit shift to the left—when the 31st bit in `flags` has to be cleared\. Catch a [proof](https://godbolt.org/z/ejnze5xMh)\.

Notice how much we need to keep in mind for such a harmless expression? The problem lies in the different operand sizes and signs of some subexpressions\. To fix it, developers just need to change the type of the `1` constant from `int` to `unsigned long long`, and the code will execute as intended:

```cpp
PHPDBG_G(flags) &= ~( 1uLL <<(brake->type+1));
```


> We discovered this bug in the PHP project; you can find the full article via the \[link\]\(https://pvs\-studio\.com/en/blog/posts/cpp/1280/\)\\\.



**N4**

I once saw a young cowboy chasing an outlaw\. He cornered him in a dead end in one of the local bars, but he fired not at the criminal, but at his own reflection in a dusty mirror, shattering it to pieces\.

The PVS\-Studio warning: [V794](https://pvs-studio.com/en/docs/warnings/v794/) The assignment operator should be protected from the case of 'this \=\= &other'\. [fs\_path\.cpp 36](https://github.com/NauEngine/NauEnginePublic/blob/020cbfec7bd4cff7ff4303e0f31d75eebed584be/engine/core/kernel/src/io/fs_path.cpp#L36)

```cpp
FsPath& FsPath::operator=(FsPath&& other)
{
    m_path = std::move(other.m_path);
    other.m_path.clear();
    return *this;
}
```

In this snippet, we have the move assignment operator for the `FsPath` class, which transfers data from the other object to the current instance\. However, there's no check for self\-assignment `(this == &other)`, which could lead to unintended consequences\.

If an attempt is made to assign the object to itself, the `m_path = std::move(other.m_path);` operation moves the contents of `other.m_path` into `m_path`, and the subsequent call to `other.m_path.clear();` clears the data\. As a result, `m_path` ends up in an unexpected state, and one can only wish developers happy debugging :\)

To eliminate the risk, we recommend adding the following check at the beginning of the operator:

```cpp
if (this == std::addressof(other))
{
    return *this;
}
```

Using `std::addressof` instead of the `&` operator ensures correct address comparison even when the operator `&` is overloaded in the class\.


> We detected this bug in the Nau Engine project; you can find the full article at the \[link\]\(https://pvs\-studio\.com/en/blog/posts/cpp/1244/\)\\\.



**N3**

I once saw a shaman trying to summon a spirit without reaching the sacred grounds\. A spirit came, but it was a completely different one—a coyote from the nearest ravine\.

The PVS\-Studio warning: [V1099](https://pvs-studio.com/en/docs/warnings/v1099/) sing the 'window\_id' function of uninitialized derived class while initializing the 'modal\_dialog' base class will lead to undefined behavior\. [install\_dependencies\.hpp](https://github.com/wesnoth/wesnoth/blob/master/src/gui/dialogs/addon/install_dependencies.hpp#L29) 29

```cpp
class install_dependencies : public modal_dialog
{
public:
  explicit install_dependencies(const addons_list& addons)
    : modal_dialog(window_id()), addons_(addons)   // <=
  {}
....
private:
  virtual const std::string& window_id() const override;
....
}
```

Thanks to this code snippet, I can tell you more about undefined behavior\.

As we can see above, the `install_dependencies` class is derived from the `modal_dialog` class\. In the `install_dependencies` constructor, the base class is initialized with the value returned by \(wait for it\.\.\.\) the non\-static `window_id` function\. So, this will happen:

1. Execution of the initialization list:
    * a call to the `install_dependencies::window_id` method;
    * a constructor call to the `modal_dialog` class;
    * an initialization of the `addons_` data member;
1. Execution of the constructor body of the `install_dependencies` class\.

This results in a function call of a class object which hasn't been initialized yet\! This violates the following [rule of the standard](https://timsong-cpp.github.io/cppwp/n4861/class.base.init#16):

> Member functions \(including virtual member functions, \[class\.virtual\]\) can be called for an object under construction
>
> Similarly, an object under construction can be the operand of the typeid operator \(\[expr\.typeid\]\) or of a dynamic\_cast \(\[expr\.dynamic\.cast\]\)\.
>
> However, if these operations are performed in a ctor\-initializer \(or in a function called directly or indirectly from a ctor\-initializer\) before all the mem\-initializers for base classes have completed, the program has undefined behavior\.

But wait, there's more\! As you may have noticed, the `window_id` member function is virtual and overridden in the `install_dependencies` class\. Issues may arise later when a programmer writes a derived class where `window_id` is overridden\.

When an object of this derived class is created and the `installed_dependencies` constructor is executed, there's no information about the existence of the new override yet\. So, the `installed_dependencies::window_id` function will always be called in the initialization list\. This may differ from the developers' original intention\.  You can read more about it [here](https://pvs-studio.com/en/blog/posts/cpp/0891/)\.


> We detected this bug in the Wesnoth project; you can find the full article at the \[link\]\(https://pvs\-studio\.com/en/blog/posts/cpp/1261/\)\\\.



**N2**

I knew a cowboy who shot at a shadow on the wall, mistaking it for a lurking enemy\. The shot boomed, plaster crumbled, leaving only a hole in the wall\. The target never existed, and the repairs took a lot of work\.

The PVS\-Studio warning: [V575](https://pvs-studio.com/en/docs/warnings/v575/) The null pointer is passed into 'fseek' function\. Inspect the first argument\. [vid\_ati\_eeprom\.c 61](https://github.com/86Box/86Box/blob/v5.0/src/video/vid_ati_eeprom.c#L61)

```cpp
void
ati_eeprom_load_mach8(ati_eeprom_t *eeprom, char *fn, int mca)
{
    FILE *fp;
    ....
    fp   = nvr_fopen(eeprom->fn, "rb");
    size = 128;
    if (!fp) {
        if (mca) {
            (void) fseek(fp, 2L, SEEK_SET);             // <=
            memset(eeprom->data + 2, 0xff, size - 2);
            fp = nvr_fopen(eeprom->fn, "wb");
            fwrite(eeprom->data, 1, size, fp);
    ....
}
```

We need to load data stored in the video adapter's NVRAM, which we keep in a binary file\. If the file doesn't exist, we need to create it with "default" data\. Let's look at the case where the file is missing\. We shift the file pointer, but it's null\. As a result, we get an `fp` null pointer dereference\.

Let's take a closer look at `fseek`\. The [C11](https://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf#page=354) standard doesn't define requirements for the function first parameter and doesn't guarantee a check for `NULL`\. This means it's up to the standard library developers to handle it properly\. Now let's welcome:

* GNU glibc;
* BSD libc from FreeBSD 14\.3;
* Microsoft Universal CRT from Windows SDK 10\.0\.26100;
* musl v1\.2\.5\.

The last two C standard library implementations are here as guests: 86Box is not designed to work with them, or their compatibility hasn't been checked\. The [build instructions](https://86box.readthedocs.io/en/v5.0/dev/buildguide.html) don't mention alternative implementations either\. So, let's start with the expected standard libraries and ask them to repeat the same actions with a null file pointer\.

**Flicking the power switch**

We take an IBM PS/2 model 55SX from the imaginary shelf and "plug in" the IBM 8514/A 2D accelerator made by ATI\.

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

The first test subject is a Windows instance built using MinGW\. We ensure the NVRAM file is absent before starting—we check the `%userprofile%\86Box VMs\<virtual machine name>\nvr` directory for the `ati8514_mca.nvr`\. file\. If it is there, we delete it\.

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

Turning on the power supply, and\.\.\.

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

Nothing exploded\! Everything is fine: the NVRAM file is written, the computer is running, and the smoke test on glibc is complete\. No defect detected\.

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

Moving on to FreeBSD\. The libc library implements the standard C library in this OS\. This is generally true for all BSD\-family operating systems\.

We use the same configuration\. We check for the absence of the `ati8514_mca.nvr` NVRAM file at the `~/.local/share/86Box/Virtual Machines/<virtual machine name>/nvr` path\. Three, two, one, power is on\.\.\.

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

Well, only an event from [Ben Grubbs'](https://www.youtube.com/watch?v=bfI_u7vACko&t=2330) recent past could better describe this situation :\)

![1330_top_cpp_2025/image7.png](https://import.viva64.com/docx/blog/1330_top_cpp_2025/image7.png)

After opening our eyes, squeezed shut after the explosion, we look at the console: we have confirmed an abnormal exit\!

```cpp
void VMManagerSystem::launchMainProcess() Full Command:
"/root/86Box/build_freebsd/src/86Box"
("--vmpath", "/root/.local/share/86Box/Virtual Machines/somevm",
 "--vmname",
 "somevm")
Connection received on 86Box.socket.5876c5
Connection disconnected
Abnormal program termination while launching main process:
exit code 11, exit status QProcess::CrashExit
```

A core dump file appeared next to the emulator executable\. Let's welcome LLDB:

```cpp
root@freebsd:~/86Box/build_freebsd/src # lldb 86Box -c 86Box.core
(lldb) target create "86Box" --core "86Box.core"
Core file '/root/86Box/build_freebsd/src/86Box.core' (x86_64) was loaded.
(lldb) bt
* thread #1, name = '86Box', stop reason = signal SIGSEGV
  * frame #0: 0x0000000832f880bf
              libc.so.7`_flockfile(fp=0x0000000000000000)
              at _flock_stub.c:65:20
    frame #1: 0x0000000832f8b675
              libc.so.7`fseek(fp=0x0000000000000000, offset=2, whence=0)
              at fseek.c:62:2
    frame #2: 0x00000000018cd964
              86Box`ati_eeprom_load_mach8(eeprom=...., fn=<unavailable>, mca=1)
              at vid_ati_eeprom.c:61:20
```

The `fp` null pointer makes a spectacular fire show—there was no way to lock the file as its descriptor is invalid\. Unfortunately, LLDB didn't really want to work in real time, crashing either with a quiet `lost connection` or with a loud boom and special effects\. Therefore, I can't show you how the code is executed like in Windows\.


> We detected this bug in the 86Box project; you can find the full article at the \[link\]\(https://pvs\-studio\.com/en/blog/posts/cpp/1304/\)\\\.



**N1**

A sheriff I know from a neighboring town once wrote in an interrogation transcript that a witness had confirmed his own testimony\. The court never figured out if it was a mistake or a clever defense tactic\.

The PVS\-Studio warning: [V501](https://pvs-studio.com/en/docs/warnings/v501/) There are identical sub\-expressions to the left and to the right of the '\=\=' operator: PeekArg\.getValNo\(\) \=\= PeekArg\.getValNo\(\) [PPCISelLowering\.cpp 7865](https://github.com/llvm/llvm-project/blob/253d18d032bb17ced8a26d72623b6ade5933f6f3/llvm/lib/Target/PowerPC/PPCISelLowering.cpp#L7865)

```cpp
SDValue PPCTargetLowering::LowerCall_AIX(....) const {
  ....
  for (unsigned I = 0, E = ArgLocs.size(); I != E;) {
    ....
    CCValAssign &GPR1 = VA;
    ....
    if (I != E) {
      // If only 1 GPR was available, there will only be one custom GPR and
      // the argument will also pass in memory.
      CCValAssign &PeekArg = ArgLocs[I];
      if (PeekArg.isRegLoc() && PeekArg.getValNo() == PeekArg.getValNo()) // <=
      {
        assert(PeekArg.needsCustom() && "A second custom GPR is expected.");
        CCValAssign &GPR2 = ArgLocs[I++]; 
        RegsToPass.push_back(std::make_pair(GPR2.getLocReg(),
          DAG.getZExtOrTrunc(ArgAsInt, dl, MVT::i32)));
      }
    }
  ....
}
```

We're assuming for now that it's yet another victim of copy paste\. Let's check whether `getValNo` have any side effects:

```cpp
class CCValAssign{
  ....
  unsigned ValNo;
  unsigned getValNo() const { return ValNo; } 
}
```

Nothing strange here, though\. Look at the last [commit](https://github.com/llvm/llvm-project/commit/b373ec8ce76a00cd079f70d108b13129c3a4a7b9#diff-909a72141a3ecd6bfde54a6344f80d2a194c3eb79622c5845f6c7c119145af6f):

```cpp
CCValAssign &GPR1 = VA;
....
assert(I != E && "A second custom GPR is expected!");
CCValAssign &GPR2 = ArgLocs[I++];
assert(GPR2.isRegLoc() && GPR2.getValNo() == GPR1.getValNo() &&
       GPR2.needsCustom() && "A second custom GPR is expected!");
RegsToPass.push_back(
  std::make_pair(GPR2.getLocReg(),
                 DAG.getZExtOrTrunc(ArgAsInt, dl, MVT::i32)));
```

The idea is clear: an exceptional case that was previously guarded by an assert was redesigned into a regular branch\. The commit text also points to that\.

> This patch implements the caller side of placing function call arguments
>
> in stack memory\. This removes the current limitation where LLVM on AIX
>
> will report fatal error when arguments can't be contained in registers\.

Note that, in addition to the error found, there's another strange assignment:

```cpp
CCValAssign &PeekArg = ArgLocs[I];
....
CCValAssign &GPR2 = ArgLocs[I++]; // here PeekArg == GPR2
```

The developer may intented to write something like this:

```cpp
if (I != E) {
  CCValAssign &GPR2 = ArgLocs[I];
  if (GPR2.isRegLoc() && PeekArg.getValNo() == GPR1.getValNo()) 
  {
    assert(PeekArg.needsCustom() && "A second custom GPR is expected.");
    I++;
    RegsToPass.push_back(std::make_pair(
             GPR2.getLocReg(), DAG.getZExtOrTrunc(ArgAsInt, dl, MVT::i32)));
  }
}
```

But for clarity, developers broke out `PeekArg` from `GPR2` to show that, unlike the previous unconditional code, the argument now needs to be "peeked" first\. And during the copy\-paste process, `GPR1` was accidentally dropped from the condition\.

The corrected `if` likely should be:

```cpp
if (PeekArg.isRegLoc() && PeekArg.getValNo() == GPR1.getValNo())
```

Interestingly, before migrating to GitHub, LLVM had a code review platform, and the commit included a [link](https://reviews.llvm.org/D73209?id=240887#inline-672042) to this website\. There, we can see that manual review can't always save the situation:

![1330_top_cpp_2025/image8.png](https://import.viva64.com/docx/blog/1330_top_cpp_2025/image8.png)


> We found this bug in the LLVM project, the full article is available at the \[link\]\(https://pvs\-studio\.com/en/blog/posts/cpp/1318/\)\\\.

## Conclusion

Silence fell over the saloon, broken only by the creak of the entrance door and the crackling of logs in the fireplace\. Ten most daring bugs of 2025 are now just stories passed from generation to generation\.

In this Wild West, you can't get far without a reliable partner, so my trusted helper in every case has been [PVS\-Studio](https://pvs-studio.com/en/pvs-studio/) analyzer\. It's ready to help you find dangerous code snippets:

* for [open\-source projects](https://pvs-studio.com/en/order/open-source-license/);
* for [educational purposes](https://pvs-studio.com/en/order/for-students/);
* using a [30\-day trial version](https://pvs-studio.com/en/pvs-studio/try-free/) for a glorious beginning\.

And if your path leads you to other territories, I suggest listening to stories about bugs from projects written in Java and C\#\. 

* [Top 10 noteworthy Java errors in 2025](https://pvs-studio.com/en/blog/posts/java/1326/);
* [Top 10 errors found in C\# projects in 2025](https://pvs-studio.com/en/blog/posts/csharp/1328/)\.