<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Unicorn Developer</title>
    <description>The latest articles on DEV Community by Unicorn Developer (@pvsdev).</description>
    <link>https://dev.to/pvsdev</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1110345%2F0615f05a-4746-4c6f-89ff-a4ef95008a77.png</url>
      <title>DEV Community: Unicorn Developer</title>
      <link>https://dev.to/pvsdev</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/pvsdev"/>
    <language>en</language>
    <item>
      <title>Pitfalls of bit fields in C++</title>
      <dc:creator>Unicorn Developer</dc:creator>
      <pubDate>Fri, 30 Oct 2026 13:26:49 +0000</pubDate>
      <link>https://dev.to/pvsdev/pitfalls-of-bit-fields-in-c-3685</link>
      <guid>https://dev.to/pvsdev/pitfalls-of-bit-fields-in-c-3685</guid>
      <description>&lt;p&gt;C++ is a language that lets developers do absolutely anything, and then it just silently watches as they blow everything up. We're used to thinking in terms of bytes, but what if the standard type system seems too wasteful? When your inner perfectionist demands compactness, bit fields are the best solution. Why use an entire eight-bit container for a simple yes-or-no flag when you can carve out exactly one bit with surgical precision? Add a colon, and suddenly you're the master of memory. However, when it comes to saving memory, order and predictability end. A programmer is left to deal with the subtleties of standards and the behavior of specific platforms. Let's take a look under the hood of C++ and see how bit fields actually work.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2sd25e98914rrgvfqfmb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2sd25e98914rrgvfqfmb.png" alt="1423_Bitfields/image1.png" width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;How did I end up here, and why did I even decide to cover this topic?&lt;/p&gt;

&lt;p&gt;For quite some time, I've been working on supporting the MISRA C++ 2023 rules. Yes, PVS-Studio analyzer learns how to check whether a codebase complies with this standard. My task was to implement support for a rule that regulates the co-use of enumerations and bit fields. It all looked simple in my head: all I had to do was check whether the &lt;code&gt;enum&lt;/code&gt; values with a fixed fundamental data type fit within the specified bit field width.&lt;/p&gt;

&lt;p&gt;Have you ever started a task that seemed like a fun little adventure that would take just a couple of hours, only to find yourself stuck in a bottomless pit of troubleshooting for an entire week? That's exactly what happened to me. I got bogged down in trying to implement support for this rule.&lt;/p&gt;

&lt;p&gt;As I tried to untangle the mess, I realized one thing: bit fields in C++ are an underrated topic that every C++ developer should know about.&lt;/p&gt;

&lt;h2&gt;
  
  
  The basics: what are bit fields?
&lt;/h2&gt;

&lt;p&gt;In C++, a bit field is a data-packing mechanism that allows you to allocate memory within a structure or class bit by bit instead of byte by byte. Unlike ordinary types, which always occupy at least one byte, bit fields enable you to allocate exactly the number of bits you want to a particular variable. This makes them invaluable when memory is strictly limited or when you need to store a set of flags as compactly as possible.&lt;/p&gt;

&lt;p&gt;Let's take a look at the syntax for declaring bit fields. It may differ slightly depending on your technical requirements, but the fundamental structure is as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;specifier&lt;/span&gt; &lt;span class="n"&gt;declarator&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;constant&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;expression&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, &lt;code&gt;constant-expression&lt;/code&gt; specifies how many bits to allocate to a particular field.&lt;/p&gt;

&lt;p&gt;The syntax for bit fields is quite interesting. We use a colon to give the compiler a direct instruction to override the usual memory allocation rules. In standard C++ code, the smallest addressable unit is a byte, which contains &lt;code&gt;CHAR_BIT&lt;/code&gt; bits. The implementation defines the &lt;code&gt;CHAR_BIT&lt;/code&gt; macro, but its most common value is eight. The colon separates the variable's logical name from its actual size. This forces the compiler to divide memory into small chunks of a specific size.&lt;/p&gt;

&lt;p&gt;This approach saves memory. How? It eliminates empty and redundant bits. When you declare standard variables, the processor rounds their size up to whole bytes due to architectural constraints. Bit fields work around this limitation by packing multiple fields into a shared storage unit.&lt;/p&gt;

&lt;p&gt;To understand how bit fields save space, we'll compare two ways of storing the same data. Let's say we need to record three system parameters:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;activity status (on/off): 1 bit is enough (values 0 or 1);&lt;/li&gt;
&lt;li&gt;mode (4 modes): 2 bits are enough (combinations 00, 01, 10, and 11);&lt;/li&gt;
&lt;li&gt;error code (from 0 to 7): 3 bits are enough (combinations from 000 to 111).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All the essential information about the object state takes up exactly six bits.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Option 1. Standard structure&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If we create a standard structure in C++, the compiler allocates one byte of memory for each type, since this is the minimum addressable size:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;StandardStruct&lt;/span&gt; 
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;is_active&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;   
  &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;        
  &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;error_code&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;/p&gt;
  The full code
  &lt;br&gt;
&lt;a href="https://godbolt.org/z/1s9v7hhc9" rel="noopener noreferrer"&gt;The example:&lt;/a&gt;&lt;br&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;iostream&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;StandardStruct&lt;/span&gt; 
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;is_active&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;   
  &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;        
  &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;error_code&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
&lt;span class="p"&gt;};&lt;/span&gt; 

&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;StandardStruct&lt;/span&gt; &lt;span class="n"&gt;stStruct&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;"Sizeof stStruct: "&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stStruct&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;"byte(s)"&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;
  Program output
  &lt;br&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;Sizeof&lt;/span&gt; &lt;span class="n"&gt;stStruct&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="n"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;p&gt;&lt;/p&gt;

&lt;p&gt;The program uses 24 memory bits. 24 memory cells were allocated for our six units of information; the remaining 18 cells simply remain empty because the processor architecture can't directly handle units smaller than one byte.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Option 2. Structure using bit fields&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Now let's add the colon syntax. The compiler starts with a fundamental data type, or container, such as &lt;code&gt;unsigned char&lt;/code&gt;, which is one byte (eight bits) in size. It then begins packing fields tightly inside the container:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;BitFieldStruct&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;is_active&lt;/span&gt;  &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
  &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;mode&lt;/span&gt;       &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
  &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;error_code&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;/p&gt;
  The full code
  &lt;br&gt;
&lt;a href="https://godbolt.org/z/9PqjcvoT8" rel="noopener noreferrer"&gt;The example:&lt;/a&gt;&lt;br&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;iostream&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;BitFieldStruct&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;is_active&lt;/span&gt;  &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
  &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;mode&lt;/span&gt;       &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
  &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;error_code&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;BitFieldStruct&lt;/span&gt; &lt;span class="n"&gt;stStruct&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;"Sizeof stStruct: "&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stStruct&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;" byte(s)"&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;
  Program output
  &lt;br&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;Sizeof&lt;/span&gt; &lt;span class="n"&gt;stStruct&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="n"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;p&gt;&lt;/p&gt;

&lt;p&gt;As a result of this mechanism, the entire structure is compressed to one byte. In memory, it appears as a single eight-bit array divided into sectors: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9saacc217a59eb7eus6v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9saacc217a59eb7eus6v.png" alt="1423_Bitfields/image2.png" width="730" height="609"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The compiler handles everything: when reading from or writing to the &lt;code&gt;mode&lt;/code&gt; variable, it automatically generates hidden bit shifts and masks to isolate the required two bits from the rest of the data. This high-density packaging significantly reduces RAM usage in large arrays and embedded systems (microcontrollers).&lt;/p&gt;

&lt;p&gt;How bit fields work and their limitations&lt;/p&gt;

&lt;p&gt;We've covered the basic principles and syntax of bit fields. Now let's take a closer look at how they work and explore the rules imposed by the language.&lt;/p&gt;

&lt;p&gt;Bit fields can exist only inside structures or classes. Developers can't declare a bit field as a standalone variable inside a function. It's also impossible to apply the &lt;code&gt;const&lt;/code&gt; or &lt;code&gt;volatile&lt;/code&gt; qualifiers directly to an individual bit field. Instead, you can apply them indirectly by declaring an object of that structure or class with the relevant qualifier.&lt;/p&gt;

&lt;h3&gt;
  
  
  Data types for bit fields
&lt;/h3&gt;

&lt;p&gt;The next thing to discuss is which data types you can use with bit fields. The C++ standard allows this mechanism only for &lt;em&gt;integral&lt;/em&gt; types and &lt;em&gt;enumerations&lt;/em&gt;. Trying to limit the bit width of floating-point types (&lt;code&gt;float&lt;/code&gt;, &lt;code&gt;double&lt;/code&gt;) or complex objects such as &lt;code&gt;std::string&lt;/code&gt; is technically impossible and will result in a compilation error.&lt;/p&gt;

&lt;p&gt;Bit fields support the following types:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;1&lt;/em&gt;. Integral types (&lt;code&gt;char&lt;/code&gt;, &lt;code&gt;wchar_t&lt;/code&gt;, &lt;code&gt;char8_t&lt;/code&gt;, &lt;code&gt;char16_t&lt;/code&gt;, &lt;code&gt;char32_t&lt;/code&gt;, &lt;code&gt;bool&lt;/code&gt;, &lt;code&gt;short&lt;/code&gt;, &lt;code&gt;int&lt;/code&gt;, &lt;code&gt;long&lt;/code&gt;, and &lt;code&gt;long long&lt;/code&gt;)&lt;em&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;These are the standard options for creating masks and flags. Before C++14, explicitly specifying the &lt;code&gt;signed&lt;/code&gt; or &lt;code&gt;unsigned&lt;/code&gt; modifier for an &lt;code&gt;int&lt;/code&gt; bit field was critical. Otherwise, the compiler determined how to interpret the signed bit. For example, a one-bit &lt;code&gt;int&lt;/code&gt; field without an explicit unsigned modifier could take 0 and -1 instead of the expected 0 and 1. For a &lt;code&gt;bool&lt;/code&gt; field, allocating exactly one bit is enough.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;2. _Enumerations (&lt;code&gt;enum&lt;/code&gt; and &lt;code&gt;enum class&lt;/code&gt;)&lt;/em&gt;._&lt;/p&gt;

&lt;p&gt;Bit fields work well for storing &lt;code&gt;enum&lt;/code&gt; types with a small set of possible values. If an &lt;code&gt;enum&lt;/code&gt; has four possible states, allocating two bits is enough.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;3. _&lt;code&gt;std::byte&lt;/code&gt; (_C++20).&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Starting with &lt;a href="https://timsong-cpp.github.io/cppwp/n5050/cstddef.syn#lib:byte" rel="noopener noreferrer"&gt;C++20&lt;/a&gt;, &lt;code&gt;std::byte&lt;/code&gt; officially joined the list of permitted types. If a structure handles raw data at the hardware level, using &lt;code&gt;std::byte&lt;/code&gt; clearly communicates the developer's intent and prevents accidental arithmetic errors.&lt;/p&gt;

&lt;h3&gt;
  
  
  Rules for working with bit fields
&lt;/h3&gt;

&lt;p&gt;The third important topic to cover is the rules governing bit fields. In C++, four key restrictions apply. &lt;strong&gt;Developers cannot&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;declare an array of bit fields;&lt;/li&gt;
&lt;li&gt;take the address of a bit field;&lt;/li&gt;
&lt;li&gt;create a pointer to a bit field;&lt;/li&gt;
&lt;li&gt;create a reference to a bit field.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's look at some examples to understand why bit fields follow these rules and what happens when you try to get around them. We'll start with a simple structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;HardwareFlags&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;mode&lt;/span&gt;   &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  No taking addresses or creating pointers
&lt;/h4&gt;

&lt;p&gt;The rule against taking addresses or creating pointers stems from a fundamental aspect of computer architecture: a bit field has no physical memory address. Modern processor architectures use the byte as the smallest addressable unit of memory (&lt;code&gt;CHAR_BIT bits&lt;/code&gt;). A processor simply has no way to address, say, the third bit within a byte.&lt;/p&gt;

&lt;p&gt;For this reason, we can't use the address-of operator &lt;code&gt;&amp;amp;&lt;/code&gt; on a bit field:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;HardwareFlags&lt;/span&gt; &lt;span class="n"&gt;flags&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;flags&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;ptr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;flags&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;     &lt;span class="c1"&gt;// doesn't compile&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since individual bit segments don't have unique addresses in a memory cell, it's physically impossible to obtain a direct pointer to such a variable.&lt;/p&gt;

&lt;h4&gt;
  
  
  No address, no references
&lt;/h4&gt;

&lt;p&gt;There's another restriction that comes from the inability to take a bit field's address: you can't bind a standard reference &lt;code&gt;&amp;amp;&lt;/code&gt; to a bit field. In C++, references rely on pointers and memory addressing. Without an address, there's simply nothing for a reference to bind to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;HardwareFlags&lt;/span&gt; &lt;span class="n"&gt;flags&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;checkMode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;ref&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;flags&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;        &lt;span class="c1"&gt;// doesn't compile&lt;/span&gt;
&lt;span class="n"&gt;checkMode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;flags&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;                 &lt;span class="c1"&gt;// doesn't compile&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Arrays: why pointer arithmetic falls short
&lt;/h4&gt;

&lt;p&gt;I'm afraid I have some bad news: you can't create an array of bit fields either. The reason lies in pointer arithmetic. When you create an array, the compiler guarantees that its elements occupy consecutive memory locations. When you access the &lt;code&gt;i&lt;/code&gt;-th element using &lt;code&gt;arr[i]&lt;/code&gt;, the compiler calculates its address relative to the start of the array via pointer arithmetic.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;BrokenStruct&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// doesn't compile&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The anatomy of alignment
&lt;/h2&gt;

&lt;p&gt;Although bit fields aim to save memory, C++ doesn't specify their exact layout within a structure. Compiler developers have considerable freedom in how they pack bits, so a structure's actual size depends on the target platform. This flexibility is impressive, but to understand why it exists, let's take a look at &lt;a href="https://timsong-cpp.github.io/cppwp/n5050/class.bit#1" rel="noopener noreferrer"&gt;what the standard says&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Allocation of bit-fields within a class object is implementation-defined. Alignment of bit-fields is implementation-defined. Bit-fields are packed into some addressable allocation unit.&lt;/p&gt;

&lt;p&gt;[Note 1: Bit-fields straddle allocation units on some machines and not on others. Bit-fields are assigned right-to-left on some machines, left-to-right on others. — end note]&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In reality, this means that the layout rules come not from the language, but from the &lt;a href="https://en.wikipedia.org/wiki/Application_binary_interface" rel="noopener noreferrer"&gt;Application Binary Interface&lt;/a&gt; (ABI) defined for a particular OS. For example, many Unix-like systems use the &lt;a href="https://itanium-cxx-abi.github.io/cxx-abi/abi.html" rel="noopener noreferrer"&gt;Itanium ABI&lt;/a&gt;, but it also leaves some aspects of bit ordering unspecified. The packing rules can vary depending on the OS and architecture. For example, MSVC on Windows and GCC on Linux may compile the same structure differently.&lt;/p&gt;

&lt;p&gt;In this section, we'll focus specifically on how bit fields work. I'll touch on alignment briefly, as I've already covered it in a series of articles: the &lt;a href="https://pvs-studio.com/en/blog/posts/cpp/1339/" rel="noopener noreferrer"&gt;first part&lt;/a&gt; introduces the basic principles, while the &lt;a href="https://pvs-studio.com/en/blog/posts/cpp/1340/" rel="noopener noreferrer"&gt;second&lt;/a&gt; and &lt;a href="https://pvs-studio.com/en/blog/posts/cpp/1369/" rel="noopener noreferrer"&gt;third&lt;/a&gt; explore how inheritance and virtual functions affect alignment.&lt;/p&gt;

&lt;h3&gt;
  
  
  How compilers divide memory into allocation units
&lt;/h3&gt;

&lt;p&gt;The phrase "Bit fields are packed into some addressable allocation unit" describes the concept of an &lt;a href="https://timsong-cpp.github.io/cppwp/n5050/class.bit#1" rel="noopener noreferrer"&gt;&lt;em&gt;allocation unit&lt;/em&gt;&lt;/a&gt;. According to the C++ standard, an allocation unit is an addressable block of hardware memory, such as a byte or machine word, into which bit-fields are packed consecutively. The exact behavior of these units is implementation-defined and depends largely on the platform's ABI.&lt;/p&gt;

&lt;p&gt;A compiler never allocates memory for individual bits out of thin air. Instead, it starts with the fundamental data type you specify when declaring a field and uses it to determine the size of the physical container. For example, if you use &lt;code&gt;unsigned char&lt;/code&gt;, the allocation unit is one byte (8 bits). If you choose &lt;code&gt;unsigned int&lt;/code&gt;, it occupies four bytes (32 bits). The compiler takes this entire physical container and starts slicing it into the specified logical segments, one bit at a time, until no space remains. Once the container runs out of room, the compiler allocates a new unit for the next fields.&lt;/p&gt;

&lt;p&gt;Let's look at how a compiler packs data:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8026rcborreqjruam1kw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8026rcborreqjruam1kw.png" alt="1423_Bitfields/image3.png" width="800" height="957"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;
  The packing algorithm
  &lt;ol&gt;
&lt;li&gt;The compiler receives a list of bit fields declared in a structure.&lt;/li&gt;
&lt;li&gt;It allocates the first container (memory allocation unit) based on the size of the fundamental data type.&lt;/li&gt;
&lt;li&gt;The first bit field occupies the beginning of the newly allocated container.&lt;/li&gt;
&lt;li&gt;The compiler calculates how many free bits remain in the current container.&lt;/li&gt;
&lt;li&gt;It takes the next bit field from the list for analysis.&lt;/li&gt;
&lt;li&gt;It compares the field's width in bits with the number of free bits remaining.&lt;/li&gt;
&lt;li&gt;If the field fully fits in the remaining space, the compiler places it in the current container, directly next to the previous one.&lt;/li&gt;
&lt;li&gt;After successfully placing the field, the compiler updates the free-bit counter and moves on to the next field.&lt;/li&gt;
&lt;li&gt;If the field's width exceeds the available space, the compiler must resolve a standard ambiguity.&lt;/li&gt;
&lt;li&gt;The compiler consults the ABI rules for the target architecture. On x86 and ARM, the compiler moves the entire field to a new container to preserve CPU performance. On other architectures, such as some RISC processors, it may split the field into two parts to maximize memory saving, filling the remaining space in the current container.&lt;/li&gt;
&lt;li&gt;The compiler closes the current container, leaving any unused bits empty.&lt;/li&gt;
&lt;li&gt;It opens a new, empty container (allocation unit).&lt;/li&gt;
&lt;li&gt;The field that didn't fit occupies the beginning of the new container.&lt;/li&gt;
&lt;li&gt;The compiler then recalculates the number of free bits in the new container and repeats these checks for the remaining fields.&lt;/li&gt;
&lt;li&gt;The process is complete once the compiler has assigned all bit fields in the list to their respective containers.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Note.&lt;/strong&gt; The direction in which the compiler fills a container depends on the ABI rules for the target architecture. The order can be from least to most significant bit or vice versa.&lt;/p&gt;



&lt;p&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  sizeof bloat: good vs. bad alignment
&lt;/h3&gt;

&lt;p&gt;Why are we even going into such detail about the compiler's step-by-step algorithm? Bit fields can become a ticking time bomb if one doesn't understand these inner workings. You write code expecting to save memory, but end up with a structure that's several times larger than normal. Declaring bit fields haphazardly can trigger sizeof bloat. The compiler loses its capability to pack data tightly and starts inserting unused bytes.&lt;/p&gt;

&lt;p&gt;Two classic developer mistakes usually lead to such hidden memory leaks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Creating giant fields whose widths exceed the physical capacity of the current memory container.&lt;/li&gt;
&lt;li&gt;Mixing data types indiscriminately, so adjacent fields keep switching between fundamental data types (for example, &lt;code&gt;char&lt;/code&gt;, then &lt;code&gt;int&lt;/code&gt;, and then &lt;code&gt;char&lt;/code&gt; again). This is a critical issue on Windows (Microsoft ABI), where the compiler starts a new allocation unit whenever the type changes, leaving unused padding behind. This limitation doesn't affect GCC and Clang on Linux and macOS: they ignore changes in base types and continuously pack fields, minimizing alignment padding.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To see just how much of a difference this makes, let's compare two scenarios: one that shows how not to do it, and one that shows how to do it right.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example N1. Inefficient layout (poor alignment)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Imagine a structure where we've tried to save memory by mixing different &lt;a href="https://godbolt.org/z/Gfohbh69o" rel="noopener noreferrer"&gt;types&lt;/a&gt;. For this example, let's use MSVC on Windows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;BadPacking&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;  &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The structure fields will be arranged as follows:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqgl56ii28eibl6gs8hks.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqgl56ii28eibl6gs8hks.png" alt="1423_Bitfields/image4.png" width="800" height="445"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The constant switching between types (&lt;code&gt;char&lt;/code&gt; &amp;gt; &lt;code&gt;int&lt;/code&gt; &amp;gt; &lt;code&gt;char&lt;/code&gt;) completely disrupts continuous packing. MSVC treats each type change as a command to close the current allocation unit. It stops filling the byte after &lt;code&gt;a&lt;/code&gt;, leaves the remaining bits as padding, and aligns the address for the next block. It then opens a 4-byte container for the &lt;code&gt;int&lt;/code&gt; &lt;code&gt;b&lt;/code&gt; field, which takes three bits, and immediately closes it to open a container for the &lt;code&gt;char&lt;/code&gt; type. As a result, large gaps of unused memory remain. The compiler also has to follow alignment rules, so it performs final alignment on the entire structure. Then, &lt;code&gt;sizeof(BadPacking)&lt;/code&gt; returns 12 bytes. Clang and GCC, on the other hand, can handle this structure efficiently: they know how to pack these fields as tightly as possible.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example N2. Optimized layout (good alignment)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To fix this, simply follow the golden rule: convert all fields to a single base &lt;a href="https://godbolt.org/z/jzKxvfxKx" rel="noopener noreferrer"&gt;type&lt;/a&gt; and group them by meaning.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;GoodPacking&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
    &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  
    &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's take a look at how the elements are arranged in the structure now:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7agzkzttdcx85u0seivf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7agzkzttdcx85u0seivf.png" alt="1423_Bitfields/image5.png" width="800" height="332"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The compiler now works with uniform and predictable four-byte blocks. The &lt;code&gt;b&lt;/code&gt; field occupies almost the entire first block, while the &lt;code&gt;a&lt;/code&gt; and &lt;code&gt;c&lt;/code&gt; fields require only eight bits combined, fitting perfectly into the second &lt;code&gt;int&lt;/code&gt; block. As a result, &lt;code&gt;sizeof(GoodPacking)&lt;/code&gt; returns just eight bytes (exactly two &lt;code&gt;int&lt;/code&gt; containers). The data is packed as tightly as possible so the processor can access it without any unnecessary overhead. This gives us a compact structure.&lt;/p&gt;

&lt;h3&gt;
  
  
  Hardware padding: reserving space for unused bits
&lt;/h3&gt;

&lt;p&gt;When writing drivers, implementing network protocols, or working with processor registers, you may encounter hardware controllers with gaps in their bit layout. For example, a chip manufacturer may reserve certain bits in a hardware byte for future use, meaning you can't write or read data to or from them.&lt;/p&gt;

&lt;p&gt;To precisely mirror the register's physical layout in code, you can use &lt;a href="https://timsong-cpp.github.io/cppwp/n5050/class.bit#2" rel="noopener noreferrer"&gt;unnamed bit fields with non-zero widths&lt;/a&gt; as placeholders or padding:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;TestController&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;transmit_ready&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
  &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt;                &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
  &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;receive_ready&lt;/span&gt;  &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt;                &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, they still occupy their designated space in memory when the compiler generates the structure. This enables you to map a C++ structure to the microcontroller's physical memory layout with bit-level precision, without shifting any of the meaningful flags.&lt;/p&gt;

&lt;p&gt;Forcing a packing boundary: why use a zero-width bit field?&lt;/p&gt;

&lt;p&gt;In some cases, such as when working with hardware interfaces, it's necessary to prevent the compiler from packing fields into the current allocation unit. For example, you may need to ensure that the next data block starts at a new byte or machine word. To do this, you can use an &lt;a href="https://timsong-cpp.github.io/cppwp/n5050/class.bit#2" rel="noopener noreferrer"&gt;unnamed zero-width bit field&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;Test&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;command&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
  &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt;         &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
  &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;    &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A zero-width bit field acts as an artificial boundary. It tells the compiler that the current memory allocation unit is closed. The next field must start in a new allocation unit and can't use any remaining bits, even if plenty of space remains. One important rule to remember when working with these fields is that you &lt;strong&gt;can't give a zero-width bit field a name&lt;/strong&gt;. It must always remain unnamed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Under the hood: how compilers store bit fields
&lt;/h2&gt;

&lt;p&gt;Now, it's time to take a look under the hood. The internal structure of bit fields in C++ is subject to implementation-defined behavior. The C++ standard abstracts away the physical details, providing only high-level rules and delegating the challenging tasks to the compiler and ABI. To understand how data actually occupies memory, we need to take a closer look at three fundamental factors: bit allocation order, compiler differences across architectures, and binary portability.&lt;/p&gt;

&lt;h3&gt;
  
  
  Bit allocation order
&lt;/h3&gt;

&lt;p&gt;The first and most important factor that determines a structure's physical layout in memory is the order in which the compiler places bits inside an allocated container. Most developers are familiar with byte order, which determines how multibyte values are mapped to memory addresses. A similar concept exists at a lower level, though: the compiler decides which direction to fill individual bits within a particular byte or machine word. The C++ standard deliberately leaves this detail unspecified, so each compiler's implementation determines how it fills each container. In real world, compilers use one of two opposite approaches: packing from the least significant bit to the most significant bit (LSB-first, Little Endian) or from the most significant bit to the least significant bit (MSB-first, Big Endian).&lt;/p&gt;

&lt;p&gt;In the &lt;a href="https://en.wikipedia.org/wiki/Bit_numbering#Least_significant_bit" rel="noopener noreferrer"&gt;&lt;em&gt;LSB-first&lt;/em&gt;&lt;/a&gt; scheme, the compiler fills the allocated container from right to left. In other words, packing begins with the least significant bit, or bit 0. The first bit field declared in the structure occupies the rightmost bits, and each subsequent field sits directly next to it, extending leftward toward bits with greater binary significance. GCC, Clang, and MSVC all use this approach when compiling code for architectures such as x86, x86-64, and ARM.&lt;/p&gt;

&lt;p&gt;The opposite strategy is &lt;a href="https://en.wikipedia.org/wiki/Bit_numbering#Most_significant_bit" rel="noopener noreferrer"&gt;&lt;em&gt;MSB-first (Most Significant Bit-first)&lt;/em&gt;&lt;/a&gt;. In this case, the compiler packs bits from left to right, starting with the highest available bit: for example, the seventh bit in a one-byte container. The first field in the structure occupies the most significant bits on the left side of the container, while subsequent fields follow in sequence toward the least significant bits. This is common in compilers for &lt;a href="https://en.wikipedia.org/wiki/Network_processor" rel="noopener noreferrer"&gt;network processors&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let's see how this works in real code. Take a look at the following &lt;a href="https://godbolt.org/z/MYM1x8rPK" rel="noopener noreferrer"&gt;structure&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;HeaderFlags&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;version&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
  &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;type&lt;/span&gt;    &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
  &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;      &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;/p&gt;
  The full code
  &lt;br&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;cstdint&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;cstring&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;iostream&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;HeaderFlags&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;version&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
  &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;type&lt;/span&gt;    &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
  &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;      &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;result_byte&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;HeaderFlags&lt;/span&gt; &lt;span class="n"&gt;flags&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;flags&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;version&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;flags&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;flags&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;memcpy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;result_byte&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;flags&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;HeaderFlags&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;p&gt;&lt;/p&gt;

&lt;p&gt;We created a &lt;code&gt;HeaderFlags&lt;/code&gt; structure that occupies exactly one byte and assigned three values to its fields. To safely extract the packed byte without violating memory access rules, we used &lt;code&gt;std::memcpy&lt;/code&gt; and copied the result into the &lt;code&gt;result_byte&lt;/code&gt; global variable.&lt;/p&gt;

&lt;p&gt;Now let's see how different compilers handle this code. To avoid wading through unnecessary assembly instructions, we'll enable the &lt;code&gt;-O2&lt;/code&gt; optimization level.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://godbolt.org/z/6G4s9envG" rel="noopener noreferrer"&gt;GCC x86-64&lt;/a&gt; output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;globl&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ios_base_library_init&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="s"&gt;"main"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;mov&lt;/span&gt;     &lt;span class="n"&gt;BYTE&lt;/span&gt; &lt;span class="n"&gt;PTR&lt;/span&gt; &lt;span class="s"&gt;"result_byte"&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;rip&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;111&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;
        &lt;span class="n"&gt;xor&lt;/span&gt;     &lt;span class="n"&gt;eax&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;eax&lt;/span&gt;
        &lt;span class="n"&gt;ret&lt;/span&gt;
&lt;span class="s"&gt;"result_byte"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;zero&lt;/span&gt;   &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;mov&lt;/code&gt; instruction contains the &lt;code&gt;-111&lt;/code&gt; negative value, which is how x86-64 assembly represents one-byte constants. Converting it to the familiar unsigned format gives us &lt;code&gt;256 - 111 = 145&lt;/code&gt;, which is &lt;code&gt;0x89&lt;/code&gt; in hexadecimal or &lt;code&gt;0b1001'0001&lt;/code&gt; in binary. The compiler has eliminated all the intermediate packing instructions and written the final result directly to memory. Since the target cell occupies four bytes, the &lt;code&gt;0x00000089&lt;/code&gt; value appears in memory as the &lt;code&gt;89 00 00 00&lt;/code&gt; byte sequence. The fact that the least significant byte 89 appears at the lowest memory address confirms the LSB-first (Little Endian) layout. &lt;/p&gt;

&lt;p&gt;Switching the compiler to the Big-Endian MIPS architecture, such as mips-linux-gcc 16.1.0, reveals a completely different picture. The assembly output for this platform &lt;a href="https://godbolt.org/z/99hYqr6b4" rel="noopener noreferrer"&gt;looks as follows&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;globl&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ios_base_library_init&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;lui&lt;/span&gt;     &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;hi&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result_byte&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;li&lt;/span&gt;      &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;52&lt;/span&gt;                 &lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="mh"&gt;0x34&lt;/span&gt;
        &lt;span class="n"&gt;sb&lt;/span&gt;      &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;lo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result_byte&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;jr&lt;/span&gt;      &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;31&lt;/span&gt;
        &lt;span class="n"&gt;move&lt;/span&gt;    &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;

&lt;span class="n"&gt;result_byte&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;space&lt;/span&gt;  &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, the &lt;code&gt;li $3, 52&lt;/code&gt; instruction loads the precomputed constant &lt;code&gt;52&lt;/code&gt;, which is &lt;code&gt;0x34&lt;/code&gt; in hexadecimal and &lt;code&gt;0b0011'0100&lt;/code&gt; in binary. The compiler uses the MSB-first strategy, packing bits from left to right: the &lt;code&gt;version&lt;/code&gt; field occupies the most significant bits 7–5, type occupies bits 4–3, and &lt;code&gt;id&lt;/code&gt; lands in the least significant bits 2–0. We can illustrate the bit layout schematically as follows:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwbvw6zyjpiuiwlbczf5q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwbvw6zyjpiuiwlbczf5q.png" alt="1423_Bitfields/image6.png" width="799" height="488"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This example shows how changing the bit endianness can completely change the physical representation of data. Directly transferring raw bytes between systems that use different bit-packing schemes can corrupt the data structure. Understanding this mechanism leads us to the second key factor: the architectural differences between compilers and the role of the ABI.&lt;/p&gt;

&lt;h3&gt;
  
  
  Platform dependence: the anatomy of the MSVC vs. GCC/Clang conflict
&lt;/h3&gt;

&lt;p&gt;We often think that fundamental data types in C++ behave deterministically on the same hardware architecture. However, bit fields have an important caveat: the compiler decides how to arrange them in memory. The in-memory layout of the same structure compiled for an x86-64 processor can differ significantly between Windows and Linux. The physical layout of bit fields follows the rules defined by the ABI. The ABI specifies how the operating system's platform expects the compiler to group, align, and divide data into individual fields.&lt;/p&gt;

&lt;p&gt;Several ABI standards define different approaches to data packing. Here are some of the most widely used ones:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://refspecs.linuxbase.org/elf/gabi41.pdf" rel="noopener noreferrer"&gt;System V ABI&lt;/a&gt; (based on the Itanium C++ ABI) is used by default in GCC and Clang on Linux, macOS, and FreeBSD. Although developers originally designed this standard for Intel Itanium processors, it has become a common foundation for GCC and Clang across various architectures, including &lt;a href="https://www.sco.com/developers/devspecs/abi386-4.pdf" rel="noopener noreferrer"&gt;x86&lt;/a&gt;, &lt;a href="https://refspecs.linuxbase.org/elf/x86_64-abi-0.99.pdf" rel="noopener noreferrer"&gt;x64&lt;/a&gt;, and &lt;a href="https://github.com/ARM-software/abi-aa/blob/main/sysvabi64/sysvabi64.rst" rel="noopener noreferrer"&gt;ARM64&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.riscv.org/reference/abi/v1.0/index.html" rel="noopener noreferrer"&gt;RISC-V ABI&lt;/a&gt; is a specification for the RISC-V open-standard architecture. This standard isn't formally derived from the System V ABI, but it shares many similar data packing and alignment rules. The goal is to pack bit fields in memory as tightly as possible.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://learn.microsoft.com/en-us/cpp/build/x64-software-conventions?view=msvc-170" rel="noopener noreferrer"&gt;Microsoft x64 ABI&lt;/a&gt; is used by default in MSVC on Windows systems running on the x86-64 architecture.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://learn.microsoft.com/en-us/cpp/build/arm64-windows-abi-conventions?view=msvc-170" rel="noopener noreferrer"&gt;Microsoft ARM64 ABI&lt;/a&gt; is the modern Windows standard for ARM64 processors. It's designed with x64 limitations in mind. Its structure alignment rules offer greater flexibility, and its calling convention enables programs to pass data directly through registers, reducing stack usage.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;These documents differ in a single rule.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The rule. Compatibility between different data types&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Developers can declare consecutive bit fields with different fundamental data types within the same structure. This kind of type mixing is one of the main causes of hidden memory bloat, as compilers use very different algorithms to handle boundaries between allocation units with different fundamental types.&lt;/p&gt;

&lt;p&gt;Let's see what happens when these rules conflict. We'll run an experiment using Compiler Explorer and measure the structure's size with the &lt;code&gt;sizeof&lt;/code&gt; operator. Let's write the following structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;PackagingConflict&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;uint8_t&lt;/span&gt;  &lt;span class="n"&gt;mode&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
  &lt;span class="kt"&gt;uint32_t&lt;/span&gt; &lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;/p&gt;
  The full code
  &lt;br&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;iostream&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;cstdint&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;PackagingConflict&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;uint8_t&lt;/span&gt;  &lt;span class="n"&gt;mode&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
    &lt;span class="kt"&gt;uint32_t&lt;/span&gt; &lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;"--- BITFIELD PACKING SIZES ---"&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;"1. PackagingConflict size: "&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PackagingConflict&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
              &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;" byte(s)"&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;    
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;p&gt;&lt;/p&gt;

&lt;p&gt;Look at the outputs from &lt;a href="https://godbolt.org/z/nY8WMGGT7" rel="noopener noreferrer"&gt;Clang&lt;/a&gt; and &lt;a href="https://godbolt.org/z/qrjj17vcE" rel="noopener noreferrer"&gt;MSVC&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;
  The Clang program output
  &lt;br&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="o"&gt;---&lt;/span&gt; &lt;span class="n"&gt;BITFIELD&lt;/span&gt; &lt;span class="n"&gt;PACKING&lt;/span&gt; &lt;span class="n"&gt;SIZES&lt;/span&gt; &lt;span class="o"&gt;---&lt;/span&gt;
&lt;span class="mf"&gt;1.&lt;/span&gt; &lt;span class="n"&gt;PackagingConflict&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt; &lt;span class="n"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;
  The MSVC program output
  &lt;br&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="o"&gt;---&lt;/span&gt; &lt;span class="n"&gt;BITFIELD&lt;/span&gt; &lt;span class="n"&gt;PACKING&lt;/span&gt; &lt;span class="n"&gt;SIZES&lt;/span&gt; &lt;span class="o"&gt;---&lt;/span&gt;
&lt;span class="mf"&gt;1.&lt;/span&gt; &lt;span class="n"&gt;PackagingConflict&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt; &lt;span class="n"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;p&gt;&lt;/p&gt;

&lt;p&gt;Here's a visual layout of the memory components:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvjl57xk8v098twn10w0u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvjl57xk8v098twn10w0u.png" alt="1423_Bitfields/image7.png" width="799" height="446"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Upon analyzing this structure, we can spot a clear difference: Clang packs it into four bytes, while MSVC inflates it to eight. Since the fields use different fundamental data types (&lt;code&gt;uint8_t&lt;/code&gt; and &lt;code&gt;uint32_t&lt;/code&gt;), both compilers initially keep them separate. They allocate one byte for the mode and add three bytes of padding so the type starts at a properly aligned four-byte boundary. Clang then applies an Itanium ABI optimization, trimming the unused part of the second allocation unit to save space. MSVC, on the other hand, strictly follows the Microsoft ABI rule that the structure's total size must be a multiple of its largest fundamental type (&lt;code&gt;uint32_t&lt;/code&gt;, or four bytes). It preserves the full four-byte allocation unit for each block, doubling the structure's final size.&lt;/p&gt;

&lt;p&gt;The real danger is when we move between platforms with different ABIs, the well-defined physical boundaries of data in memory simply disappear. Hidden padding and differences in how compilers handle unused space within allocation units can completely change the internal field layout. This makes bit fields unsuitable for direct byte-by-byte copying, file storage, or binary serialization. If a structure is saved using Clang's four-byte layout and then read using MSVC's eight-byte layout, the program reads from incorrect offsets, resulting in corrupted data.&lt;/p&gt;

&lt;h3&gt;
  
  
  Binary fragility and industry standards
&lt;/h3&gt;

&lt;p&gt;Due to inconsistencies in alignment and bit ordering, structures containing bit fields offer virtually no binary portability. C++ compilers treat bit fields as a black box: you write concise code, but leave the actual memory layout to chance.&lt;/p&gt;

&lt;p&gt;Using bit fields is virtually guaranteed to cause problems in three areas:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Network I/O.&lt;/strong&gt; Sending a structure directly over a socket with a call like &lt;code&gt;send(sock, &amp;amp;packet, sizeof(packet), 0)&lt;/code&gt; is a ticking time bomb. If the server runs Linux (Clang) and the client runs Windows (MSVC), ABI differences can shift bit positions, turning valid flags into a meaningless jumble.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. File I/O (serialization).&lt;/strong&gt; For example, writing bit fields directly to a file byte by byte with &lt;code&gt;fwrite&lt;/code&gt; ties the data to a specific ABI. According to Section &lt;a href="https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2310.pdf#page=95" rel="noopener noreferrer"&gt;6.7.2.1&lt;/a&gt; of the ISO C standard, the order in which compilers lay out bit fields and padding is implementation-defined behavior. Writing such a structure to a file on Linux and then reading it on Windows can cause differences between the Microsoft and System V ABIs to result in the program reading corrupted data from incorrect offsets.&lt;/p&gt;

&lt;p&gt;The C++ object model in C++23 partially addresses the issue of object lifetimes with the &lt;a href="https://en.cppreference.com/cpp/memory/start_lifetime_as" rel="noopener noreferrer"&gt;&lt;code&gt;std::start_lifetime_as&lt;/code&gt;&lt;/a&gt; function. However, this function only validates the creation of an object from raw bytes in memory; it doesn't address differences in the physical layout of fields across platforms. Moreover, copying uninitialized structure padding when writing data to a file technically involves reading indeterminate values, which leads to undefined behavior.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Drivers and hardware (Hardware MMIO).&lt;/strong&gt; A microcontroller's hardware defines the bit layout of its registers, and it never changes. In C, however, the order and alignment of bit fields, as well as the width of memory accesses, depend on the implementation. So, describing a hardware register with bit fields doesn't guarantee that each field will map to the intended bits. Switching compilers, compiler versions, or build flags can shift the fields, causing writes to affect the wrong register bits.&lt;/p&gt;

&lt;p&gt;Developers avoid bit fields entirely for any task that requires a strictly defined data layout, such as network communication, file storage, or hardware registers. Instead, they use fixed-width integer types (&lt;code&gt;uint8_t&lt;/code&gt;, &lt;code&gt;uint16_t&lt;/code&gt;, and &lt;code&gt;uint32_t&lt;/code&gt;) combined with explicit bit shifts (&lt;code&gt;&amp;lt;&amp;lt;, &amp;gt;&amp;gt;&lt;/code&gt;) and bit masks (&lt;code&gt;&amp;amp;, |&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Differences between compiler ABIs make it difficult to use standard bit fields without manual alignment for cross-platform data exchange. A program compiled on Linux using GCC or Clang produces a data structure that a Windows application built with MSVC can't read correctly because the Windows application expects alignment and padding bits in different locations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use cases: where bit fields actually make sense
&lt;/h2&gt;

&lt;p&gt;In C++ development, bit fields serve specific engineering needs rather than abstract memory-saving goals. There are two main scenarios where this feature proves most useful.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Compact metadata for millions of objects.&lt;/strong&gt; Developers often need to store metadata, such as status flags, type IDs, and reference counts, for huge numbers of small elements when designing game engines, custom memory allocators, or databases. Allocating a separate variable for each flag can waste enormous amounts of memory due to compiler-imposed alignment. Bit fields let you pack several independent properties into a single byte, minimizing memory usage.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Optimizing CPU cache usage (Cache Lines).&lt;/strong&gt; Modern processors don't read data from RAM one item at a time. Instead, they fetch large blocks of data called cache lines, typically 64 bytes each. When a data structure becomes too large, each cache line contains fewer useful objects. This forces the processor to repeatedly wait for slow RAM access, resulting in a cache miss. Using bit fields to pack data tightly allows the CPU cache to hold several times more objects. An algorithm can run several times faster when it iterates over objects sequentially in large batches because it retrieves data from the CPU's ultra-fast cache.&lt;/p&gt;

&lt;h2&gt;
  
  
  Modern alternatives to bit fields
&lt;/h2&gt;

&lt;p&gt;Due to portability issues, dependence on platforms, and restrictions on address taking, developers often need to look for alternatives to traditional bit fields. Modern C++ offers three main architectural alternatives, each designed to address a specific use case.&lt;/p&gt;

&lt;h3&gt;
  
  
  The classic approach: manual bit masks and shifts
&lt;/h3&gt;

&lt;p&gt;If you need to have complete control over the physical position of each bit, the classic C-style approach is your best option. Rather than relying on the compiler to automatically pack bits, you select a fixed-width integer type and manually manipulate individual bits using bitwise operators (&lt;code&gt;&amp;amp;,&lt;/code&gt; &lt;code&gt;|&lt;/code&gt;, &lt;code&gt;~&lt;/code&gt;, &lt;code&gt;^&lt;/code&gt;, &lt;code&gt;&amp;lt;&amp;lt;&lt;/code&gt;, and &lt;code&gt;&amp;gt;&amp;gt;&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Take a look at the example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DeviceConfig&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="nl"&gt;public:&lt;/span&gt;
  &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;set_mode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;MODE_MASK&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;mode&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;MODE_MASK&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;get_mode&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;MODE_MASK&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;private&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
  &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;constexpr&lt;/span&gt; &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;ENABLE_CLOCK_MASK&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mh"&gt;0x01&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;constexpr&lt;/span&gt; &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;MODE_MASK&lt;/span&gt;         &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mh"&gt;0x0E&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;constexpr&lt;/span&gt; &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;INTERRUPT_MASK&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mh"&gt;0xF0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;private&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
  &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Yes, this code is more complex, but its binary layout is now completely independent of the compiler and ABI. This makes it an ideal approach for implementing network protocols and writing device drivers. The only thing developers need to keep in mind is the processor's byte order, or endianness. Multi-byte values appear in reverse order on Big Endian architectures compared to Little Endian ones.&lt;/p&gt;

&lt;h3&gt;
  
  
  For maximum safety: the std::bitset container
&lt;/h3&gt;

&lt;p&gt;The built-in &lt;a href="https://timsong-cpp.github.io/cppwp/n5050/bitset" rel="noopener noreferrer"&gt;&lt;code&gt;std::bitset&lt;/code&gt;&lt;/a&gt; class is the best choice if code safety and convenient manipulation of Boolean flags matter more than saving memory in individual structures.&lt;/p&gt;

&lt;p&gt;This container provides a fixed-size array of bits whose size is specified as a template parameter at compile time. It encapsulates all bitwise operations, providing developers with a high-level, type-safe interface.&lt;/p&gt;

&lt;p&gt;Look at the following &lt;a href="https://godbolt.org/z/vh47czvWT" rel="noopener noreferrer"&gt;example&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;bitset&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;iostream&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="k"&gt;enum&lt;/span&gt; &lt;span class="n"&gt;Permission&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;Read&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;Write&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;Execute&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;Admin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;MaxPermissions&lt;/span&gt; 
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;ManagePermissions&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;bitset&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;MaxPermissions&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;user_rights&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;user_rights&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Permission&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Read&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;    
  &lt;span class="n"&gt;user_rights&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Permission&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;   
  &lt;span class="n"&gt;user_rights&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;flip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Permission&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Execute&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_rights&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Permission&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;"The user can write files.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;"Current rights mask: "&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;user_rights&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;ManagePermissions&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The main advantage of &lt;code&gt;std::bitset&lt;/code&gt; is that it protects against human error. If you pass an invalid index to one of its member functions—&lt;a href="https://timsong-cpp.github.io/cppwp/n5050/bitset#lib:set_(member),bitset_" rel="noopener noreferrer"&gt;&lt;code&gt;std::bitset&amp;lt;N&amp;gt;::set&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://timsong-cpp.github.io/cppwp/n5050/bitset#lib:reset,bitset_" rel="noopener noreferrer"&gt;&lt;code&gt;std::bitset&amp;lt;N&amp;gt;::reset&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://timsong-cpp.github.io/cppwp/n5050/bitset#lib:flip,bitset_" rel="noopener noreferrer"&gt;&lt;code&gt;std::bitset&amp;lt;N&amp;gt;::flip&lt;/code&gt;&lt;/a&gt;, or &lt;a href="https://timsong-cpp.github.io/cppwp/n5050/bitset#lib:test,bitset" rel="noopener noreferrer"&gt;&lt;code&gt;std::bitset&amp;lt;N&amp;gt;::test&lt;/code&gt;&lt;/a&gt;—such as index 15 for a four-bit bitset, the function throws a &lt;code&gt;std::out_of_range&lt;/code&gt; exception. With manual bit masks, the same mistake could lead to unpredictable reads from unrelated memory or corrupt adjacent data.&lt;/p&gt;

&lt;p&gt;There's a caveat, though: &lt;code&gt;std::bitset&lt;/code&gt; typically rounds its internal storage up to the processor's native word size, so it can't save memory at the individual-bit level.&lt;/p&gt;

&lt;h3&gt;
  
  
  For large numbers of flags: the std::vector specialization
&lt;/h3&gt;

&lt;p&gt;Using a regular &lt;code&gt;bool&lt;/code&gt; array to manage a huge, dynamically sized array of Boolean flags wastes a lot of memory because each element occupies an entire byte. To fix this issue, the standard library provides a specialized version of &lt;code&gt;std::vector&lt;/code&gt;: &lt;a href="https://timsong-cpp.github.io/cppwp/n5050/vector.bool" rel="noopener noreferrer"&gt;&lt;code&gt;std::vector&amp;lt;bool&amp;gt;&lt;/code&gt;.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This container works differently from ordinary vectors. The standard library optimizes it for memory efficiency by packing &lt;code&gt;bool&lt;/code&gt; elements bit by bit into larger integer types (machine words). Usually, it can store 32 or 64 Boolean values in a single memory block.&lt;/p&gt;

&lt;p&gt;The following is an example of using a large dynamic array:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;vector&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;feature_flags&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;process_features&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;feature_flags&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;feature_flags&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// code&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Despite its convenience, &lt;code&gt;std::vector&amp;lt;bool&amp;gt;&lt;/code&gt; is one of the most controversial features of the C++ standard. Developers should exercise caution when using it. Because it packs bits so tightly, its elements aren't actual &lt;code&gt;bool&lt;/code&gt; objects in memory. As a result, you can't take the address of an element directly (the &lt;code&gt;bool *ptr = &amp;amp;feature_flags[0];&lt;/code&gt; code won't compile) or pass an element by reference or pointer. The &lt;code&gt;[]&lt;/code&gt; operator returns a special temporary proxy object that mimics reference behavior rather than a reference. This is the trade-off for compressing data in dynamically allocated memory.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Well, that's all I have for you today. What can I say? Bit fields in C++ perfectly embody the language's philosophy. They give you complete freedom to cut out exactly one bit, then leave you alone to navigate the hidden landmines buried in compilers and system ABIs. Now that you've looked under the hood and seen how this intricate memory optimization coexists with platform-dependent chaos, there's no room for illusions. Bit fields are a powerful tool for optimizing cache lines and working with hardware. However, they can also create hidden issues when you try to send a structure over the network. Now you know the rules of this low-level game. How you wield this power over memory in your own projects is up to you.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://pvs-studio.com/en/pvs-studio/try-free/?utm_source=website&amp;amp;utm_medium=devto&amp;amp;utm_campaign=article&amp;amp;utm_content=1423" rel="noopener noreferrer"&gt;Get a free one-month trial&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>cpp</category>
      <category>programming</category>
    </item>
    <item>
      <title>Game++. Part 2.2: Types of optimization</title>
      <dc:creator>Unicorn Developer</dc:creator>
      <pubDate>Fri, 23 Oct 2026 12:18:36 +0000</pubDate>
      <link>https://dev.to/pvsdev/game-part-22-types-of-optimization-4aal</link>
      <guid>https://dev.to/pvsdev/game-part-22-types-of-optimization-4aal</guid>
      <description>&lt;p&gt;This book offers insights into C++, including the algorithms and practices used in game development, and explores the language's strengths and weaknesses, its established workflows, and hands-on solutions, because C++ still dominates the game industry today thanks to its combination of high performance, flexibility, and deep low-level control.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F04qurrit37jls97ecno1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F04qurrit37jls97ecno1.png" alt="1422_pt_7/image1.png" width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Hotspots and bottlenecks
&lt;/h2&gt;

&lt;p&gt;The key task in optimization is to find hotspots, which are code fragments with a high computational load, and bottlenecks, which are components that limit overall throughput, and these problems usually fall into three categories, namely abstractions, smoothness, and hardware limitations.&lt;/p&gt;

&lt;p&gt;Abstractions, or more precisely premature abstractions, add unnecessary layers to the engine architecture and make the whole system more complex than it needs to be, and the usual suspects here are multiple inheritance, one-size-fits-all solutions to game development problems, and heavy use of design patterns in places where simple procedural code would do the job just fine.&lt;/p&gt;

&lt;p&gt;The same category includes writing beautiful code instead of fast code, when performance-critical sections get buried under unnecessary layers of ceremony and checks, which is exactly what the KISS principle warns us about.&lt;/p&gt;

&lt;p&gt;Most developers agree that smoothness matters more than peak performance, and the things that work against it are well known, because sporadic memory allocations on the main thread make the frame rate uneven, algorithms with unpredictable complexity make frame times inconsistent, and blocking resource loads cause stuttering. A stable 30 FPS beats a frame rate that jumps between 60 and 20, because players feel those jumps immediately, which is why a consistent frame rate is such an easy-to-understand and measurable indicator of quality.&lt;/p&gt;

&lt;p&gt;Hardware limitations are best treated as creative constraints, because brute-forcing a platform's physical limits instead of applying smart optimizations only adds complexity without any real payoff. Raising the polygon count without a proper level-of-detail system will leave the player with low FPS, and the same goes for complex shaders that ignore fill-rate limits, memory-hungry data structures that don't account for the cache hierarchy, and so on.&lt;/p&gt;

&lt;p&gt;A modern CPU-GPU architecture is a complex data-processing pipeline with many parallel execution units, and in this "digital hell" data moves through a hierarchy of caches, travels between the CPU and GPU over the bus, and gets synchronized across threads with memory barriers and atomic operations, so the system almost never does exactly what you wrote in the code.&lt;/p&gt;

&lt;p&gt;You can get solid and stable performance by balancing the workload across all of these components, and even then you may not be able to push the CPU beyond 70 to 80%, but you can make much better use of the GPU, memory bandwidth, and caches. The real challenge is finding a delicate balance right at the edge of what's possible for every component at once, and if you get it wrong, resource contention follows, one component becomes the critical link, and the rest of the system suffers from pipeline stalls, context-switching overhead, and reduced throughput.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hotspots
&lt;/h2&gt;

&lt;p&gt;In software systems, hotspots are localized sections of code with unusually high resource consumption, whether that's CPU time, memory, or disk I/O, and they're characterized by a disproportionately high execution frequency, heavy CPU utilization, high memory pressure, or significant system call overhead.&lt;/p&gt;

&lt;p&gt;In the context of code optimization, the Pareto principle, also known as the 80/20 rule, means that 20% of the source code accounts for 80% of a program's total execution time, which makes hunting down hotspots a highly effective strategy. Searching iteratively helps you find the code blocks that consume the most resources so you can target them and cool them down, but once one issue is fixed, the workload shifts and previously minor sections turn into new hotspots that need attention. This process goes on until the results are acceptable or the time allocated for the task runs out, and it's worth remembering that an engineer's time is a finite resource too, because the more time a developer spends polishing one part of the code, the less time they have for everything else.&lt;/p&gt;

&lt;p&gt;Modern profilers provide detailed analysis down to the level of individual CPU instructions, which makes it possible to identify temporal hotspots, code with a high number of cache misses, heavy I/O operations, and resource-lock contention in multithreaded applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bottlenecks
&lt;/h2&gt;

&lt;p&gt;Imagine a dish being prepared in a café. The chef can't make the whole thing at once, so they hand the side dish off to an assistant while working on the main part themselves, and then the two parts come together and a waiter takes the finished plate to the customer. How long will the whole process take? Suppose the chef finishes first, but the assistant simply can't work any faster, and now the assistant is the bottleneck that slows down the entire system.&lt;/p&gt;

&lt;p&gt;Games work exactly the same way, because there's always a "slow assistant" somewhere, whether it's the CPU, the GPU, memory, or something in the code that holds everything else back, and the developer's job is to find that weak link and bring its performance in line with the rest. Optimization almost always involves trade-offs, and in 99% of cases there's no silver bullet that will fix the problem right away.&lt;/p&gt;

&lt;p&gt;The first and most common trade-off is between performance and memory, since sometimes it's more efficient to store extra data than to recalculate it from scratch. This is called &lt;strong&gt;memoization&lt;/strong&gt; or &lt;strong&gt;caching&lt;/strong&gt;, and the idea is that you calculate something once, store the result, and then simply pull it from memory whenever you need it, which costs more memory but gets you the result faster.&lt;/p&gt;

&lt;p&gt;The second trade-off is between accuracy and speed. Sometimes you can cut corners and speed up a system by simplifying a data type or using a less precise algorithm, and shaders are a good example, because they provide both &lt;code&gt;log&lt;/code&gt; and &lt;code&gt;logp&lt;/code&gt;, where the former is more accurate but slower and the latter is faster but less precise. In the final image, players are unlikely to notice that a neighboring polygon has shifted by a quarter of a pixel, but the game may run noticeably faster, and the same principle applies to almost any data model, pathfinding system, or game AI. The key question is how much precision you're willing to give up, or, in more formal terms, how much you can shift resources from lower-priority computations to higher-priority ones.&lt;/p&gt;

&lt;p&gt;The third classic trade-off is simplicity versus speed, and this one has more to do with people and the team than with hardware. A classic example is a young, talented developer who has just discovered design patterns and responds by building five levels of nested caching in an attempt to optimize the texture-loading system.&lt;/p&gt;

&lt;p&gt;Sure, they'll get that system built, and it may even run faster thanks to intrusive pointers, custom allocator pools, and a lock-free hash table, but the result is predictable, because nobody, not even the author a month or two later, can understand, debug, or modify that code without risking breaking something. Other developers on the team start avoiding those files, they groan every time they have to touch the system, and code reviews keep getting comments like "What the hell is this? Can we just rewrite it in plain C++?"&lt;/p&gt;

&lt;p&gt;An experienced developer knows that real performance gains don't come from showing off their knowledge of algorithms, but from understanding the trade-off between how maintainable the code is and how much the optimization actually pays off.&lt;/p&gt;

&lt;p&gt;Yes, you can squeeze out another 5% of performance with custom memory pools, but that will take two weeks to implement and another month to debug all the weird edge cases, so it might be smarter to use a simple linear allocator and trade some memory for time.&lt;/p&gt;

&lt;p&gt;Mature optimization means fixing the truly critical bottlenecks with clean, well-documented solutions that you can easily switch off with conditional compilation if something goes wrong. In the real world, shipping the game matters more than cool algorithms, and having code the team can maintain matters more than having code that looks impressive in a conference talk.&lt;/p&gt;

&lt;h2&gt;
  
  
  Myths and misconceptions
&lt;/h2&gt;

&lt;p&gt;Software optimization is inherently endless, because there will always be something left to improve, but it's important to understand that past a certain point you start hitting diminishing returns, and every additional effort delivers a smaller and less noticeable performance gain.&lt;/p&gt;

&lt;p&gt;On top of that, developers often spend time chasing dead ends that provide no real benefit (but make for great slides and conference talks) and only make the system harder to maintain. The key skill here is knowing when to stop and ask whether further improvements will actually add value or turn into a witch hunt.&lt;/p&gt;

&lt;p&gt;One of the most common mistakes is making decisions based on assumptions. You can't just "guess" what's slowing the system down, because those guesses are usually wrong, and the only reliable approach is to measure and analyze, then analyze and measure again, until guesses and gut feelings turn into well-founded engineering decisions.&lt;/p&gt;

&lt;p&gt;Optimization doesn't start after the code is written, and in fact 80% of performance problems can be eliminated at the architecture design stage, because proper decomposition, a clear object hierarchy, and well-thought-out dependency management help you avoid bottlenecks in the first place. Despite the overhead that comes with languages like C# and Java, a well-structured system often outperforms code written in pure C++ that ignores architectural constraints.&lt;/p&gt;

&lt;p&gt;When it comes to optimization, it's important to focus on worst-case scenarios rather than average ones. Most developers test their games and applications on powerful workstations, which often gives them a distorted picture, and on weaker hardware the bottlenecks can be completely different, with memory bandwidth or CPU power becoming the limiting factor instead of the GPU.&lt;/p&gt;

&lt;p&gt;To analyze performance properly, developers need to deliberately test on configurations with minimal or weak hardware specs, because those machines are much closer to what a good portion of your players actually experience. Players can tell the difference between 55 and 60 FPS, but they rarely complain about it, while a drop to 20 FPS feels like serious lag even if it only happens once in a while, and that's why consistent frame times often matter more than a high average frame rate.&lt;/p&gt;

&lt;p&gt;Debug and release builds give fundamentally different results (Pic. 3.1). In debug mode, compiler optimizations are turned off and extra checks are turned on, which can slow the code down several times over, and not evenly. For valid performance profiling, work only with release builds and enable debug symbols or disable optimization for specific sections when you need to, because this lets you strike a balance between traceability and accurate measurements while still giving you a realistic picture of performance.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fovqor2327a7y6h3tnf8y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fovqor2327a7y6h3tnf8y.png" alt="1422_pt_7/image2.png" width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Picture 3. 1&lt;/p&gt;

&lt;p&gt;That said, debug builds are useful in the early stages of testing, when they can reveal excessive CPU usage or inefficient algorithms before those problems become critical.&lt;/p&gt;

&lt;p&gt;Finally, the key requirement for any benchmark is control over external variables, since poorly designed tests can create the illusion of optimization. For example, the first measurement might be taken in fullscreen mode while the second runs in windowed mode, at a different refresh rate, or at a different resolution, and the frame rate goes up because the environment changed rather than the code, which makes the whole comparison meaningless. To avoid mistakes like this, keep every environment parameter fixed and change only one thing between runs, namely the piece of code you're optimizing. The best practice is to automate your benchmarks, which removes human error and gives you reproducible results.&lt;/p&gt;

&lt;p&gt;Many people think optimization time should be added to sprints once the game is nearly finished, or, even worse, only when performance problems show up. But ignoring optimization in the early stages of development means risking increasingly tangled processes and unpredictable performance problems at the worst possible moment.&lt;/p&gt;

&lt;p&gt;Another myth is that reactive optimization works well enough on its own. Yes, hundreds of games ship after being optimized at the last minute, but this approach usually ends with cutting features or simplifying mechanics to make up for low FPS. Reactive optimization creates a false sense of control, because fixing problems late in development takes far more time and effort than taking a systematic approach throughout the whole project.&lt;/p&gt;

&lt;p&gt;The next myth is that optimization needs large, dedicated blocks of time, when in reality it's much more effective to work it in gradually. With practices like performance budgets, you can set limits for FPS, CPU, and GPU usage up front and organize the team's work around those numbers, and continuous monitoring with incremental code adjustments produces better results than occasional optimization pushes in the final weeks of development.&lt;/p&gt;

&lt;p&gt;There's also a persistent belief that every optimization is justified. In reality, there are plenty of areas where programmers can sink time without seeing any obvious benefit, so only optimize what actually affects performance and weigh the potential payoff against the time the changes will take. This approach keeps you from wasting effort and keeps the focus on the bottlenecks that are really slowing the game down.&lt;/p&gt;

&lt;p&gt;Finally, there's a misconception that performance is a single metric, when a game that "feels slow" can mean any combination of low FPS, longer response times, high CPU and GPU load, and frame rate drops. To optimize even one of these metrics effectively, developers first need to understand which ones are critical for their particular project, how they relate to each other, and what's actually holding the game back.&lt;/p&gt;

&lt;p&gt;A systematic approach like this is the only way to avoid the common misconceptions about optimization. Will anyone actually approve such changes, though? Most likely not, because it's extremely unlikely that the project architect, tech lead, or CTO will sign off on real architectural changes, and that's not really the programmer's call to make anyway, so pushing for it tends to step on the architect's toes. Besides, changing an existing, working, well-tested system can break the systems around it, and there's no way to predict when the error will surface, only that it inevitably will. That's exactly why a developer who just joined the team can't rewrite half the engine "the right way," and what's left for them is code-level and algorithmic tweaks, which can still squeeze out a performance improvement of at least 10%.&lt;/p&gt;

&lt;p&gt;This brings us to the reality that game development forces us to balance our "ideal" technical solutions against the practical constraints of the project. Even a programmer who sees through every optimization myth often has to work within an existing architecture they can't change and settle for local improvements at the algorithm and code level, but this approach can still deliver tangible results, such as the 10 to 15% performance gains that can make all the difference for a successful release.&lt;/p&gt;

&lt;p&gt;Knowing where your influence ends matters, and so does choosing your battles wisely. Optimization was never just a technical skill, because it's also a team sport where every change needs to be justified, measured, and agreed upon, and in the end the best optimization is the one players actually notice, not the one that gets you a few nods in a technical chat.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tools
&lt;/h2&gt;

&lt;p&gt;Any work aimed at improving performance is wasted if you can't see what's actually happening in your code. It's like trying to repair a watch blindfolded or tune a musical instrument with your ears plugged, because you can turn the screws and pluck the strings all you want, but the result will be purely random.&lt;/p&gt;

&lt;p&gt;In everyday life, we get immediate feedback, so if you trip, you fall, if you take a wrong turn, you may end up at a dead end, and if you add too much salt, you ruin the dish. These signals help us correct course right away and remember not to make the same mistake twice. In programming, however, things work differently, because code can execute millions of times per second, process gigabytes of data, and interact with dozens of system components, while all we see is the end result, say, an FPS counter that refuses to go above 50.&lt;/p&gt;

&lt;p&gt;Modern software, and games in particular, can run to hundreds of thousands of lines of code stacked on top of complex operating systems, graphics drivers, and various libraries that add even more code. Without specialized analysis tools, all you can really do is guess whether the CPU can't keep up, whether the bottleneck is loading textures from disk, or whether memory is leaking somewhere. Profilers, performance monitors, and debuggers can mislead you too, but you can't do without them, because they show which functions take the longest to execute, how much memory each part of the program uses, how often the application hits the disk, and where the CPU sits idle waiting for data. Without this information you're flying blind, and with it the solution often becomes obvious, although measuring and analyzing performance correctly is its own kind of science that sometimes borders on alchemy.&lt;/p&gt;

&lt;p&gt;Any tool that measures a program's performance will inevitably affect that performance. Some tools are light enough on their feet that they barely slow the program down, and those are called &lt;strong&gt;non-intrusive&lt;/strong&gt;, while others can seriously drag down an application's performance, and those are called &lt;strong&gt;intrusive&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;How much interference you get depends on how much data you need and how often you need it. A simple FPS counter has virtually no impact on the game, while a detailed analyzer that logs every function call and its execution time can slow things down considerably. Some tools, such as Valgrind, go even further and run the entire program inside a virtual machine to collect highly detailed information about every operation, and you can guess what that does to performance, since the program can easily run ten times slower than usual or worse.&lt;/p&gt;

&lt;p&gt;There are several ways to measure performance, and sampling profilers are the gentlest and simplest of them. They periodically take a snapshot of the program to see which code is running at that moment, and by collecting a series of these snapshots, developers can build a statistical picture of what the program spends most of its time doing.&lt;/p&gt;

&lt;p&gt;A more intrusive approach relies on interception tools that sit between the program and external resources, so PIX, for example, intercepts every call the program makes to the GPU through the DirectX API, while network analyzers peek at all network traffic.&lt;/p&gt;

&lt;p&gt;Getting even more detail means adding special commands and profiling markers to the code to collect data, and this process is called instrumentation.&lt;/p&gt;

&lt;p&gt;Choosing the right tool depends on your specific goals and on how much performance you're willing to sacrifice for a more detailed analysis. The one rule that really matters is that the tool shouldn't distort the measurements more than the problem you're hunting for, since there's little point in optimizing a function that accounts for only 1% of execution time if the profiler itself slows the program down by 50%. That's why all three types of tools are often used, each in its own circumstances.&lt;/p&gt;

&lt;h2&gt;
  
  
  Theory and terminology
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Profilers&lt;/strong&gt; is an umbrella term for the performance analysis tools used across most of game and software development, and a profiler's main job is to capture how the workload breaks down during execution in as much detail as the developer allows.&lt;/p&gt;

&lt;p&gt;The classic use case is measuring CPU time, but modern profilers can track much more, including cache misses, memory allocations, disk access, thread usage, and synchronization. Depending on the level of instrumentation, they can give you either an aggregated view of the workload that shows which modules or systems put the most load on the CPU and where, or a per-frame or per-interval snapshot with the call stack and the exact distribution of work across individual instructions.&lt;/p&gt;

&lt;p&gt;Profilers fall into two categories, general-purpose and specialized. General-purpose profilers are usually the ones built into an IDE or a platform SDK, such as the Visual Studio Profiler, and they give you a broad sense of where performance is leaking. Specialized profilers are low-level tools, such as Sony Razor, Intel VTune, PIX, or Tracy, that collect data from CPU performance counters and OS events and let you analyze code behavior with much greater precision, and only these low-level tools let developers evaluate how specific algorithmic steps or memory access patterns affect the overall performance of a piece of code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Total time&lt;/strong&gt; shows the cumulative execution time of a function, including all the nested calls it makes to other functions. In theory, it helps identify hotspots in an application and gives a complete picture of how much time the program spends in a particular section of code along with all its dependencies, but in practice it can give a distorted view of performance.&lt;/p&gt;

&lt;p&gt;As part of its optimizations, the compiler may inline functions directly into the code of the calling function, which blurs the execution time of the parent function even though the inlined code is what actually does the work. This metric also doesn't account for indirect costs, such as cache pollution or data eviction, which can seriously undermine how reliable the measurement is.&lt;/p&gt;

&lt;p&gt;For example, when you analyze functions whose performance depends heavily on their input data, such as sorting an almost-sorted array versus an unsorted one, the profiler will report an average value, which can hide real performance problems that only show up in certain use cases.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Self time&lt;/strong&gt; measures only the time spent executing instructions inside the function itself, excluding the time spent in all the functions it calls. This helps identify the code blocks that actually do the expensive work rather than just handing it off to other functions, and functions with heavy algorithms, loops, or number crunching typically show high self time.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;ObjectUpdate()&lt;/code&gt; function may have a high total time because it calls all the other subsystems responsible for updating the game state, but a low self time because it doesn't do much work on its own, while a collision-physics function may show significant self time, which tells you that this particular section needs optimization. The problems here are much the same as with the previous metric, because self time can't reflect a function's actual impact on the overall performance of the system. A function may have a low self time while triggering many expensive operations through other functions, which creates a false impression of efficiency. On top of that, this metric ignores function call overhead, so if a function makes thousands of small calls, the cost of creating stack frames, passing parameters, and returning values can be significant, or even close to the actual execution time, and still stay invisible in the self-time numbers.&lt;/p&gt;

&lt;p&gt;Another issue is "aggressive optimization," which is especially common with Clang-based compilers that inline small functions and partially embed their code at the call site. As a result, self-time measurements get distorted, because code that belongs to a different function is counted as self time for the caller (Pic. 3.2).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fy1pbly8wx5as494pc6lr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fy1pbly8wx5as494pc6lr.png" alt="1422_pt_7/image3.png" width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Picture 3. 2&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;Calls&lt;/strong&gt; metric shows how often a particular piece of code runs during a profiling session, which helps reveal how different functions are actually used in the application. Even if their individual execution times are short, functions with a high call count are good candidates for optimization, because the cumulative overhead of all those calls can be significant.&lt;/p&gt;

&lt;p&gt;Analyzing call counts is one of the first steps in finding inefficient algorithms or unnecessary computations (with one caveat, which is covered in the note below). A function that gets called thousands of times per frame may need a whole range of optimization techniques, and a high call count can also point to recursion, resource leaks, or other architectural problems in the application (Pic. 3.3).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbenh4kchc00j2rzy4g5u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbenh4kchc00j2rzy4g5u.png" alt="1422_pt_7/image4.png" width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Picture 3.3&lt;/p&gt;

&lt;p&gt;Overall, this is a fairly useful metric, but the call count alone doesn't show how those calls are distributed over time. A function may be called 100,000 times in a session, but if all those calls happen while a level is loading, they have no impact on gameplay performance, and in that case the profiler will show a high call count without telling you that the function sits idle while frames are being rendered. The call count can also be misleading when it comes to spotting real architectural problems, because a high number of calls may simply be the result of a well-designed architecture with lots of small, specialized functions rather than a sign of inefficiency.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Modern compilers have gotten very good at inlining, so focusing only on call counts can lead to premature or incorrect conclusions\.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Total waste time&lt;/strong&gt; tracks how long a function spends with its thread blocked while waiting for resources to become available, I/O operations to complete, or system events to occur (Fig. 3.4). This time doesn't reflect active execution of the function, but rather delays caused by external factors, and a high waste time can point to indirect performance problems that affect the function's overall execution time. This metric is usually analyzed when refactoring code or reducing dependencies between functions.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fq6bvymm65m6c9wvxgkpm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fq6bvymm65m6c9wvxgkpm.png" alt="1422_pt_7/image5.png" width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Picture 3.4&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Author: Sergei Kushnirenko&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Sergei has over 20-year experience in coding and game development. He graduated from ITMO National Research University and began his career developing software for naval simulators, navigation systems, and network solutions. For the past fifteen years, Sergei has specialized in game development: at Electronic Arts, he worked on optimizing The Sims and SimCity BuildIt, and at Gaijin Entertainment, Sergei headed up the porting of games to the Nintendo Switch and Apple TV platforms. Sergei actively participates in open-source projects, including the ImSpinner library and the Pharaoh (1999) game restoration project.&lt;/p&gt;

&lt;h2&gt;
  
  
  All parts
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://pvs-studio.com/en/blog/posts/1361/" rel="noopener noreferrer"&gt;Game++. Part 1.1: C++, game engines, and architectures&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://pvs-studio.com/en/blog/posts/1375/" rel="noopener noreferrer"&gt;Game++. Part 1.2: C++, game engines, and architectures&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://pvs-studio.com/en/blog/posts/1384/" rel="noopener noreferrer"&gt;Game++. Part 1.3: C++, game engines, and architectures&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://pvs-studio.com/en/blog/posts/1390/" rel="noopener noreferrer"&gt;Game++. Part 1.4: C++, game engines, and architectures&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://pvs-studio.com/en/blog/posts/1397/" rel="noopener noreferrer"&gt;Game++. Part 2.1: Types of optimization&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>cpp</category>
      <category>gamedev</category>
      <category>programming</category>
    </item>
    <item>
      <title>What's new in C# 15: Overview</title>
      <dc:creator>Unicorn Developer</dc:creator>
      <pubDate>Tue, 20 Oct 2026 14:12:02 +0000</pubDate>
      <link>https://dev.to/pvsdev/whats-new-in-c-15-overview-3md3</link>
      <guid>https://dev.to/pvsdev/whats-new-in-c-15-overview-3md3</guid>
      <description>&lt;p&gt;A new version of C# is coming soon, so we're continuing our annual tradition of reviewing its new features. The Microsoft team has prepared several highly anticipated and exciting changes for this release. Let's take a look at them. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7h6yhwy2pluk2yy3spls.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7h6yhwy2pluk2yy3spls.png" alt=" " width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Union types
&lt;/h2&gt;

&lt;p&gt;We'll start with the most straightforward change, &lt;code&gt;union&lt;/code&gt; types. They enable developers to combine types without relying on inheritance or interfaces where it's unnecessary or unavailable. A &lt;code&gt;union&lt;/code&gt; is a structure that contains the complete set of supported types.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;union&lt;/span&gt; &lt;span class="nf"&gt;TestUnion&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Version&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;IEnumerable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the code above, &lt;code&gt;union&lt;/code&gt; is the keyword, while &lt;code&gt;int&lt;/code&gt;, &lt;code&gt;Version&lt;/code&gt;, and &lt;code&gt;IEnumerable&amp;lt;string&amp;gt;&lt;/code&gt; are the set of supported types.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;union&lt;/code&gt; types come in handy when traditional inheritance isn't an option, as it requires the types to have something in common. However, there may be cases where inheritance is impossible or makes little architectural sense. We might need to handle a specific set of types, including primitives. Normally, we'd have to specify a variable of the &lt;code&gt;object&lt;/code&gt; type as input and then cast it to the required types within the method, including logic for handling anything unsupported. That's error-prone. Using &lt;code&gt;union&lt;/code&gt; in this situation would solve these problems, making the code safer and easier to read.&lt;/p&gt;

&lt;p&gt;Given the nature of the new structure, when we use &lt;code&gt;union&lt;/code&gt;, the compiler already knows the complete list of types it can contain. So, the &lt;code&gt;default&lt;/code&gt; branch is no longer necessary. The change protects us from a &lt;code&gt;switch&lt;/code&gt; that misses some types while new subclasses keep falling into the &lt;code&gt;default&lt;/code&gt; section, which can cause unpredictable program behavior.&lt;/p&gt;

&lt;p&gt;Let's look at a more specific example. Before this update, we'd have had to write something like this to define a method for handling API responses:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;abstract&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="n"&gt;ApiResult&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="nf"&gt;ErrorData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="n"&gt;Success&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ApiResult&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="n"&gt;ValidationError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ErrorData&lt;/span&gt; &lt;span class="n"&gt;Data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ApiResult&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;Process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ApiResult&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="k"&gt;switch&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Success&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;ValidationError&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"Unknown result"&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;ApiResult&lt;/code&gt; abstract class, from which specific responses inherit, is declared. So, if a new subclass appears and the developer fails to handle it, executions falls into the &lt;code&gt;default&lt;/code&gt; branch. With a &lt;code&gt;union&lt;/code&gt;, it works differently:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="nf"&gt;ErrorData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="nf"&gt;Success&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="nf"&gt;ValidationError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ErrorData&lt;/span&gt; &lt;span class="n"&gt;Data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;union&lt;/span&gt; &lt;span class="nf"&gt;ApiResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Success&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ValidationError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt; 
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="n"&gt;GetData&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt; &lt;span class="k"&gt;switch&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;Success&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="n"&gt;ValidationError&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Message&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, there's no need for a parent class just to group the types together. The behavior is also more predictable because the compiler knows at compile time exactly which types &lt;code&gt;union&lt;/code&gt; can contain. So, if a &lt;code&gt;switch&lt;/code&gt; doesn't handle every type in the union, the compiler issues a warning.&lt;/p&gt;

&lt;p&gt;Moreover, the &lt;code&gt;union&lt;/code&gt; gives developers an easier way to express patterns such as monads. It also enables implementing custom methods and properties within &lt;code&gt;union&lt;/code&gt;, so working with all its types doesn't require writing &lt;code&gt;switch&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Closed hierarchies
&lt;/h2&gt;

&lt;p&gt;This change is somewhat related to &lt;code&gt;union&lt;/code&gt; in that it also lets the compiler know exactly how many types it'll work with. It does so by preventing inheritance from a class outside the assembly where it was declared. This behavior resembles a mix of &lt;code&gt;internal&lt;/code&gt; and &lt;code&gt;sealed&lt;/code&gt;: it takes the scope from &lt;code&gt;internal&lt;/code&gt; and the restriction on inheritance from &lt;code&gt;sealed&lt;/code&gt;. This can be useful, for example, in libraries where we want to restrict inheritance from certain classes without blocking it within our own assembly. Here's an example declaration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;closed&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="n"&gt;ClosedRecordClass&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;closed&lt;/code&gt; keyword marks the class as closed to inheritance. As a result, attempting to inherit from such a class in another assembly causes a compilation error. Note that, like &lt;code&gt;union&lt;/code&gt;, a closed hierarchy supports an exhaustive &lt;code&gt;switch&lt;/code&gt;, which enables omitting the &lt;code&gt;default&lt;/code&gt; branch. &lt;/p&gt;

&lt;p&gt;A few important details are worth keeping in mind. Firstly, a class marked as &lt;code&gt;closed&lt;/code&gt; is always abstract. This also helps enable an exhaustive &lt;code&gt;switch&lt;/code&gt;. Secondly, descendants don't automatically become closed. If we need to hide them from other assemblies, we can mark them with the &lt;code&gt;internal&lt;/code&gt; access modifier. Thirdly, only classes (&lt;code&gt;class&lt;/code&gt; and &lt;code&gt;record class&lt;/code&gt;) can be closed to inheritance from another assembly. Structs don't support inheritance, while interfaces are specifically designed to be inherited from. So, adding the keyword to a struct or an interface will result in a compilation error. &lt;/p&gt;

&lt;h2&gt;
  
  
  Labeled break and continue
&lt;/h2&gt;

&lt;p&gt;A small but quite important addition: most of us have probably run into situations where we needed to interrupt the execution of an external structure or skip to its next iteration. The classic approach would have looked something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;enum&lt;/span&gt; &lt;span class="n"&gt;WorkItemType&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;Process&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;StopAll&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;WorkItem&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// ....&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;WorkItemType&lt;/span&gt; &lt;span class="n"&gt;Type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;OldLabeledBreak&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;PerformAction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IEnumerable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;WorkItem&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;workList&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;stopProcessing&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="n"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;workList&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// #1&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// #2&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;WorkItemType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Process&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
          &lt;span class="c1"&gt;// ....&lt;/span&gt;
          &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// break #2&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;WorkItemType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StopAll&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
          &lt;span class="n"&gt;stopProcessing&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
          &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// break #2&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stopProcessing&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// break #1&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="c1"&gt;// ....&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In other words, we need an additional flag so that the outer loop can exit after the inner &lt;code&gt;switch&lt;/code&gt; finishes executing. Of course, we could use &lt;code&gt;goto&lt;/code&gt;, but it can make the code harder to follow because the label code execution jumps to can appear anywhere. Labeled &lt;code&gt;break&lt;/code&gt; and &lt;code&gt;continue&lt;/code&gt; simplify this. Let's see what this method would look like now.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;PerformAction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IEnumerable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;WorkItem&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;workList&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;outer:&lt;/span&gt;  &lt;span class="n"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;workList&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// #1&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// #2&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;WorkItemType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Process&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;// ....&lt;/span&gt;
        &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// break #2&lt;/span&gt;
      &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;WorkItemType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StopAll&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;break&lt;/span&gt; &lt;span class="n"&gt;outer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// break #1&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="c1"&gt;// ....&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, the syntax is similar to &lt;code&gt;goto&lt;/code&gt;, while the code becomes more readable. This lets us avoid creating extra flags and checks, which can slightly reduce memory usage and also make the code more expressive. Labels can be applied with the following constructs: &lt;code&gt;for&lt;/code&gt;, &lt;code&gt;foreach&lt;/code&gt;, &lt;code&gt;while&lt;/code&gt;, &lt;code&gt;do&lt;/code&gt;, and &lt;code&gt;switch&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Extension indexers
&lt;/h2&gt;

&lt;p&gt;This change enables developers to define how collection elements can be accessed by index using extension indexers. For example, it's possible to implement element access with &lt;code&gt;Range&lt;/code&gt; for &lt;code&gt;IReadOnlyList&lt;/code&gt;. Before C# 15, we could implement this as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;OldExtensionIndexers&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;Process&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;IReadOnlyList&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;readOnlyList&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"val1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"val2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"val3"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="n"&gt;var&lt;/span&gt; &lt;span class="n"&gt;elem&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;readOnlyList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Slice&lt;/span&gt;&lt;span class="p"&gt;(.&lt;/span&gt;&lt;span class="mf"&gt;.2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;OldReadOnlyListExtensions&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;IReadOnlyList&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Slice&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt; &lt;span class="n"&gt;IReadOnlyList&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
                                          &lt;span class="n"&gt;Range&lt;/span&gt; &lt;span class="n"&gt;range&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;var&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;range&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetOffsetAndLength&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Count&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;var&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;offset&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While a regular extension method already solves this problem, C# 15 introduces the option to create extension indexers. So, we'll get access to elements using the familiar brackets. Let's look at how this would work in our example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;NewExtensionIndexers&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;Process&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;IReadOnlyList&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;readOnlyList&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"val1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"val2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"val3"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="n"&gt;var&lt;/span&gt; &lt;span class="n"&gt;elem&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;readOnlyList&lt;/span&gt;&lt;span class="p"&gt;[.&lt;/span&gt;&lt;span class="mf"&gt;.2&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;NewReadOnlyListExtensions&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;extension&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IReadOnlyList&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;IReadOnlyList&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Range&lt;/span&gt; &lt;span class="n"&gt;range&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;get&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;var&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;range&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetOffsetAndLength&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Count&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Skip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;Take&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;ToList&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's worth noting that if a type has its own indexer, it takes precedence over an indexer declared as an extension. The official order of precedence is as follows: &lt;code&gt;explicit&lt;/code&gt; type indexers, &lt;code&gt;implicit&lt;/code&gt; type indexers, &lt;code&gt;explicit&lt;/code&gt; extension indexers, and &lt;code&gt;implicit&lt;/code&gt; extension indexers. &lt;/p&gt;

&lt;h2&gt;
  
  
  Collection expression arguments
&lt;/h2&gt;

&lt;p&gt;The next feature will help shorten code and make collection initialization more convenient by passing the required arguments directly to the constructor. For example, we can pass &lt;code&gt;capacity&lt;/code&gt; and &lt;code&gt;comparer&lt;/code&gt;. In C# 14 and earlier, we would need to write something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;ProcessList&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;loginList&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"login1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"login2"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

  &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;newLoginList&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;loginList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Count&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;newLoginList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddRange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;loginList&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;ProcessHashSet&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;HashSet&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;hashSet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;HashSet&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;StringComparer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OrdinalIgnoreCase&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;hashSet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"value 1"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;hashSet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"value 2"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The initializer supports only one option because &lt;code&gt;List&lt;/code&gt; has just three constructors: an empty one, one that takes &lt;code&gt;capacity&lt;/code&gt;, and one that takes a collection. Let's look at the new possible implementation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;ProcessList&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;loginList&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"login1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"login2"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

  &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;newLoginList&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;with&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;loginList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Count&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;..&lt;/span&gt;&lt;span class="n"&gt;loginList&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="c1"&gt;// newLoginList.AddRange(loginList);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;ProcessHashSet&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;HashSet&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;hashSet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;with&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;StringComparer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OrdinalIgnoreCase&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; 
    &lt;span class="s"&gt;"value 1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"value 2"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="c1"&gt;// hashSet.Add("value 1");&lt;/span&gt;
  &lt;span class="c1"&gt;// hashSet.Add("value 2");&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code looks cleaner, right? Your IDE will probably even suggest this syntax and collapse everything into a single line. However, note that &lt;code&gt;with&lt;/code&gt; must always come first; otherwise, the compiler will issue an error.&lt;/p&gt;

&lt;h2&gt;
  
  
  Memory safety
&lt;/h2&gt;

&lt;p&gt;The final change involves reevaluating what C# considers unsafe. The language team aims to flag only code that actually accesses unmanaged memory as unsafe. In other words, using pointers will no longer automatically make code unsafe. Before C# 15, unsafe code was marked like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;unsafe&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;OldMemorySafety&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;ReadMemory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;byte&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;ptr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;ptr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;Process&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;byte&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;byte&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;newPtr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ReadMemory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;newPtr&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Any use of pointers used to require the &lt;code&gt;unsafe&lt;/code&gt; keyword. To better understand the change, let's take a look at what the code will look like in the new version:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;NewMemorySafety&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;ReadMemory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;byte&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;ptr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;unsafe&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;ptr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;Process&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;byte&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;byte&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;newPtr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ReadMemory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;newPtr&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We no longer need to mark the class as &lt;code&gt;unsafe&lt;/code&gt;. Instead, the keyword goes only where it's needed. In this case, dereferencing the pointer is unsafe, so it should be marked as such.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;safe&lt;/code&gt; keyword has also been added. It should be used when a block contains unsafe operations that are safe for the caller's context, so callers don't require the &lt;code&gt;unsafe&lt;/code&gt; block. In other words, use &lt;code&gt;safe&lt;/code&gt; when the compiler can't verify safety on its own. Examples include &lt;code&gt;extern&lt;/code&gt; methods and fields in structs with explicit memory layout (&lt;code&gt;[StructLayout(LayoutKind.Explicit)]&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;It's also worth mentioning &lt;code&gt;stackalloc&lt;/code&gt;. Its use is now considered unsafe when all of the following apply: it's converted to &lt;code&gt;Span&amp;lt;T&amp;gt;&lt;/code&gt; or &lt;code&gt;ReadOnlySpan&amp;lt;T&amp;gt;&lt;/code&gt;, it has no initializer, and it's used where &lt;code&gt;SkipLocalsInitAttribute&lt;/code&gt; is present.&lt;/p&gt;

&lt;p&gt;The new rules introduced by this change should be enabled separately. If you'd like to learn more, follow &lt;a href="https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/compiler-options/language#enable-the-updated-memory-safety-rules" rel="noopener noreferrer"&gt;this link&lt;/a&gt; for the official instructions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;This year's language release has brought developers a number of fairly important features. Among them are useful additions such as &lt;code&gt;union&lt;/code&gt; types and closed hierarchies, while several other changes simplify common coding patterns, making development little smoother once again. Some of these features may not become as popular, but that doesn't make them any less useful to certain groups of developers. Which of these changes did you find most useful? Share your thoughts in the comments!&lt;/p&gt;

&lt;p&gt;You can read the C# 15 documentation via &lt;a href="https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-15" rel="noopener noreferrer"&gt;this link&lt;/a&gt;. Don't forget to check out our overviews of previous versions, here's the list:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://pvs-studio.com/en/blog/posts/csharp/0860/" rel="noopener noreferrer"&gt;What's new in C# 9: overview&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://pvs-studio.com/en/blog/posts/csharp/0875/" rel="noopener noreferrer"&gt;What's new in C# 10: overview&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://pvs-studio.com/en/blog/posts/csharp/1002/" rel="noopener noreferrer"&gt;What's new in C# 11: overview&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://pvs-studio.com/en/blog/posts/csharp/1074/" rel="noopener noreferrer"&gt;What's new in C# 12: overview&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://pvs-studio.com/en/blog/posts/csharp/1173/" rel="noopener noreferrer"&gt;What's new in C# 13: overview&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://pvs-studio.com/en/blog/posts/csharp/1301/" rel="noopener noreferrer"&gt;What's new in C# 14: overview&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>csharp</category>
      <category>dotnet</category>
      <category>news</category>
      <category>programming</category>
    </item>
    <item>
      <title>PVS-Studio 8.01: OWASP Benchmark, JDK 25 and Go 1.27 support, and much more</title>
      <dc:creator>Unicorn Developer</dc:creator>
      <pubDate>Fri, 16 Oct 2026 14:02:33 +0000</pubDate>
      <link>https://dev.to/pvsdev/pvs-studio-801-owasp-benchmark-jdk-25-and-go-127-support-and-much-more-p5d</link>
      <guid>https://dev.to/pvsdev/pvs-studio-801-owasp-benchmark-jdk-25-and-go-127-support-and-much-more-p5d</guid>
      <description>&lt;p&gt;PVS-Studio 8.01 has been released. This version features expanded support for OWASP, JDK 25 and Go 1.27 support, and much more.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fi4358vjgxr1v5azcrjar.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fi4358vjgxr1v5azcrjar.png" alt=" " width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  OWASP Benchmark for Java
&lt;/h2&gt;

&lt;p&gt;In this release, we checked the Java analyzer SAST rules against the &lt;a href="https://owasp.org/www-project-benchmark/" rel="noopener noreferrer"&gt;OWASP Benchmark for Java&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Evaluating the quality of security-related diagnostic rules on real-world projects can be quite challenging. We can't predict how many vulnerabilities the code will contain, so we can't determine which defects the analyzer has overlooked.&lt;/p&gt;

&lt;p&gt;We used the benchmark to address gaps in the Java analyzer SAST capabilities, which made the tool more effective at detecting security defects.&lt;/p&gt;

&lt;h2&gt;
  
  
  New versions of Java and Go
&lt;/h2&gt;

&lt;p&gt;With the release of PVS-Studio 8.01, we've added support for the latest platform versions. The Java analyzer now supports JDK 25, and the Go analyzer supports Go 1.27. &lt;/p&gt;

&lt;p&gt;This enables teams to analyze projects using the latest language versions and standard libraries without delaying updates due to limitations in their analysis tools. &lt;/p&gt;

&lt;p&gt;JDK 25 is also an LTS release, making its support particularly important for teams migrating to a new long-term support version.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reports with analysis configuration details
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;PVS-Studio_Cmd.exe&lt;/code&gt; utility for analyzing MSBuild projects now includes in JSON reports the project configurations used during analysis. This makes it easier to fix warnings that occur on specific platforms. &lt;/p&gt;

&lt;p&gt;In addition, the &lt;code&gt;fullhtml&lt;/code&gt; report generated by &lt;a href="https://pvs-studio.com/en/docs/manual/0038/" rel="noopener noreferrer"&gt;&lt;code&gt;PlogConverter.exe&lt;/code&gt;&lt;/a&gt; now groups warnings by analysis configuration.&lt;/p&gt;

&lt;h2&gt;
  
  
  Expanded configuration options
&lt;/h2&gt;

&lt;p&gt;This release expands the configuration options for our analyzers and utilities, making them easier to tailor to specific project requirements and environments.&lt;/p&gt;

&lt;p&gt;The JavaScript and TypeScript analyzer now supports the &lt;code&gt;max-old-space-size&lt;/code&gt; setting. You can find it in the &lt;a href="https://pvs-studio.com/en/docs/manual/7193/" rel="noopener noreferrer"&gt;&lt;code&gt;pvs-settings.toml&lt;/code&gt; configuration file&lt;/a&gt; and the &lt;a href="https://pvs-studio.com/en/docs/manual/7195/" rel="noopener noreferrer"&gt;&lt;code&gt;pvs-js.exe&lt;/code&gt; command-line utility&lt;/a&gt;. This setting enables you to specify how much memory the analyzer's Node.js server can use.&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;PVS-Studio_Cmd.exe&lt;/code&gt;, you can now specify dependency cache paths relative to the &lt;a href="https://pvs-studio.com/en/docs/manual/6630/" rel="noopener noreferrer"&gt;&lt;code&gt;.pvsconfig&lt;/code&gt; configuration file&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The C and C++ analyzer now offers more options for configuring diagnostic rules. Now, you can specify custom types as "cheap-to-copy," and configure the analyzer behavior based on the target platform.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://pvs-studio.com/en/docs/warnings/v719/" rel="noopener noreferrer"&gt;V719&lt;/a&gt; diagnostic rule now supports additional configuration options: ignoring &lt;code&gt;default&lt;/code&gt; branches and small &lt;code&gt;enum&lt;/code&gt; types, specifying individual values to ignore, and setting the maximum number of constants that can be ignored.&lt;/p&gt;

&lt;h2&gt;
  
  
  Extended warning filtering
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://pvs-studio.com/en/docs/manual/0038/" rel="noopener noreferrer"&gt;Plog Converter utility&lt;/a&gt; for converting and filtering reports now allows you to filter diagnostic rules by CWE codes and SAST identifiers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Breaking Change
&lt;/h2&gt;

&lt;p&gt;This release includes a change that breaks backward compatibility with previous versions of the analyzer. You may need to adjust how you use the analyzer due to these changes.&lt;/p&gt;

&lt;p&gt;The PVS-Studio installer for Windows now &lt;a href="https://pvs-studio.com/en/docs/manual/0025/" rel="noopener noreferrer"&gt;returns exit code &lt;code&gt;100&lt;/code&gt;&lt;/a&gt; if Visual Studio plugin installation fails. We also added the &lt;code&gt;skipVSIXInstallErrorCode&lt;/code&gt; flag to disable the non-zero exit code in this case.&lt;/p&gt;

&lt;h2&gt;
  
  
  New diagnostic rules
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Java
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://pvs-studio.com/en/docs/warnings/v5341/" rel="noopener noreferrer"&gt;V5341&lt;/a&gt;. OWASP. A cookie was created without enabling the 'Secure' attribute. This may lead to the exposure of sensitive data.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://pvs-studio.com/en/docs/warnings/v5342/" rel="noopener noreferrer"&gt;V5342&lt;/a&gt;. OWASP. Potentially tainted data is stored in an object that can be used as a source of trusted data.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://pvs-studio.com/en/docs/warnings/v5343/" rel="noopener noreferrer"&gt;V5343&lt;/a&gt;. OWASP. A cryptographically weak random number is used for sensitive data.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Articles
&lt;/h2&gt;

&lt;p&gt;Here's the traditional roundup of posts from our blog! Over the past two months, we've published articles where we looked for bugs in the popular C# ORMs, RepoDB and SqlSugar, reviewed VSCode source code, explored the new features of Java 27, found bugs in the Create mode, and much more. The full list is below:&lt;/p&gt;

&lt;h3&gt;
  
  
  C and C++
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://pvs-studio.com/en/blog/posts/cpp/1409/" rel="noopener noreferrer"&gt;The worst programming language of all time /s&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Csharp
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://pvs-studio.com/en/blog/posts/csharp/1411/" rel="noopener noreferrer"&gt;What popular ORMs for C# hide: Let's check RepoDB and SqlSugar&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Java
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://pvs-studio.com/en/blog/posts/java/1412/" rel="noopener noreferrer"&gt;What's new in Java 27&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://pvs-studio.com/en/blog/posts/java/1417/" rel="noopener noreferrer"&gt;I found some bugs in Create mod and checked them in Minecraft&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  JavaScript and TypeScript
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://pvs-studio.com/en/blog/posts/js/1407/" rel="noopener noreferrer"&gt;We checked the source code of VS Code&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Go
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://pvs-studio.com/en/blog/posts/go/1413/" rel="noopener noreferrer"&gt;PVS-Studio for Go: Quick overview of new diagnostic rules&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Security
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://pvs-studio.com/en/blog/posts/1408/" rel="noopener noreferrer"&gt;Avoid adding new library to project: 10-year retrospective&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Other
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://pvs-studio.com/en/blog/posts/1410/" rel="noopener noreferrer"&gt;Why do we integrate PVS-Studio analyzer with so many tools?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Webinars
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Let's make a programming language. Variables
&lt;/h3&gt;

&lt;p&gt;We continue building our own programming language from scratch. In this video, we'll take the next step by adding variables to the language.&lt;/p&gt;

&lt;p&gt;So far, our programs have consisted of a single expression built from smaller language constructs. Now it's time to evolve the language. Instead of parsing a single expression, we'll introduce a list of declarations, allowing our language to support variable declarations and laying the groundwork for more complex programs.&lt;/p&gt;

&lt;p&gt;During the video, Yuri will walk through the implementation step by step, showing how variables are represented and processed in our language, and how to add this functionality to your language in C++.&lt;/p&gt;

&lt;p&gt;This video is designed for developers who want to understand how programming languages work under the hood—not just how to use them.&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/Sn8fVb_O90Y" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  Go-Go-Gadg...Error? A closer look at the mistakes Go developers make!
&lt;/h3&gt;

&lt;p&gt;Mistakes happen in Go code just like in any other language: typos, duplicates, broken condition checks, and so on.&lt;/p&gt;

&lt;p&gt;But why do they still slip through? After all, many teams use tools like go vet, which catches all of this perfectly well... right?&lt;/p&gt;

&lt;p&gt;In this webinar we covered:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Common mistakes in Go code, straight from well-known projects;&lt;/li&gt;
&lt;li&gt;Errors that standard tools and approaches fail to catch, and how to handle them.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/gdF_AObnq6Y" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  Let's make a programming language. Functions
&lt;/h3&gt;

&lt;p&gt;We continue building our own programming language from scratch.&lt;/p&gt;

&lt;p&gt;In the previous session, we introduced variables—they could be declared, reference one another, and were resolved through a global hash table. Now it's time to add one of the core building blocks of any language: functions. Implementing functions is really a story about scopes and name resolution. We'll explore how identifiers are looked up across different scope levels: the global scope, function scopes with their own variables, and nested local scopes inside function bodies. What happens when the same variable name exists in multiple scopes? How does the compiler determine which one to use?&lt;/p&gt;

&lt;p&gt;In this video, we will walk through the implementation step by step, demonstrating how functions, scopes, and symbol lookup are built in code using C++. Along the way, you'll gain a deeper understanding of one of the fundamental mechanisms behind modern programming languages. &lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/QT7tyIENfZI" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;h4&gt;
  
  
  Let's make a programming language. Evaluator
&lt;/h4&gt;

&lt;p&gt;We're reaching the final stage of our journey of building a programming language in C++!&lt;/p&gt;

&lt;p&gt;So far, we've created a lexer, a parser, and an AST. Now it's time to make our language do what it was designed to do—evaluate expressions.&lt;/p&gt;

&lt;p&gt;In this webinar, we'll explore how to represent the results of computations in our language and learn how to evaluate expressions step by step. By the end of the session, we'll bring all the pieces together and complete our own programming language.&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/2-3ytWWhy8s" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  Go vet can't go: How to create your own Go analyzer?
&lt;/h3&gt;

&lt;p&gt;A static analyzer is a powerful dev tool, and any Go developer who has worked with go vet knows it. But what if its capabilities aren't enough? Would you look for a new tool, or... build your own?&lt;/p&gt;

&lt;p&gt;In this live talk, PVS-Studio's Developer Advocate walks through Go's built-in tools and code-parsing capabilities, explains the basics of static analysis, unpacks what a semantic model is, shows how to build a syntax tree, and much more.&lt;/p&gt;

&lt;p&gt;The end goal? Build your own static analyzer, tailored to catch what matters most in your projects.&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/KAaJT_mUijA" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Bugbusters
&lt;/h2&gt;

&lt;p&gt;This is the first episode of our new podcast, Bugbusters. Our guest is Nathan Baggs, a content creator and YouTuber. We discussed whether it's worth learning C++ in 2026, how the language is evolving, what it's used for, and what its drawbacks are. We hope you enjoy this episode! We look forward to your comments!&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/kd-5hJHvKIY" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;If you would like to receive news about PVS-Studio releases, &lt;a href="https://pvs-studio.com/en/subscribe/" rel="noopener noreferrer"&gt;subscribe to our newsletter here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you haven't checked your project using PVS-Studio yet, &lt;a href="https://pvs-studio.com/en/pvs-studio/try-free/?utm_source=website&amp;amp;utm_medium=devto&amp;amp;utm_campaign=article&amp;amp;utm_content=1420" rel="noopener noreferrer"&gt;start with a trial license&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>news</category>
      <category>cpp</category>
      <category>java</category>
      <category>go</category>
    </item>
    <item>
      <title>When copy-paste goes wrong: Bugs in structurally isomorphic Go code</title>
      <dc:creator>Unicorn Developer</dc:creator>
      <pubDate>Tue, 13 Oct 2026 14:20:32 +0000</pubDate>
      <link>https://dev.to/pvsdev/when-copy-paste-goes-wrong-bugs-in-structurally-isomorphic-go-code-1ng8</link>
      <guid>https://dev.to/pvsdev/when-copy-paste-goes-wrong-bugs-in-structurally-isomorphic-go-code-1ng8</guid>
      <description>&lt;p&gt;You might've done this many times: you found code in a project that seemed like a good fit for your task, copied it, replaced the variables or function calls with the ones you needed, and then got behavior you didn't expect when you ran the code. It's likely that you missed something while making those changes. This is exactly how the errors described in this article occur.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Flc2ey8jxn6fvcw3ofz34.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Flc2ey8jxn6fvcw3ofz34.png" alt=" " width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;PVS-Studio 8.00 was recently released, introducing several &lt;a href="https://pvs-studio.com/en/blog/posts/1406/" rel="noopener noreferrer"&gt;new major features&lt;/a&gt;, including the Go analyzer that comes with several new and cool diagnostic rules. &lt;/p&gt;

&lt;p&gt;It includes a rule that detects one of the trickiest types of copy-paste bugs, the kind that can easily slip past a regular code review. Okay, now let's take a look at the code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ProcessName&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;nil&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; 
   &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ProcessName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;
   &lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ProcessName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;common&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NameFieldMaxLength&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;kit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CCError&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CCErrorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;common&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CCErrCommParamsInvalid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;        
                              &lt;span class="n"&gt;common&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BKProcessNameField&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;....&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FuncName&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;nil&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; 
   &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FuncName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;
   &lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ProcessName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;common&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NameFieldMaxLength&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;kit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CCError&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CCErrorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;common&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CCErrCommParamsInvalid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
                              &lt;span class="n"&gt;common&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BKFuncName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You've probably noticed that the expressions in both &lt;code&gt;if&lt;/code&gt; statements consist of the same checks, but they aren't completely identical: the first one uses &lt;code&gt;process.ProcessName&lt;/code&gt;, while the second one uses &lt;code&gt;process.FuncName&lt;/code&gt; in the same positions. Or... does it?&lt;/p&gt;

&lt;p&gt;The last checks suspiciously break this pattern: they're exactly the same, and both use the &lt;code&gt;process.ProcessName&lt;/code&gt; field. Based on the logic the code has consistently followed so far, the check in the second &lt;code&gt;if&lt;/code&gt; should have used a different field, &lt;code&gt;process.FuncName&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Since such typos can easily slip past manual review, the best solution is to delegate the task of catching them to a static analyzer. But how can we teach a program to compare similar yet distinct code fragments and use those comparisons to detect bugs the way humans do? Is AI necessary for that? In the rest of this article, we'll explore these questions by looking at how the diagnostic rule works in PVS-Studio for Go. &lt;/p&gt;

&lt;h2&gt;
  
  
  How does the analyzer find these bugs?
&lt;/h2&gt;

&lt;p&gt;Modern AI models can indeed detect such bugs. However, integrating artificial intelligence into a static analyzer for such a purpose is too expensive and resource-intensive.&lt;/p&gt;

&lt;p&gt;Fortunately, we don't need AI here. We can handle the task with a relatively simple heuristic algorithm. We'll take a closer look at how it works later, but first, let's go over a few basic concepts from static code analysis:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Statements are the elements of code that form its skeleton and describe the execution flow (&lt;code&gt;if&lt;/code&gt;, &lt;code&gt;switch&lt;/code&gt;, &lt;code&gt;for&lt;/code&gt;, and &lt;code&gt;{...}&lt;/code&gt; blocks).&lt;/li&gt;
&lt;li&gt;Expressions are code elements that manage data (function calls, variables, and operators).&lt;/li&gt;
&lt;li&gt;Nodes is a general term for statements, expressions, and other types of code elements.&lt;/li&gt;
&lt;li&gt;Abstract Syntax Tree (AST) represents code as a hierarchical structure where some elements, like folders in a file system, contain other elements. An AST contains the same information you can get from the code itself, but its structured format makes it better suited for program analysis.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you're interested in delving deeper into static analysis, we have the perfect &lt;a href="https://pvs-studio.com/en/blog/posts/go/1329/" rel="noopener noreferrer"&gt;article&lt;/a&gt; for you.&lt;/p&gt;

&lt;p&gt;Well, now that we have enough context, we're ready to face the &lt;del&gt;boss&lt;/del&gt; algorithm. Here's how the &lt;a href="https://pvs-studio.com/en/docs/warnings/v8033/" rel="noopener noreferrer"&gt;V8033&lt;/a&gt; diagnostic rule in PVS-Studio's Go analyzer works:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Within a function, the analyzer takes individual statements and groups of statements, separated by blank lines (hereinafter referred to as code fragments) and builds a simplified AST for them. Unlike a regular AST, it contains only the information needed to describe the code structure and omits specific names of variables, functions, and other semantic information.&lt;/li&gt;
&lt;li&gt;The fragments are grouped by their simplified AST. This is how fragments with similar structure are identified, even though they may still differ in their details (for example, in the variables they use).&lt;/li&gt;
&lt;li&gt;Within each group, the fragments are paired and compared with one another. Let's look at how the algorithm works for a single pair. For convenience, let's call the two fragments in one pair A and B.&lt;/li&gt;
&lt;li&gt;The analyzer identifies the variables that appear in both A and B (common variables) as well as the variables that appear in only one of the fragments (specific variables).&lt;/li&gt;
&lt;li&gt;Let's assume that A is higher in the code than B. If one of the common variables occurs less frequently in B than in A, but still at the same relative positions, the uses of that variable in B are treated as potential typos.&lt;/li&gt;
&lt;li&gt;Next, a replacement candidate is sought among the B variables. This variable must be used in the same relative position as the previously considered general variable in A, but not in B.&lt;/li&gt;
&lt;li&gt;If the analyzer finds such a candidate, it performs a series of final checks to determine whether the variables are interchangeable. If all the checks pass, the developer receives warnings about possible typos in the code.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Of course, this is just a conceptual outline. A significant amount of important logic remains behind the scenes, especially the logic that filters out false positives. Without it, the diagnostic rule would be far less useful.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;It is only 5% of the task to create the diagnostic. It's not hard for the analyzer to complain about suspicious code, it's much harder to not complain about the correct code. We spend 95% of our time "teaching" the analyzer to detect various programming techniques, which may seem suspicious for the diagnostic, but in reality they are correct.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;From the &lt;a href="https://pvs-studio.com/en/blog/posts/cpp/0466/" rel="noopener noreferrer"&gt;article&lt;/a&gt; "How PVS-Studio does the bug search: methods and technologies"&lt;/p&gt;

&lt;p&gt;Now that we've taken a quick look at how the analyzer works, let's exercise in looking for similar errors on our own.&lt;/p&gt;

&lt;h2&gt;
  
  
  Find an error
&lt;/h2&gt;

&lt;p&gt;I invite you to challenge yourselves by finding errors in this code, which was taken from real open-source projects. The closer you get to the end, the harder the examples become. &lt;/p&gt;

&lt;p&gt;Are you up for the challenge? Let's get started, then!&lt;/p&gt;

&lt;h3&gt;
  
  
  Yao Agents
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/YaoApp/yao" rel="noopener noreferrer"&gt;Yao Agents&lt;/a&gt; is an open-source platform for creating and running autonomous AI agents. Its key feature is that the agents run directly on users' devices, while all operations are centralized and controlled via a single interface.&lt;/p&gt;

&lt;p&gt;We found this code in the &lt;a href="https://github.com/YaoApp/yao/releases/tag/v1.0.0-rc15" rel="noopener noreferrer"&gt;v1.0.0-rc15&lt;/a&gt; release:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;Generate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;option&lt;/span&gt; &lt;span class="n"&gt;Option&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;option&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Width&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;option&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Width&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;240&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;option&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Height&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;option&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Width&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;option&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;option&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;option&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Lang&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;option&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Lang&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"zh"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;....&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;/p&gt;
  The analyzer's hint
  &lt;br&gt;
V8033 Two similar code fragments were found. The second fragment may contain a typo: the "option.Height" variable should be used instead of the "option.Width". &lt;a href="https://github.com/YaoApp/yao/blob/8999225a4ca612cb665f81f47bd65b2c89a10cd3/utils/captcha/captcha.go#L48" rel="noopener noreferrer"&gt;captcha.go 48&lt;/a&gt;



&lt;p&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  CDS
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/ovh/cds" rel="noopener noreferrer"&gt;CDS&lt;/a&gt; is an enterprise-grade platform for automating DevOps processes, continuous integration (CI), and continuous delivery (CD).&lt;/p&gt;

&lt;p&gt;We found this code in the &lt;a href="https://github.com/ovh/cds/releases/tag/v0.54.1" rel="noopener noreferrer"&gt;0.54.1&lt;/a&gt; release:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;conf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GraylogFieldCDSServiceName&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;extra&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"CDSName"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;conf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GraylogFieldCDSServiceName&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;conf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GraylogFieldCDSServiceName&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;extra&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"CDSService"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;conf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GraylogFieldCDSServiceType&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;conf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GraylogFieldCDSVersion&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;extra&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"CDSVersion"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;conf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GraylogFieldCDSVersion&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;conf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GraylogFieldCDSOS&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;extra&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"CDSOS"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;conf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GraylogFieldCDSOS&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;conf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GraylogFieldCDSArch&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;extra&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"CDSArch"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;conf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GraylogFieldCDSArch&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;/p&gt;
  The analyzer's hint
  &lt;br&gt;
V8033 Two similar code fragments were found. The second fragment may contain a typo: the "conf.GraylogFieldCDSServiceType" variable should be used instead of the "conf.GraylogFieldCDSServiceName". &lt;a href="https://github.com/ovh/cds/blob/a58c0035cb4fc99830d5604e4657d4a1d577e2c5/sdk/log/log.go#L160" rel="noopener noreferrer"&gt;log.go 107&lt;/a&gt;



&lt;p&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  BFE
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/bfenetworks/bfe" rel="noopener noreferrer"&gt;BFE&lt;/a&gt; is a high-performance, application-level load balancer and reverse proxy server.&lt;/p&gt;

&lt;p&gt;We found this code in the &lt;a href="https://github.com/bfenetworks/bfe/releases/tag/v1.8.4" rel="noopener noreferrer"&gt;1.8.4&lt;/a&gt; release:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Basic&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WasmPluginPath&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;....&lt;/span&gt;
  &lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Basic&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WasmPluginPath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"mod_wasm"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Basic&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WasmPluginPath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bfe_util&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ConfPathProc&lt;/span&gt;&lt;span class="p"&gt;(....)&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Basic&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DataPath&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;....&lt;/span&gt;
  &lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Basic&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WasmPluginPath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"mod_wasm/wasm.data"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Basic&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DataPath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bfe_util&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ConfPathProc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Basic&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DataPath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
                                           &lt;span class="n"&gt;confRoot&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;/p&gt;
  The analyzer's hint
  &lt;br&gt;
V8033 Two similar code fragments were found. The second fragment may contain a typo: the "cfg.Basic.DataPath" variable should be used instead of the "cfg.Basic.WasmPluginPath". &lt;a href="https://github.com/bfenetworks/bfe/blob/b9fb26f3e7be27b4caf6b1a5540fb2dcb9b5659a/bfe_modules/mod_wasmplugin/conf_mod_wasmplugin.go#L63" rel="noopener noreferrer"&gt;conf_mod_wasmplugin.go 63&lt;/a&gt;



&lt;p&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Hertz
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/cloudwego/hertz" rel="noopener noreferrer"&gt;Hertz&lt;/a&gt; is a high-performance HTTP framework written in Go by ByteDance (the creators of TikTok), designed for building high-load microservices. It combined the concepts of popular Go frameworks (Gin, FastHTTP) with ByteDance's internal requirements.&lt;/p&gt;

&lt;p&gt;We found this code in the &lt;a href="https://github.com/cloudwego/hertz/releases/tag/v0.10.6" rel="noopener noreferrer"&gt;0.10.6&lt;/a&gt; release:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;goOptMapAlias&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;sb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Scope&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetOptions&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;GetGoPackage&lt;/span&gt;&lt;span class="p"&gt;()]&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;reqName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;goOptMapAlias&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;sb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Scope&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetOptions&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;GetGoPackage&lt;/span&gt;&lt;span class="p"&gt;()]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; 
            &lt;span class="s"&gt;"."&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;inputGoType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GoIdent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GoName&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;goOptMapAlias&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;sb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Scope&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetOptions&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;GetGoPackage&lt;/span&gt;&lt;span class="p"&gt;()]&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;respName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;goOptMapAlias&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Scope&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetOptions&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;GetGoPackage&lt;/span&gt;&lt;span class="p"&gt;()]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; 
             &lt;span class="s"&gt;"."&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;outputGoType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GoIdent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GoName&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;/p&gt;
  The analyzer's hint
  &lt;br&gt;
V8033 Two similar code fragments were found. The second fragment may contain a typo: the "st" variable should be used instead of the "sb". &lt;a href="https://github.com/cloudwego/hertz/blob/3415de4ca25f550996dab49d62839ebc6165d6b9/cmd/hz/protobuf/ast.go#L233" rel="noopener noreferrer"&gt;ast.go 233&lt;/a&gt;



&lt;p&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Nuclei
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/projectdiscovery/nuclei/tree/dev" rel="noopener noreferrer"&gt;Nuclei&lt;/a&gt; is a modern, high-performance vulnerability scanner that uses simple YAML-based templates. It enables users to create their own vulnerability detection scenarios that simulate real-world conditions, which eliminates false positives.&lt;/p&gt;

&lt;p&gt;We found this code in the &lt;a href="https://github.com/projectdiscovery/nuclei/releases/tag/v3.11.1" rel="noopener noreferrer"&gt;3.11.1&lt;/a&gt; release:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tag&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;range&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ExcludeTags&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;range&lt;/span&gt; &lt;span class="n"&gt;splitCommaTrim&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="p"&gt;{}{}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tag&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;range&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Severities&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;severities&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;severities&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="p"&gt;{}{}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;....&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tag&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;range&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ExcludeProtocols&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;excludeTypes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;excludeTypes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="p"&gt;{}{}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;range&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ExcludeIds&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;range&lt;/span&gt; &lt;span class="n"&gt;splitCommaTrim&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;excludeIds&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="p"&gt;{}{}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;/p&gt;
  The analyzer's hint
  &lt;br&gt;
V8033 Two similar code fragments were found. The second fragment may contain a typo: the "filter.excludeIds" variable should be used instead of the "filter.block". &lt;a href="https://github.com/projectdiscovery/nuclei/blob/bb79d8ed71fcb71b49ca0563ecadbb3083857cd9/pkg/templates/tag_filter.go#L434" rel="noopener noreferrer"&gt;tag_filter.go 434&lt;/a&gt;



&lt;p&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  LakeFS
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/treeverse/lakeFS" rel="noopener noreferrer"&gt;LakeFS&lt;/a&gt; is an open-source data version control system for managing data stored in an object storage system. It enables Git-like operations like branching, committing, merging, and rolling back for large-scale data, stored in systems including Amazon S3, Azure Blob Storage, and Google Cloud Storage, as well as on other S3-compatible object storage platforms.&lt;/p&gt;

&lt;p&gt;We found this code in the &lt;a href="https://github.com/treeverse/lakeFS/releases/tag/v1.86.0" rel="noopener noreferrer"&gt;1.86.0&lt;/a&gt; release:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;usersKey&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GroupUserPath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;groupID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;kv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewSecondaryIterator&lt;/span&gt;&lt;span class="p"&gt;(....)&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Next&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;entry&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Entry&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;.(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UserData&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;....&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Err&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;policiesKey&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GroupPolicyPath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;groupID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;itr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;kv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewSecondaryIterator&lt;/span&gt;&lt;span class="p"&gt;(....)&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;itr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Next&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;entry&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;itr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Entry&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="n"&gt;policy&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;.(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PolicyData&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;....&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;itr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Err&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;/p&gt;
  The analyzer's hint
  &lt;br&gt;
V8033 Two similar code fragments were found. The second fragment may contain a typo: the "itr" variable should be used instead of the "it". &lt;a href="https://github.com/treeverse/lakeFS/blob/4bb11638e95637e853d9680abf072b14f09e32fb/contrib/auth/acl/service.go#L476" rel="noopener noreferrer"&gt;service.go 476&lt;/a&gt;



&lt;p&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Vault
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/hashicorp/vault" rel="noopener noreferrer"&gt;Vault&lt;/a&gt; is an open-source (BSL) tool for centralized secret management, data encryption, and for the protection of confidential information in cloud and hybrid infrastructures.&lt;/p&gt;

&lt;p&gt;We found this code in the &lt;a href="https://github.com/hashicorp/vault/releases/tag/v2.0.4" rel="noopener noreferrer"&gt;2.0.4&lt;/a&gt; release:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;crl&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;range&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CRLs&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;....&lt;/span&gt;
  &lt;span class="n"&gt;ratio&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Duration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;int64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;int64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CRLExpiryPercentage&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;int64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;used&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;ratio&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;expWhen&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;crl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ThisUpdate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ratio&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ret&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ResultCritical&lt;/span&gt;
    &lt;span class="n"&gt;ret&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="p"&gt;....,&lt;/span&gt; 
      &lt;span class="n"&gt;crl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NextUpdate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"2006-01-02"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; 
      &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CRLExpiryPercentage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;   
      &lt;span class="n"&gt;crl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ThisUpdate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"2006-01-02"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; 
      &lt;span class="n"&gt;expWhen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"2006-01-02"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;....&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;ret&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;crl&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;range&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DeltaCRLs&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;....&lt;/span&gt;
  &lt;span class="n"&gt;ratio&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Duration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;int64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;int64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DeltaCRLExpiryPercentage&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;int64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;used&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;ratio&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;expWhen&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;crl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ThisUpdate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ratio&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ret&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ResultCritical&lt;/span&gt;
    &lt;span class="n"&gt;ret&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="p"&gt;....,&lt;/span&gt; 
      &lt;span class="n"&gt;crl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NextUpdate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"2006-01-02"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CRLExpiryPercentage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
      &lt;span class="n"&gt;crl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ThisUpdate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"2006-01-02"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; 
      &lt;span class="n"&gt;expWhen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"2006-01-02"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;....&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;ret&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;/p&gt;
  The analyzer's hint
  &lt;br&gt;
V8033 Two similar code fragments were found. The second fragment may contain a typo: the "h.DeltaCRLExpiryPercentage" variable should be used instead of the "h.CRLExpiryPercentage". &lt;a href="https://github.com/hashicorp/vault/blob/2beda6097e3409b0ffc56c4bd23965daa661a112/command/healthcheck/pki_crl_validity_period.go#L195" rel="noopener noreferrer"&gt;pki_crl_validity_period.go 195&lt;/a&gt;



&lt;p&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Did you spot all the errors without looking at the hints? If so, that's great! If not, don't worry—that's where a static code analyzer comes into play!&lt;/p&gt;

&lt;p&gt;By the way, you can download it from our &lt;a href="https://pvs-studio.com/en/pvs-studio/try-free/?utm_source=website&amp;amp;utm_medium=devto&amp;amp;utm_campaign=article&amp;amp;utm_content=1419" rel="noopener noreferrer"&gt;official website&lt;/a&gt; and try it for free on your own projects. &lt;/p&gt;

&lt;p&gt;In addition to the Go analyzer, PVS-Studio 8.00 brought several other exciting features, including an analyzer for JavaScript and TypeScript. You can find more details about them in our &lt;a href="https://pvs-studio.com/en/blog/posts/1406/" rel="noopener noreferrer"&gt;article&lt;/a&gt;.  &lt;/p&gt;

&lt;p&gt;Happy coding!&lt;/p&gt;

</description>
      <category>go</category>
      <category>programming</category>
      <category>debugging</category>
    </item>
    <item>
      <title>How we made JavaScript analyzer understand control flow</title>
      <dc:creator>Unicorn Developer</dc:creator>
      <pubDate>Fri, 09 Oct 2026 12:31:28 +0000</pubDate>
      <link>https://dev.to/pvsdev/how-we-made-javascript-analyzer-understand-control-flow-4ghl</link>
      <guid>https://dev.to/pvsdev/how-we-made-javascript-analyzer-understand-control-flow-4ghl</guid>
      <description>&lt;p&gt;We recently added JavaScript/TypeScript support to PVS-Studio analyzer. From its first release, the analyzer can detect control-flow bugs in code. In this article, we'll learn about the control flow graph (CFG), how we've implemented it, and why it's useful.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjcbezezdpcuyy82jk8cl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjcbezezdpcuyy82jk8cl.png" alt="1418_js_cfg/image1.png" width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  A Control Flow Graph?
&lt;/h2&gt;

&lt;p&gt;I've touched on this topic before, in my &lt;a href="https://pvs-studio.com/en/blog/posts/java/1198/" rel="noopener noreferrer"&gt;series&lt;/a&gt; on taint analysis in Java, but let's quickly recap it here. A static analyzer starts by converting source code into an abstract syntax tree (AST). It almost completely mirrors the structure of the code as you write it in the editor. That makes it a poor fit for anything involving control flow analysis, such as finding unreachable code. It's possible to write a check for unreachable code on the AST, but:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;this would be unreliable in corner cases;&lt;/li&gt;
&lt;li&gt;this wouldn't scale well to similar rules;&lt;/li&gt;
&lt;li&gt;this would be hard to maintain. Every bug fix or new language version would mean revisiting all of these diagnostic rules.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The Control Flow Graph (CFG) exists to address these issues; it maps out all possible execution paths in a program.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3i2c6uwamxp5x60yj4u1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3i2c6uwamxp5x60yj4u1.png" alt="1418_js_cfg/image2.png" width="800" height="773"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The CFG consists of three components:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;entry and exit nodes;&lt;/li&gt;
&lt;li&gt;Basic blocks nodes, each containing linear instructions;

&lt;ul&gt;
&lt;li&gt;Each basic block ends with a terminator (or with nothing). A terminator is a special instruction that determines specific semantics for the execution flow: branching, &lt;code&gt;break&lt;/code&gt;/&lt;code&gt;continue&lt;/code&gt;, and so on.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Edges between nodes that represent possible control flow transitions.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1q0epm8x6l22n82uldds.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1q0epm8x6l22n82uldds.png" alt="1418_js_cfg/image3.png" width="800" height="175"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How did we do it?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Common CFG
&lt;/h3&gt;

&lt;p&gt;In our &lt;a href="https://pvs-studio.com/en/blog/posts/js/1363/" rel="noopener noreferrer"&gt;article&lt;/a&gt; on developing the JavaScript/TypeScript analyzer, we &lt;a href="https://pvs-studio.com/en/blog/posts/js/1363/#IDC01AE1A5F1" rel="noopener noreferrer"&gt;mentioned&lt;/a&gt; that the tool includes not only a syntax tree for each specific language, but also a common one for multilingual analysis. We named it CAT (Common Abstract Tree).&lt;/p&gt;

&lt;p&gt;No other languages have joined JavaScript/TypeScript yet, but we've already made the CFG extensible: the core engine doesn't depend on any specific language. We define a set of multiple semantics and just combine them like building blocks into a CFG for a specific language we need. It'll save time when it comes to supporting other languages in the future.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1nv51v8zxi50tn31i7m0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1nv51v8zxi50tn31i7m0.png" alt="1418_js_cfg/image4.png" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here are two examples of language-specific semantics for JavaScript/TypeScript:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;try&lt;/code&gt; blocks in which exceptions are untyped, and only one &lt;code&gt;catch&lt;/code&gt; is allowed.&lt;/li&gt;
&lt;li&gt;Labels are attached to a specific statement, and you can jump to them only from the &lt;code&gt;break&lt;/code&gt; statement nested within that statement. You can also jump to the label using &lt;code&gt;continue&lt;/code&gt; if it is inside a loop.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Testing approach
&lt;/h3&gt;

&lt;p&gt;Checking that a CFG is correct is quite an adventure of its own. The first thing that comes to mind is to serialize the graph in &lt;a href="https://en.wikipedia.org/wiki/Graphviz" rel="noopener noreferrer"&gt;Graphviz&lt;/a&gt; (or some other way), check it visually, and save it as a reference. Spoiler: that was a trap, and we fell into it. Here's why it doesn't work:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The graph changes constantly during development. You end up manually rewriting the failing tests or burning through AI agents' tokens.&lt;/li&gt;
&lt;li&gt;It's very easy to miss a bug in the reference. If people didn't make mistakes, the static analysis industry wouldn't exist.&lt;/li&gt;
&lt;li&gt;A neat-looking topology doesn't guarantee that the graph captures the full semantics of the control flow.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So we changed the approach and wrote a mini-interpreter for our CAT, driven by the CFG. The idea is simple: if our interpreter, after traversing the graph, produces the same result as the JavaScript interpreter, the graph is constructed correctly. We verify this with a simple assertion API, like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="n"&gt;Test&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;branching&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;EvaluationAssert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;evaluate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"branching"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;withParam&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"param"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"a"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;EvaluationAssert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;evaluate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"branching"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;withParam&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"param"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"a"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This test runs the interpreter and compares the execution results with the reference, which you can get by running the TypeScript code beforehand:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;branching&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;param&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;let&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;param&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We didn't have to implement the entire JavaScript specification—a tiny subset was enough. Cutting corners actually worked in our favor: if you don't clear variables when they go out of scope, you can inspect the state of the code at different points.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fx5z9cohoov6ho8trmcct.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fx5z9cohoov6ho8trmcct.png" alt="1418_js_cfg/image5.png" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Another nice bonus: the minimalist interpreter is a full-fledged proof of concept for graph processing. It can serve both as a reference for using the API and as groundwork for upcoming data-flow analysis.&lt;/p&gt;

&lt;p&gt;The result is a working graph builder for JavaScript/TypeScript that constructs each graph in a single AST traversal. It's quite fast: for &lt;a href="https://www.google.com/search?client=firefox-b-d&amp;amp;q=react&amp;amp;sei=_ymVao7PAuev5NoPzafroAY" rel="noopener noreferrer"&gt;React&lt;/a&gt;, all graphs are built in a quarter of a second.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it can catch today
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Linear code
&lt;/h3&gt;

&lt;p&gt;The most basic typos, the kind the AST could catch too, come first, of course:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;curveLengths&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;diff&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;curveLengths&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;curve&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;curves&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="n"&gt;var&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;diff&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;curve&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getLength&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;curve&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getPointAt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The PVS-Studio warning: &lt;a href="https://pvs-studio.com/en/docs/warnings/v7039/" rel="noopener noreferrer"&gt;V7039&lt;/a&gt; Unreachable code detected. Control flow never reaches this statement. &lt;a href="https://github.com/juice-shop/juice-shop/blob/1618a611b173b4bf114028e6e02549950606e29d/frontend/src/assets/private/three.js#L29417" rel="noopener noreferrer"&gt;three.js 29417&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;That's the graph built by the analyzer:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvde0qpy2n2qllh8x1bt9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvde0qpy2n2qllh8x1bt9.png" alt="1418_js_cfg/image6.png" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;
  What are merge nodes?
  &lt;br&gt;
A merge node is an auxiliary node used during graph construction. It makes the graph easier to work with, because nodes with multiple predecessors are cumbersome to handle. The analysis doesn't use merge nodes (yet). 

&lt;p&gt;In the example above, the merge has only one incoming edge instead of two, as in the previous scheme, because the &lt;code&gt;true&lt;/code&gt; branch contains a &lt;code&gt;return&lt;/code&gt;, which requires an edge to be created straight to the exit node. &lt;/p&gt;



&lt;p&gt;&lt;/p&gt;

&lt;p&gt;The graph shows clearly no path lead to &lt;code&gt;break&lt;/code&gt;, so the analyzer marks it as unreachable. &lt;/p&gt;

&lt;p&gt;It's unlikely that this error has any effect, and the unreachable &lt;code&gt;break&lt;/code&gt; is probably just redundant. But here's the interesting part: this file is the &lt;a href="https://github.com/mrdoob/three.js/" rel="noopener noreferrer"&gt;Three.js&lt;/a&gt; library, copied into &lt;a href="https://github.com/juice-shop/juice-shop/" rel="noopener noreferrer"&gt;Juice Shop&lt;/a&gt;, and we couldn't find the same error in the current Three.js repository.&lt;/p&gt;

&lt;p&gt;By the way, here's a classic bug involving automatic semicolon insertion (ASI):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="c1"&gt;// asi happens here&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bar&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The analyzer catches it the same way. The inserted &lt;code&gt;;&lt;/code&gt; creates a terminator in the block containing the &lt;code&gt;return&lt;/code&gt; and moves &lt;code&gt;this.bar&lt;/code&gt; to the next block:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fsbticptxa0qnl49ahtu5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fsbticptxa0qnl49ahtu5.png" alt="1418_js_cfg/image7.png" width="798" height="262"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Conditions
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/phaserjs/phaser" rel="noopener noreferrer"&gt;Phaser&lt;/a&gt; gives us a good example of "defensive programming":&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;childA&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parentContainer&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;childB&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parentContainer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;displayList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getIndex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;childB&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;displayList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getIndex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;childA&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="nf"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;childA&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parentContainer&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="n"&gt;childB&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parentContainer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="c1"&gt;// more branches ending with return statements here&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;var&lt;/span&gt; &lt;span class="n"&gt;listA&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;childA&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getIndexList&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;var&lt;/span&gt; &lt;span class="n"&gt;listB&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;childB&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getIndexList&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;var&lt;/span&gt; &lt;span class="n"&gt;len&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;listA&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;listB&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;var&lt;/span&gt; &lt;span class="n"&gt;indexA&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;listA&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
        &lt;span class="n"&gt;var&lt;/span&gt; &lt;span class="n"&gt;indexB&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;listB&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;indexA&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="n"&gt;indexB&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;continue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;indexB&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;indexA&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;listB&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;length&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;listA&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;//  Technically this shouldn't happen, but ...&lt;/span&gt;
&lt;span class="c1"&gt;// eslint-disable-next-line no-unreachable&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The PVS-Studio warning: &lt;a href="https://pvs-studio.com/en/docs/warnings/v7039/" rel="noopener noreferrer"&gt;V7039&lt;/a&gt; Unreachable code detected. Control flow never reaches this statement. &lt;a href="https://github.com/phaserjs/phaser/blob/02d8931b626d9764c133cbb3fbf99966c03c757c/src/input/InputPlugin.js#L2981" rel="noopener noreferrer"&gt;InputPlugin.js 2981&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There were more &lt;code&gt;else-if&lt;/code&gt; branches, but I removed them to keep the example short and to the graph small:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F70khqudzojphu4lf16z3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F70khqudzojphu4lf16z3.png" alt="1418_js_cfg/image9.png" width="800" height="555"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you peruse the comment and look at the code, the programmers' concern starts making sense: the logic above is complex, merging more than 5 branches, each of which terminates the execution flow. Devs decided to play it safe, not even trusting ESLint. Following its trail, the analyzer saw from the graph's topology that there is simply no path to &lt;code&gt;return 0&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Loops
&lt;/h3&gt;

&lt;p&gt;As a bonus, we also get the ability to identify loops that run infinitely or, conversely, only once. I found such a case in the already mentioned Three.js:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="nl"&gt;loop:&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var&lt;/span&gt; &lt;span class="n"&gt;pos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;pos&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;pos&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(;&lt;/span&gt; &lt;span class="n"&gt;pos&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;pos&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;                 &lt;span class="c1"&gt;// &amp;lt;=&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;needleLength&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;haystack&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;pos&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="n"&gt;needle&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;continue&lt;/span&gt; &lt;span class="n"&gt;loop&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;pos&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The PVS-Studio warning: &lt;a href="https://pvs-studio.com/en/docs/warnings/v7039/" rel="noopener noreferrer"&gt;V7039&lt;/a&gt; Unreachable code detected. Control flow never reaches this statement. &lt;a href="https://github.com/mrdoob/three.js/blob/aa625d502d4920a84975c80a6438c108678fb4ac/examples/jsm/libs/opentype.module.js#L6109" rel="noopener noreferrer"&gt;opentype.module.js 6109&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Here is the control flow graph:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhezcj7ih79480niueo53.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhezcj7ih79480niueo53.png" alt="1418_js_cfg/image10.png" width="800" height="725"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The diagnostic rule warns that the increment of the &lt;code&gt;pos&lt;/code&gt; variable in the loop is unreachable. Looking at the code, you can easily see that all the branches indeed terminate the second &lt;code&gt;for&lt;/code&gt; loop, so it runs only once. The graph confirms this—there is no path to the increment.&lt;/p&gt;

&lt;p&gt;This code originally came from &lt;a href="https://github.com/opentypejs/opentype.js" rel="noopener noreferrer"&gt;OpenType&lt;/a&gt;, but the copied dependency was removed at the time of the writing.&lt;/p&gt;

&lt;h3&gt;
  
  
  Exception handling
&lt;/h3&gt;

&lt;p&gt;Nested &lt;code&gt;try&lt;/code&gt; blocks and execution flow interruptions from &lt;code&gt;finally&lt;/code&gt; are rare andoften considered a code smell, so I couldn't find any instances in open-source code right away.&lt;/p&gt;

&lt;p&gt;Still, this was one of the trickiest cases to handle due to the complexity of the &lt;code&gt;try-catch-finally&lt;/code&gt; semantics. The analyzer has to handle several things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Check if the &lt;code&gt;try&lt;/code&gt; block contains a &lt;code&gt;catch&lt;/code&gt;, a &lt;code&gt;finally&lt;/code&gt;, or both;&lt;/li&gt;
&lt;li&gt;Track explicit &lt;code&gt;throw&lt;/code&gt; statements and also handle where implicit exceptions lead.&lt;/li&gt;
&lt;li&gt;Override the control flow interruption within the &lt;code&gt;finally&lt;/code&gt; block when the control flow interruption occurs in &lt;code&gt;try&lt;/code&gt; or &lt;code&gt;catch&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Propagate the control flow interruption that occurs in &lt;code&gt;finally&lt;/code&gt; up through the &lt;code&gt;try&lt;/code&gt; block. &lt;/li&gt;
&lt;li&gt;Cover many other edge cases and their combinations.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Since I still want to show this case, here's a synthetic example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;tryCatchFinallyCase&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Whoops"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="n"&gt;finally&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"inner"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt; &lt;span class="c1"&gt;// V7039&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="n"&gt;finally&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"outer"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// V7039&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For this function, the analyzer will construct the following graph:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjh1f7p0gkjv1flxlzqso.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjh1f7p0gkjv1flxlzqso.png" alt="1418_js_cfg/image11.png" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The diagram clearly shows that the edges themselves carry information about which operation they "remembered" before exiting the function. The analyzer also identifies the unreachable &lt;code&gt;return&lt;/code&gt; nodes. &lt;/p&gt;

&lt;h2&gt;
  
  
  What's next?
&lt;/h2&gt;

&lt;p&gt;We've walked through the errors that the analyzer can now detect thanks to control flow graph support. It has already proven its capabilities, making it fairly straightforward to implement diagnostic rules &lt;a href="https://pvs-studio.com/en/docs/warnings/v7039/" rel="noopener noreferrer"&gt;V7039&lt;/a&gt; (unreachable code) and &lt;a href="https://pvs-studio.com/en/docs/warnings/v7040/" rel="noopener noreferrer"&gt;V7040&lt;/a&gt; (infinite recursion) by the time PVS-Studio 8.00 was released. Beyond adding new diagnostic rules, other opportunities are opening up:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Extend the CFG construction by applying it to short-circuit expressions.&lt;/li&gt;
&lt;li&gt;Find dead code as well as unreachable code, using conditional constant propagation. Once we have laid the groundwork for the data-flow analysis engine, we can implement &lt;a href="https://pvs-studio.com/en/blog/terms/6496/" rel="noopener noreferrer"&gt;taint analysis&lt;/a&gt; (tracking tainted data throughout the program).&lt;/li&gt;
&lt;li&gt;Extend the same engine to other kinds of &lt;a href="https://pvs-studio.com/en/blog/terms/7004/" rel="noopener noreferrer"&gt;data-flow analysis&lt;/a&gt;, such as detecting null dereference, division by zero, and so on.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In short, CAT grows the analyzer wider, and the CFG lets us grow it deeper. The ground for developing the new analyzer is now even more productive.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrap-up
&lt;/h2&gt;

&lt;p&gt;That's the end of the brief overview of the analyzer's technology. I hope you enjoyed seeing how static analysis works and what kinds of errors control flow analysis can find. If you've worked with similar technologies, share your experience in the comments. I'd love to read your stories. The promised article on the inner workings of CAT is still on the way, along with more articles on code quality. Follow us to stay tuned:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;PVS-Studio in &lt;a href="https://x.com/pvs_studio" rel="noopener noreferrer"&gt;X&lt;/a&gt;;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://pvs-studio.com/en/subscribe/" rel="noopener noreferrer"&gt;monthly newsletter&lt;/a&gt;;&lt;/li&gt;
&lt;li&gt;my personal &lt;a href="https://twitter.com/kvolokhovskii" rel="noopener noreferrer"&gt;blog&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>javascript</category>
      <category>programming</category>
    </item>
    <item>
      <title>Go vet can't go: How to create your own Go analyzer?—Key points</title>
      <dc:creator>Unicorn Developer</dc:creator>
      <pubDate>Thu, 08 Oct 2026 11:48:24 +0000</pubDate>
      <link>https://dev.to/pvsdev/go-vet-cant-go-how-to-create-your-own-go-analyzer-key-points-f3b</link>
      <guid>https://dev.to/pvsdev/go-vet-cant-go-how-to-create-your-own-go-analyzer-key-points-f3b</guid>
      <description>&lt;p&gt;In this live talk, PVS-Studio's Developer Advocate walks through Go's built-in tools and code-parsing capabilities, explains the basics of static analysis, unpacks what a semantic model is, shows how to build a syntax tree, and much more.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why build a custom analyzer?
&lt;/h2&gt;

&lt;p&gt;Go already includes static analysis via go vet, but it can't detect every issue. Real-world projects contain errors that may look obvious to a developer yet remain invisible to standard tools. Other tools can also produce false positives or miss errors. A custom analyzer lets you focus on problems specific to your code and control exactly what the tool checks. The trade-off is that it needs to be maintained and tested. The diagnostic rules also need to be refined to minimize false positives and negatives.&lt;/p&gt;

&lt;h2&gt;
  
  
  Syntax and semantics
&lt;/h2&gt;

&lt;p&gt;Static analysis relies on two main sources of information: syntax and semantics. The syntax tree shows the code structure and can reveal issues based on this structure. However, some cases require understanding what expressions and identifiers mean. Go/types provide this semantic information, including expression types and the declarations they refer to.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building an analyzer
&lt;/h2&gt;

&lt;p&gt;The Go analysis framework handles routine work such as collecting files, parsing them, and checking types. The analysis pass provides parsed files, type information, the current package, diagnostic rules, and source positions. A rule can then traverse the syntax tree, inspect relevant nodes, and report issues to the user.&lt;/p&gt;

&lt;h2&gt;
  
  
  From rule to diagnostic
&lt;/h2&gt;

&lt;p&gt;The speaker demonstrates this process with a rule that detects empty &lt;code&gt;if&lt;/code&gt; statements and then applies the same approach to a more complex value-receiver case. The result is a custom diagnostic rule tailored to a specific problem that existing tools may miss.&lt;/p&gt;

&lt;h2&gt;
  
  
  Want more?
&lt;/h2&gt;

&lt;p&gt;If you want to watch the full talk, follow this &lt;a href="https://pvs-studio.com/en/blog/video/11828/" rel="noopener noreferrer"&gt;link&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;And if you'd like to learn more about PVS-Studio analyzer, check out our &lt;a href="https://pvs-studio.com/en/" rel="noopener noreferrer"&gt;website&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;See ya!&lt;/p&gt;

</description>
      <category>go</category>
      <category>webinar</category>
      <category>programming</category>
    </item>
    <item>
      <title>I found some bugs in Create mod and checked them in Minecraft</title>
      <dc:creator>Unicorn Developer</dc:creator>
      <pubDate>Tue, 29 Sep 2026 13:29:42 +0000</pubDate>
      <link>https://dev.to/pvsdev/i-found-some-bugs-in-create-mod-and-checked-them-in-minecraft-2cbk</link>
      <guid>https://dev.to/pvsdev/i-found-some-bugs-in-create-mod-and-checked-them-in-minecraft-2cbk</guid>
      <description>&lt;p&gt;This article covers bugs in Create, one of the most popular Minecraft mods. Let's see how they impact the game and then submit pull requests with the necessary fixes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvxhx3qbwtnjyfouq4sjh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvxhx3qbwtnjyfouq4sjh.png" alt="1417_Create/image1.png" width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://modrinth.com/mod/create" rel="noopener noreferrer"&gt;Create&lt;/a&gt; is a Minecraft mod that adds shafts, gears, and other mechanical components. You can combine them to build machines powered by rotational force, from a simple windmill to a fully automated &lt;a href="https://www.youtube.com/watch?v=rR8W-f9YhYA" rel="noopener noreferrer"&gt;cake factory&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The mod is hugely popular: it has more than 206 million &lt;a href="https://www.curseforge.com/minecraft/mc-mods/create" rel="noopener noreferrer"&gt;downloads on CurseForge&lt;/a&gt; alone. That doesn't even include &lt;a href="https://modrinth.com/mod/create" rel="noopener noreferrer"&gt;Modrinth&lt;/a&gt;, and the mod keeps getting updates for new versions of the game. I'm pretty sure almost everyone who opened the article has played this mod. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fepukcd2je4wlo2xmc2di.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fepukcd2je4wlo2xmc2di.png" alt="1417_Create/image2.png" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Let's check the project
&lt;/h2&gt;

&lt;p&gt;&lt;/p&gt;
  Some important info
  &lt;ul&gt;
&lt;li&gt;To check the project, I used PVS-Studio static analyzer. The article author is one of its developers.&lt;/li&gt;
&lt;li&gt;You'll see code examples as you read. Most of them have been shortened to avoid overwhelming the reader. I've also put an ellipsis to mark the shortened code: "....".&lt;/li&gt;
&lt;li&gt;At the time of the check, the latest revision was the &lt;a href="https://github.com/Creators-of-Create/Create/tree/87b3c6a65fd00c023a07b37b0353144bc7e6a5bf" rel="noopener noreferrer"&gt;87b3c6a&lt;/a&gt; commit. I checked it using the static analyzer.&lt;/li&gt;
&lt;li&gt;All analyzed source files and any conclusions based on other source files, include a permanent link that you can use to find them.&lt;/li&gt;
&lt;li&gt;The article includes only the bugs that the author found interesting (yes, it's a matter of personal taste). If you want to see the rest, you can always download the analyzer and check the project yourself.&lt;/li&gt;
&lt;/ul&gt;



&lt;p&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Ctrl + V doesn't work
&lt;/h3&gt;

&lt;p&gt;The &lt;a href="https://github.com/Creators-of-Create/Create/blob/0924e93639ad5f61cfc39a221d909e16f2893df1/src/main/java/com/simibubi/create/content/schematics/client/SchematicEditScreen.java#L130" rel="noopener noreferrer"&gt;SchematicEditScreen.java(130)&lt;/a&gt; file&lt;/p&gt;

&lt;p&gt;Let's take a look at the menu for pasting a schematic.&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;
  What's a schematic?
  &lt;br&gt;
A schematic is a part of the game world saved as a separate file. This lets you move your house from one world to another, for example.



&lt;br&gt;
&lt;p&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;keyPressed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;....)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;isPaste&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;coords&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;minecraft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keyboardHandler&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getClipboard&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;coords&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;null&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;coords&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isEmpty&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;coords&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;replaceAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;" "&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;             &lt;span class="c1"&gt;// &amp;lt;=&lt;/span&gt;
      &lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;split&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;coords&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;","&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;length&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;boolean&lt;/span&gt; &lt;span class="n"&gt;valid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;Integer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parseInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;NumberFormatException&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;valid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;valid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="n"&gt;xInput&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
          &lt;span class="n"&gt;yInput&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
          &lt;span class="n"&gt;zInput&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
          &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;....&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The PVS-Studio warning:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://pvs-studio.com/en/docs/warnings/v6010/" rel="noopener noreferrer"&gt;V6010&lt;/a&gt; The return value of function 'replaceAll' is required to be utilized. SchematicEditScreen.java 130&lt;/p&gt;

&lt;p&gt;The idea is simple: the player copies the coordinates, presses Ctrl + V in a dedicated window, and the fields fill in automatically.&lt;/p&gt;

&lt;p&gt;But the &lt;code&gt;replaceAll&lt;/code&gt; call marked &lt;code&gt;// &amp;lt;=&lt;/code&gt; serves no purpose. Strings in Java are immutable, so the method doesn't modify the original string; it returns a new one instead. The new string is immediately discarded, leaving the spaces instead.&lt;/p&gt;

&lt;p&gt;The code then splits the string by commas, leaving a space at the beginning of the second and third elements, and &lt;code&gt;Integer.parseInt(" 67")&lt;/code&gt; throws a &lt;a href="https://docs.oracle.com/javase/8/docs/api/java/lang/NumberFormatException.html" rel="noopener noreferrer"&gt;&lt;code&gt;NumberFormatException&lt;/code&gt;&lt;/a&gt;. As a result, the fields remain empty.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F86f9wkzjz8sb04jpuqh3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F86f9wkzjz8sb04jpuqh3.png" alt="1417_Create/image3.png" width="800" height="428"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After opening the menu, I saw the expected behavior:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;-156, 67, 204&lt;/code&gt; doesn't work;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-156,67,204&lt;/code&gt; works.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The fix fits on a single line. We just add an assignment before the &lt;code&gt;replaceAll&lt;/code&gt; operation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;coords&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;coords&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;replaceAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;" "&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Unnecessary maximum
&lt;/h3&gt;

&lt;p&gt;The &lt;a href="https://github.com/Creators-of-Create/Create/blob/0924e93639ad5f61cfc39a221d909e16f2893df1/src/main/java/com/simibubi/create/content/trains/schedule/ScheduleScreen.java#L557" rel="noopener noreferrer"&gt;ScheduleScreen.java(557)&lt;/a&gt; file&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ScheduleWaitCondition&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;conditions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;maxWidth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;getConditionColumnWidth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;ScheduleWaitCondition&lt;/span&gt; &lt;span class="n"&gt;scheduleWaitCondition&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;maxWidth&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;renderInput&lt;/span&gt;&lt;span class="p"&gt;(....));&lt;/span&gt;   &lt;span class="c1"&gt;// &amp;lt;=&lt;/span&gt;
    &lt;span class="n"&gt;scheduleWaitCondition&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;renderSpecialIcon&lt;/span&gt;&lt;span class="p"&gt;(....);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="n"&gt;AllGuiTextures&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SCHEDULE_CONDITION_APPEND&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;graphics&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="n"&gt;xOffset&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;maxWidth&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="mi"&gt;29&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;18&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;xOffset&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;maxWidth&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The PVS-Studio warning:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://pvs-studio.com/en/docs/warnings/v6010/" rel="noopener noreferrer"&gt;V6010&lt;/a&gt; The return value of function 'max' is required to be utilized. ScheduleScreen.java 557&lt;/p&gt;

&lt;p&gt;The analyzer warning clearly explains the error: the result of the &lt;code&gt;Math.max(....)&lt;/code&gt; call isn't written anywhere. &lt;/p&gt;

&lt;p&gt;I looked through the commit history, expecting to find some traces of refactoring. I thought the developers might have moved the width calculation to a separate method and removed the assignment to &lt;code&gt;maxWidth&lt;/code&gt; but left the &lt;code&gt;Math#max&lt;/code&gt; call untouched. There was nothing like that, though. The file first appeared on February 1, 2022, in a &lt;a href="https://github.com/Creators-of-Create/Create/commit/576d00d3a0e502d418488ef463ad7eb4237560ab#diff-59b447844d14ec067c0449bccbecf6179277ee5603f60cc4cb682911967f0bc8" rel="noopener noreferrer"&gt;single 941-line commit&lt;/a&gt;, and the &lt;code&gt;Math#max&lt;/code&gt; call without an assignment had been there all along. The original initialization of &lt;code&gt;maxWidth&lt;/code&gt; with a call to &lt;code&gt;getConditionColumnWidth()&lt;/code&gt; was there too.&lt;/p&gt;

&lt;p&gt;What would change if the devs added &lt;code&gt;maxWidth = Math.max(....)&lt;/code&gt;? Nothing. The column width where the text appears (see the image below) is calculated in advance with some extra room: &lt;code&gt;getConditionColumnWidth()&lt;/code&gt; goes through the entire column and takes the maximum width, so no line can extend beyond it. I checked this using the debugger: in every case I was able to test, it returned the same width. So, the code is searching for the maximum of two identical numbers.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2esdg9vuu69hek5cwfeg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2esdg9vuu69hek5cwfeg.png" alt="1417_Create/image4.png" width="800" height="428"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The line didn't break over time, nor was it affected by any refactoring. From day one, it had done nothing—for four years and through several updates to newer Minecraft versions.&lt;/p&gt;

&lt;p&gt;I'd suggest removing the unnecessary wrapper and leaving &lt;code&gt;renderInput&lt;/code&gt; on its own.&lt;/p&gt;

&lt;h3&gt;
  
  
  Ignore error handling
&lt;/h3&gt;

&lt;p&gt;The &lt;a href="https://github.com/Creators-of-Create/Create/blob/0924e93639ad5f61cfc39a221d909e16f2893df1/src/main/java/com/simibubi/create/content/kinetics/crafter/MechanicalCrafterBlockEntity.java#L535" rel="noopener noreferrer"&gt;MechanicalCrafterBlockEntity.java(535)&lt;/a&gt; file&lt;/p&gt;

&lt;p&gt;First of all, let me show you what the mechanical crafter looks like:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fx81148burhwvnszks1g9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fx81148burhwvnszks1g9.png" alt="1417_Create/image5.png" width="800" height="428"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;
  Image explanation
  &lt;br&gt;
In vanilla Minecraft, players craft items at a crafting table by manually placing ingredients in specific slots. A mechanical crafter does the same thing automatically. You build a grid from several blocks, with each block corresponding to one slot in the recipe, and place the required ingredient in each one. The screenshot shows the recipe for an iron pickaxe: three ingots in the top row and two sticks down the middle.

&lt;p&gt;The arrows on the front indicate the route. The crafters pass items from one to another along the chain until everything reaches the final block. That's where the recipe gets assembled, and the finished item moves on to a conveyor belt or into a chest.&lt;/p&gt;

&lt;p&gt;The whole system runs on rotational power, so it needs a drive connected to the side. In the screenshot, a creative motor powers the grid.&lt;/p&gt;



&lt;p&gt;&lt;/p&gt;

&lt;p&gt;Let's take a look at a method in its logic:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;continueIfAllPrecedingFinished&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;MechanicalCrafterBlockEntity&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;preceding&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; 
    &lt;span class="n"&gt;RecipeGridHandler&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getPrecedingCrafters&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;preceding&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;// &amp;lt;=&lt;/span&gt;
    &lt;span class="n"&gt;ejectWholeGrid&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MechanicalCrafterBlockEntity&lt;/span&gt; &lt;span class="n"&gt;blockEntity&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;preceding&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;blockEntity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;phase&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;Phase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WAITING&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="n"&gt;phase&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Phase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ASSEMBLING&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;countDown&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The PVS-Studio warning:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://pvs-studio.com/en/docs/warnings/v6007/" rel="noopener noreferrer"&gt;V6007&lt;/a&gt; Expression 'preceding == null' is always false. New returns not-null reference. MechanicalCrafterBlockEntity.java 535&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;getPrecedingCrafters&lt;/code&gt; method returns the crafters that come earlier in the chain. In other words, the ones that feed items into the current crafter. It can never return &lt;code&gt;null&lt;/code&gt;. A list is created at the start, and both method exits return it. Even if the block isn't a crafter, the method returns an empty list:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;MechanicalCrafterBlockEntity&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;getPrecedingCrafters&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;MechanicalCrafterBlockEntity&lt;/span&gt; &lt;span class="n"&gt;crafter&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;BlockPos&lt;/span&gt; &lt;span class="n"&gt;pos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;crafter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getBlockPos&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="n"&gt;Level&lt;/span&gt; &lt;span class="n"&gt;world&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;crafter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getLevel&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;MechanicalCrafterBlockEntity&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;crafters&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;ArrayList&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="n"&gt;BlockState&lt;/span&gt; &lt;span class="n"&gt;blockState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;crafter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getBlockState&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;isCrafter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;blockState&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;crafters&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="p"&gt;....&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;crafters&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This means the branch with &lt;code&gt;ejectWholeGrid()&lt;/code&gt; is unreachable.  The &lt;code&gt;preceding&lt;/code&gt; list can never be &lt;code&gt;null&lt;/code&gt;, but it can be empty, and often is. What if we replace the check with &lt;code&gt;isEmpty()&lt;/code&gt; and test it in the game? Let's see what happens.&lt;/p&gt;

&lt;p&gt;Before the fix:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fe56epbgnosl4m2pzkzgp.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fe56epbgnosl4m2pzkzgp.gif" alt="1417_Create/image6.gif" width="480" height="253"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After the fix with &lt;code&gt;isEmpty&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4e19b4kq954irv4kuk38.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4e19b4kq954irv4kuk38.gif" alt="1417_Create/image7.gif" width="600" height="314"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The video shows that, before the fix, items entering the loop were passed from one crafter to another indefinitely. That could potentially cause trouble and break someone's factory :)&lt;/p&gt;

&lt;p&gt;However, after the check was replaced with &lt;code&gt;isEmpty()&lt;/code&gt;, the loop didn't even have a chance to form. The method determined that there was nowhere else to expect items from, so it ejected them.&lt;/p&gt;

&lt;p&gt;However, as soon as I added two more crafters to the chain, the fix stopped working:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fd2vs9nnzk5j087hjol2r.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fd2vs9nnzk5j087hjol2r.gif" alt="1417_Create/image8.gif" width="200" height="107"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Two options are possible here. Either the mechanical crafter needs to detect loops differently, then simply replacing the check with &lt;code&gt;isEmpty()&lt;/code&gt; isn't enough. Or this looping behavior isn't a bug at all. In that case, we can just remove the &lt;code&gt;null&lt;/code&gt; check.&lt;/p&gt;

&lt;h3&gt;
  
  
  The logging crash
&lt;/h3&gt;

&lt;p&gt;The &lt;a href="https://github.com/Creators-of-Create/Create/blob/0924e93639ad5f61cfc39a221d909e16f2893df1/src/main/java/com/simibubi/create/content/trains/entity/TrainRelocationPacket.java#L52" rel="noopener noreferrer"&gt;TrainRelocationPacket.java(52)&lt;/a&gt; file&lt;/p&gt;

&lt;p&gt;Here's the client-server train movement package handler:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ServerPlayer&lt;/span&gt; &lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;Train&lt;/span&gt; &lt;span class="n"&gt;train&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RAILWAYS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;trains&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;trainId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;Entity&lt;/span&gt; &lt;span class="n"&gt;entity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;getEntity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;entityId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;messagePrefix&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getName&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getString&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;" could not relocate Train "&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;train&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;null&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="c1"&gt;// &amp;lt;=&lt;/span&gt;
    &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;entity&lt;/span&gt; &lt;span class="n"&gt;instanceof&lt;/span&gt; &lt;span class="n"&gt;CarriageContraptionEntity&lt;/span&gt; &lt;span class="n"&gt;cce&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LOGGER&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;warn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;messagePrefix&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;train&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;substring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;": not present on server"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;train&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;equals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cce&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;trainId&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="p"&gt;....&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The PVS-Studio warning:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://pvs-studio.com/en/docs/warnings/v6008/" rel="noopener noreferrer"&gt;V6008&lt;/a&gt; Potential null dereference of 'train'. TrainRelocationPacket.java 52&lt;/p&gt;

&lt;p&gt;The condition triggers in two cases: either the train can't be found, or the entity is of the wrong class. The second case is fine: it logs a proper warning. However, in the first case, the code accesses &lt;code&gt;train.id&lt;/code&gt; when &lt;code&gt;train&lt;/code&gt; is &lt;code&gt;null&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The funny part is that the message we're trying to log ends with &lt;code&gt;not present on server&lt;/code&gt;. The branch was created for a missing train, but it fails because of it.&lt;/p&gt;

&lt;p&gt;The packet comes from the client, meaning it chooses the train ID. A modified client build can send requests to transfer nonexistent trains and make the server fill its log with stack traces.&lt;/p&gt;

&lt;p&gt;The server won't crash: Create registers its packets so they execute safely, and even if an exception occurs, it gets logged, while the packet simply goes unhandled.&lt;/p&gt;

&lt;p&gt;We can fix this by including the identifier in the package:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;messagePrefix&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;trainId&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;substring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The two-state theory
&lt;/h3&gt;

&lt;p&gt;The &lt;a href="https://github.com/Creators-of-Create/Create/blob/0924e93639ad5f61cfc39a221d909e16f2893df1/src/main/java/com/simibubi/create/content/kinetics/mixer/MechanicalMixerBlockEntity.java#L238" rel="noopener noreferrer"&gt;MechanicalMixerBlockEntity.java(238)&lt;/a&gt; file&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Recipe&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;?&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;getMatchingRecipes&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Recipe&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;?&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;matchingRecipes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getMatchingRecipes&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;  
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;AllConfigs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;recipes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;allowBrewingInMixer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;matchingRecipes&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="n"&gt;Optional&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;BasinBlockEntity&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;basin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;getBasin&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;basin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isPresent&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;matchingRecipes&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="n"&gt;BasinBlockEntity&lt;/span&gt; &lt;span class="n"&gt;basinBlockEntity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;basin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;basin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isEmpty&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="c1"&gt;// &amp;lt;= &lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;matchingRecipes&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="n"&gt;IItemHandler&lt;/span&gt; &lt;span class="n"&gt;availableItems&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getCapability&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;Capabilities&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ItemHandler&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BLOCK&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
  &lt;span class="n"&gt;basinBlockEntity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getBlockPos&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;null&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;availableItems&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;matchingRecipes&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;availableItems&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getSlots&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;....&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;matchingRecipes&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The PVS-Studio warning:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://pvs-studio.com/en/docs/warnings/v6007/" rel="noopener noreferrer"&gt;V6007&lt;/a&gt; Expression 'basin.isEmpty()' is always true. MechanicalMixerBlockEntity.java 238&lt;/p&gt;

&lt;p&gt;Here, &lt;code&gt;basin.isEmpty()&lt;/code&gt; can never return &lt;code&gt;true&lt;/code&gt;, so &lt;code&gt;return&lt;/code&gt; in this branch is unreachable. Most likely, the developers meant to check &lt;code&gt;basinBlockEntity&lt;/code&gt; rather than &lt;code&gt;Optional&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This doesn't affect gameplay in any way. Further down, the code has other checks that work with the same block, and if the basin is empty, either the loop doesn't run or &lt;code&gt;availableItems&lt;/code&gt; is &lt;code&gt;null&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;But a dead &lt;code&gt;if&lt;/code&gt; is more dangerous than it looks. It's a safeguard that doesn't really protect against anything. Rewriting the checks below leaves a hole that no one will think to look for because the check is kind of there.&lt;/p&gt;

&lt;h3&gt;
  
  
  Method contracts must be followed
&lt;/h3&gt;

&lt;p&gt;The &lt;a href="https://github.com/Creators-of-Create/Create/blob/0924e93639ad5f61cfc39a221d909e16f2893df1/src/main/java/com/simibubi/create/content/contraptions/Contraption.java#L230" rel="noopener noreferrer"&gt;Contraption.java(230)&lt;/a&gt; file&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;Contraption&lt;/span&gt; &lt;span class="nf"&gt;fromNBT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Level&lt;/span&gt; &lt;span class="n"&gt;world&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CompoundTag&lt;/span&gt; &lt;span class="n"&gt;nbt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
                  &lt;span class="n"&gt;boolean&lt;/span&gt; &lt;span class="n"&gt;spawnData&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;nbt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Type"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;Contraption&lt;/span&gt; &lt;span class="n"&gt;contraption&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ContraptionType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fromType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;contraption&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;readNBT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;world&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;nbt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;spawnData&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;....&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Can you see the error? What if we take a look inside &lt;code&gt;ContraptionType#fromType&lt;/code&gt;?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="cm"&gt;/**
 * Lookup the ContraptionType with the given ID, 
 * and create a new Contraption from it if present.
 * If it doesn't exist, returns null.
 */&lt;/span&gt;
&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="n"&gt;Nullable&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;Contraption&lt;/span&gt; &lt;span class="nf"&gt;fromType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;typeId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;ContraptionType&lt;/span&gt; &lt;span class="n"&gt;legacy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;AllContraptionTypes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BY_LEGACY_NAME&lt;/span&gt;
                        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;typeId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;legacy&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;legacy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="n"&gt;ResourceLocation&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ResourceLocation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tryParse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;typeId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;ContraptionType&lt;/span&gt; &lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;CreateBuiltInRegistries&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CONTRAPTION_TYPE&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;null&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;null&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now it's clear. The method explicitly warns about &lt;code&gt;null&lt;/code&gt; twice: with an annotation and a comment. However, the caller code doesn't check anything.&lt;/p&gt;

&lt;p&gt;The PVS-Studio warning:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://pvs-studio.com/en/docs/warnings/v6008/" rel="noopener noreferrer"&gt;V6008&lt;/a&gt; Potential null dereference of 'contraption'. Contraption.java 230&lt;/p&gt;

&lt;p&gt;It's easier to break than it seems. The very first line calls &lt;code&gt;nbt.getString("Type")&lt;/code&gt;, and if the key doesn't exist, an empty string is returned. This type isn't in the registry either, so the code returns &lt;code&gt;null&lt;/code&gt; again.&lt;/p&gt;

&lt;p&gt;We can verify this pretty easily by giving ourselves a minecart with a nonexistent contraption type:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;give&lt;/span&gt; &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;
&lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;minecart_contraption&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;minecart_contraption_data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Type&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="s"&gt;"create:does_not_exist"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;InitialOrientation&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="s"&gt;"north"&lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;/p&gt;
  What's a contraption?
  &lt;br&gt;
A contraption is a structure that the mod detaches from the world and turns into a single movable object: a platform on a minecart, a piston carrying a load, or a rotating bridge. The blocks inside stop being part of the world and are stored as data belonging to a single entity instead.



&lt;p&gt;&lt;/p&gt;

&lt;p&gt;The command won't break anything, and the item will go into the inventory without a problem. But once we put the minecart on the rails, &lt;code&gt;MinecartContraptionItem&lt;/code&gt; will try to build a contraption from this data, and that's where we'll get a &lt;a href="https://gist.github.com/TheLivan/ad251e6a4357230f1181eb59ae06d7c3" rel="noopener noreferrer"&gt;stack trace with &lt;code&gt;NullPointerException&lt;/code&gt;&lt;/a&gt;. Minecraft will replace the player's contraption with a vanilla minecart.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fw4le7qtjt9u72iu5l8zi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fw4le7qtjt9u72iu5l8zi.png" alt="1417_Create/image9.png" width="800" height="428"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can easily add the check:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;Contraption&lt;/span&gt; &lt;span class="n"&gt;contraption&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ContraptionType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fromType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;contraption&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LOGGER&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;warn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Unknown contraption type: {}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But then &lt;code&gt;null&lt;/code&gt; will need to be handled in both code snippets that call it. That raises the question of what to do with a minecart whose contents the mod can no longer understand. Should we leave it as an empty minecart, or simply not load the entity at all? I think it's worth asking the mod developers. They clearly know better than anyone else what to do here.&lt;/p&gt;

&lt;h3&gt;
  
  
  Interruption
&lt;/h3&gt;

&lt;p&gt;The &lt;a href="https://github.com/Creators-of-Create/Create/blob/0924e93639ad5f61cfc39a221d909e16f2893df1/src/main/java/com/simibubi/create/infrastructure/command/ServerLagger.java#L14" rel="noopener noreferrer"&gt;ServerLagger.java(14)&lt;/a&gt; file&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;tick&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;isLagging&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;tickTime&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tickTime&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;InterruptedException&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;printStackTrace&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The PVS-Studio warning:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://pvs-studio.com/en/docs/warnings/v6103/" rel="noopener noreferrer"&gt;V6103&lt;/a&gt; Ignored InterruptedException could lead to delayed thread shutdown. ServerLagger.java 14&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ServerLagger&lt;/code&gt; is a helper class for the &lt;code&gt;killtps start &amp;lt;tickTime&amp;gt;&lt;/code&gt; debug command that puts the server to sleep for the specified number of milliseconds on every tick, allowing to see how the mod behaves when the TPS drops. It's available only in debug builds and only to operators (that's what server administrators are called), so there's no need to worry. However, the code is still incorrect, and it's worth explaining why.&lt;/p&gt;

&lt;p&gt;When the thread is interrupted, &lt;code&gt;sleep&lt;/code&gt; immediately throws an &lt;code&gt;InterruptedException&lt;/code&gt; and also clears the interrupt flag. In other words, after &lt;code&gt;catch&lt;/code&gt;, it seems like nothing's left: no flag, no exception, just a line in &lt;code&gt;System.err&lt;/code&gt;. The method returns control without issue, and the server continues running as if it had never been called.&lt;/p&gt;

&lt;p&gt;An &lt;a href="https://docs.oracle.com/javase/tutorial/essential/concurrency/interrupt.html" rel="noopener noreferrer"&gt;interrupt&lt;/a&gt; is a request for the entire thread to stop, not just the part where you catch it. By interrupting the thread and doing nothing, you take that request and throw it away. The &lt;a href="https://docs.oracle.com/en/java/javase/26/docs/api/java.base/java/lang/InterruptedException.html" rel="noopener noreferrer"&gt;Javadoc&lt;/a&gt; explicitly points this out. One line is enough to pass the interrupt:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;InterruptedException&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;currentThread&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;interrupt&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;That's all for today. I collected all the bugs both in this article and in pull requests for the project's developers (&lt;a href="https://github.com/Creators-of-Create/Create/pull/10696" rel="noopener noreferrer"&gt;click&lt;/a&gt;, &lt;a href="https://github.com/Creators-of-Create/Create/pull/10721" rel="noopener noreferrer"&gt;click&lt;/a&gt;). &lt;/p&gt;

&lt;p&gt;Want to try static analysis too? You can always integrate it into your own project with PVS-Studio. You can download a trial version &lt;a href="https://pvs-studio.com/en/pvs-studio/try-free/?utm_source=website&amp;amp;utm_medium=devto&amp;amp;utm_campaign=article&amp;amp;utm_content=1417" rel="noopener noreferrer"&gt;here&lt;/a&gt;. The license is &lt;a href="https://pvs-studio.com/en/order/open-source-license/" rel="noopener noreferrer"&gt;free for open-source projects&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>java</category>
      <category>gamedev</category>
      <category>minecraft</category>
      <category>programming</category>
    </item>
    <item>
      <title>Let's make a programming language. Functions—Key points</title>
      <dc:creator>Unicorn Developer</dc:creator>
      <pubDate>Wed, 23 Sep 2026 12:35:34 +0000</pubDate>
      <link>https://dev.to/pvsdev/lets-make-a-programming-language-functions-key-points-19p6</link>
      <guid>https://dev.to/pvsdev/lets-make-a-programming-language-functions-key-points-19p6</guid>
      <description>&lt;p&gt;We continue the development of our toy programming language. In this episode, our speaker Yuri demonstrates how to implement functions and explains how functions, scopes, and symbol lookup are built in code using C++. &lt;/p&gt;

&lt;h2&gt;
  
  
  About the speaker
&lt;/h2&gt;

&lt;p&gt;Yuri Minaev is an experienced C++ developer, architect at PVS-Studio, and a recognized voice in the C++ community who has spoken at CppCast, C++ on Sea, and CppCon. Over the course of ten sessions, he'll guide you through each stage of building your own programming language.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introducing scopes
&lt;/h2&gt;

&lt;p&gt;Functions introduce multiple scopes and different levels of name visibility. Unlike variables, which previously existed only in the global scope, functions create their own scope. Names declared inside a function are not visible outside it, while names from parent scopes remain accessible. Compound statements can also create nested scopes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Managing the symbol table
&lt;/h2&gt;

&lt;p&gt;To resolve names, the semantic analyzer uses a symbol table that associates names with their declarators and the scopes where they appear. Two lookup methods are used. An unscoped lookup searches the current scope and then moves upward through parent scopes until it finds the name. A scoped lookup checks only a specified scope. The latter also prevents duplicate names from being declared within the same scope.&lt;/p&gt;

&lt;h2&gt;
  
  
  Parsing functions
&lt;/h2&gt;

&lt;p&gt;A function consists of the &lt;code&gt;fn&lt;/code&gt; keyword, a name, parameters, an optional return type, and a compound statement containing its body. Parameters have a type and a unique name. Functions are parsed in two stages: the declaration is parsed and registered in the symbol table before the body is processed. This allows the function to reference itself recursively.&lt;/p&gt;

&lt;h2&gt;
  
  
  Handling return types
&lt;/h2&gt;

&lt;p&gt;The semantic analyzer determines a function's return type from its return statements when no type is specified. It also checks that return expressions are compatible with the function's return type and adds implicit casts when necessary. An empty function with no return statements gets the &lt;code&gt;void&lt;/code&gt; type. Incompatible return types make the function invalid.&lt;/p&gt;

&lt;p&gt;The talk concludes with functions implemented and introduces the evaluator as the next step.&lt;/p&gt;

&lt;h2&gt;
  
  
  Want more?
&lt;/h2&gt;

&lt;p&gt;If you want to watch other talks, follow this &lt;a href="https://www.youtube.com/playlist?app=desktop&amp;amp;list=PLGVoaOmC1PBw&amp;amp;si=WyndGLWrXYvY75YG" rel="noopener noreferrer"&gt;link&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You can also sign up for our upcoming webinars: &lt;a href="https://pvs-studio.com/en/webinar/34/?utm_source=devto&amp;amp;utm_medium=pvs&amp;amp;utm_campaign=webinar&amp;amp;utm_content=web8" rel="noopener noreferrer"&gt;Let's make a programming language. Evaluator&lt;/a&gt;. We hope to see you there!&lt;/p&gt;

&lt;p&gt;If you'd like to learn more about PVS-Studio analyzer, check out our &lt;a href="https://pvs-studio.com/en/" rel="noopener noreferrer"&gt;website&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;See ya!&lt;/p&gt;

</description>
      <category>cpp</category>
      <category>programming</category>
      <category>webinar</category>
    </item>
    <item>
      <title>Live talk on how to create your own Go analyzer</title>
      <dc:creator>Unicorn Developer</dc:creator>
      <pubDate>Fri, 18 Sep 2026 12:48:45 +0000</pubDate>
      <link>https://dev.to/pvsdev/live-talk-on-how-to-create-your-own-go-analyzer-4b1n</link>
      <guid>https://dev.to/pvsdev/live-talk-on-how-to-create-your-own-go-analyzer-4b1n</guid>
      <description>&lt;p&gt;Static analyzers are powerful tools, and any Go developer who has worked with go vet knows how useful they can be. What happens when the tools you have at your disposal don't catch the most important issues in your projects, though? You could look for another solution... or you could build your own!&lt;/p&gt;

&lt;p&gt;In our upcoming live talk, we'll explore how Go's built-in tools and code-parsing capabilities can help you take the first steps toward creating a static analyzer tailored to your needs.&lt;/p&gt;

&lt;h2&gt;
  
  
  From Go's built-in tools to your own analyzer
&lt;/h2&gt;

&lt;p&gt;A PVS-Studio Developer Advocate will walk you through the foundations needed to understand before building a Go analyzer. We'll start with Go's built-in tools and code-parsing capabilities, then move on to the basics of static analysis. From there, we'll look at what a semantic model is and how it fits into the analysis process. Another important part of the talk will be building a syntax tree. &lt;/p&gt;

&lt;p&gt;The goal of this talk is to bring all the pieces together and show how they can be used to create your own static analyzer. Instead of relying solely on existing tools, you can tailor an analyzer to catch the issues that matter most in your projects.&lt;/p&gt;

&lt;h2&gt;
  
  
  Join us live
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://pvs-studio.com/en/webinar/35/?utm_source=devto&amp;amp;utm_medium=pvs&amp;amp;utm_campaign=webinar&amp;amp;utm_content=go_mistakes2" rel="noopener noreferrer"&gt;Join us&lt;/a&gt; on &lt;strong&gt;September 30, 2026, at 1:00 PM UTC+1&lt;/strong&gt; for &lt;em&gt;"Go vet can't go: How to create your own Go analyzer?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Register for the live talk and start exploring how to create a Go analyzer tailored to your projects!&lt;/p&gt;

</description>
      <category>go</category>
      <category>webinar</category>
      <category>software</category>
      <category>programming</category>
    </item>
    <item>
      <title>PVS-Studio for Go: Quick overview of new diagnostic rules</title>
      <dc:creator>Unicorn Developer</dc:creator>
      <pubDate>Thu, 17 Sep 2026 11:41:35 +0000</pubDate>
      <link>https://dev.to/pvsdev/pvs-studio-for-go-quick-overview-of-new-diagnostic-rules-eej</link>
      <guid>https://dev.to/pvsdev/pvs-studio-for-go-quick-overview-of-new-diagnostic-rules-eej</guid>
      <description>&lt;p&gt;PVS-Studio 8.0 is here! We added support for Go project analysis and much more. This article discusses some of the new diagnostic rules for Go that we developed for the latest version of our analyzer.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4zpi83oul8q6yca1z0ij.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4zpi83oul8q6yca1z0ij.png" alt="1413_New_For_Go/image1.png" width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;PVS-Studio 8.0 officially introduced support for analyzing Go projects, as well as the option to work directly from &lt;a href="https://pvs-studio.com/en/docs/manual/7190/" rel="noopener noreferrer"&gt;GoLand&lt;/a&gt; and &lt;a href="https://pvs-studio.com/en/docs/manual/6646/" rel="noopener noreferrer"&gt;Visual Studio Code&lt;/a&gt; when using Go. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The Visual Studio Code plugin also received a major overhaul. It now supports Go project analysis and all the new analyzers introduced in PVS-Studio 8.0. You can learn about other new features in the &lt;a href="https://pvs-studio.com/en/blog/posts/1406/" rel="noopener noreferrer"&gt;press release&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The new release also added 40 new diagnostic rules for Go to the analyzer. In this article, we'll take a look at some of the most interesting ones, explore different use cases, and compare them with traditional tools. Enjoy the read!&lt;/p&gt;

&lt;h2&gt;
  
  
  Classic errors
&lt;/h2&gt;

&lt;p&gt;We'll start with something that isn't specific to the Go language. Instead, let's focus on more universal and familiar territory: the mistakes that anyone can make when coding or communicating, regardless of the language used.&lt;/p&gt;

&lt;p&gt;I should mention that our approach to the "typical developer mistakes" is somewhat different. In addition to studying Go projects, developer forums, and other resources, we used our "secret weapon" to develop diagnostic rules that detect common issues. &lt;/p&gt;

&lt;p&gt;That's 18 years of experience searching for issues in code :)&lt;/p&gt;

&lt;p&gt;Thanks to this experience in developing analyzers for C, C++, C#, and Java, we've built solid expertise in detecting common mistakes that developers can make regardless of the language they use. This enables us to consider more error cases and scenarios when designing a new analyzer. &lt;/p&gt;

&lt;p&gt;Mistakes like typos, copy-paste errors, and other patterns inherent to human behavior may seem simple...&lt;/p&gt;

&lt;p&gt;Let's look at a few examples.&lt;/p&gt;

&lt;h3&gt;
  
  
  Accessing by constant index within a loop
&lt;/h3&gt;

&lt;p&gt;The example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;sum&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;     &lt;span class="c1"&gt;// &amp;lt;= It should most likely be arr[i]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The PVS-Studio warning: &lt;a href="https://pvs-studio.com/en/docs/warnings/v8008/" rel="noopener noreferrer"&gt;V8008&lt;/a&gt;. Suspicious access to a collection element by a constant index inside a loop.&lt;/p&gt;

&lt;p&gt;This diagnostic rule is interesting because the issue isn't a syntax error, but rather a logical one—a mistake that developers of any skill level can make. &lt;/p&gt;

&lt;p&gt;The index is syntactically valid, so the compiler doesn't report the error, but it remains. Situations like "Oops, I forgot to change &lt;code&gt;i&lt;/code&gt; to &lt;code&gt;j&lt;/code&gt;" or "I forgot that &lt;code&gt;i&lt;/code&gt; even existed" are far more common than you might think. At this point, it becomes a pattern rather than an isolated issue.&lt;/p&gt;

&lt;p&gt;We cover this because we know firsthand that developers make such mistakes! Each of our "classic" analyzers has equivalent rules (&lt;a href="https://pvs-studio.com/en/docs/warnings/v3102/" rel="noopener noreferrer"&gt;V3102&lt;/a&gt; is for C#, &lt;a href="https://pvs-studio.com/en/docs/warnings/v767/" rel="noopener noreferrer"&gt;V767&lt;/a&gt; is for C++, and &lt;a href="https://pvs-studio.com/en/docs/warnings/v6016/" rel="noopener noreferrer"&gt;V6016&lt;/a&gt; is for Java) and includes examples of such mistakes found in popular open-source projects. So, these issues shouldn't be underestimated. You can find examples of errors here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://pvs-studio.com/en/blog/examples/v3102/" rel="noopener noreferrer"&gt;C# examples&lt;/a&gt; (.NET 8, Orleans, PascalABC.NET, etc.);&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://pvs-studio.com/en/blog/examples/v767/" rel="noopener noreferrer"&gt;C++ examples&lt;/a&gt; (Godot Engine, RT-Thread, etc.);&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://pvs-studio.com/en/blog/examples/v6016/" rel="noopener noreferrer"&gt;Java examples&lt;/a&gt; (Apache Solr, Bouncy Castle, Apache Dubbo, etc.).&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Recurring condition check
&lt;/h3&gt;

&lt;p&gt;The example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;A&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;B&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;A&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;B&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;....&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The PVS-Studio warning: &lt;a href="https://pvs-studio.com/en/docs/warnings/v8020/" rel="noopener noreferrer"&gt;V8020&lt;/a&gt;. Recurring check. This condition was already verified on a previous line.&lt;/p&gt;

&lt;p&gt;As you can see, I wasn't lying when I said these mistakes look simple... almost too simple.&lt;/p&gt;

&lt;p&gt;And that's the scary part! You get this strong feeling, "I'd never, ever make a mistake like that. I'm not that silly." Then a fly buzzes by, a bug slips through, a colleague walks over, and suddenly there's a couple of checks doing the same thing.&lt;/p&gt;

&lt;p&gt;Here's a real-world example from the &lt;a href="https://github.com/lxc/incus" rel="noopener noreferrer"&gt;Incus&lt;/a&gt; project, which we covered in one of our &lt;a href="https://pvs-studio.com/en/blog/posts/go/1371/" rel="noopener noreferrer"&gt;articles&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pidPath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;err2&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Stop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;        &lt;span class="c1"&gt;// &amp;lt;= It looks like it should be err2&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"...: %s: %s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The PVS-Studio warning: &lt;a href="https://pvs-studio.com/en/docs/warnings/v8020/" rel="noopener noreferrer"&gt;V8020&lt;/a&gt; Recurring check. The 'err != nil' condition was already verified on line 407 &lt;a href="https://github.com/lxc/incus/blob/321c40f963e9c1e7b68736fb4941431cccac3d60/internal/server/device/proxy.go#L407" rel="noopener noreferrer"&gt;proxy.go 407&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The second condition should check &lt;code&gt;err2&lt;/code&gt; instead of &lt;code&gt;err&lt;/code&gt;, as &lt;code&gt;err&lt;/code&gt; has already been checked and hasn't changed since.&lt;/p&gt;

&lt;p&gt;However, there's more to it because &lt;code&gt;err2&lt;/code&gt; appears in the error handling:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"....: %s: %s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At first, you might not see anything unusual about this context. Although, the answer is obvious: if a problem occurs while handling errors, it becomes more difficult to detect and fix them.&lt;/p&gt;

&lt;p&gt;Here's one more point worth mentioning. Go's error-handling philosophy follows a simple principle: "an error is a value." The caller must explicitly handle an ordinary value that a function explicitly returns. Such code is common and &lt;a href="https://en.wikipedia.org/wiki/Boilerplate_code" rel="noopener noreferrer"&gt;boilerplate&lt;/a&gt;, so it's easy to make mistakes with it! &lt;/p&gt;

&lt;p&gt;We designed one of our new diagnostic rules with this particular aspect of Go in mind:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://pvs-studio.com/en/docs/warnings/v8023/" rel="noopener noreferrer"&gt;V8023&lt;/a&gt;. It is possible that a wrong variable of the 'error' type is checked for 'nil'.&lt;/p&gt;

&lt;p&gt;The example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;func&lt;/span&gt; &lt;span class="n"&gt;processOrder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;orderID&lt;/span&gt; &lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;fetchOrder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;orderID&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"fetch order: %w"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;payment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;errPay&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;chargePayment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;          
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"charge payment: %w"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;savePayment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payment&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, let's return to the topic of common developer mistakes and discuss copy-pasting. You can notice that &lt;code&gt;err&lt;/code&gt; is used instead of &lt;code&gt;errPay&lt;/code&gt; in the second case. The result of &lt;code&gt;chargePayment&lt;/code&gt; is assigned to a different variable, but developers forgot to change the variable name.&lt;/p&gt;

&lt;p&gt;It's easy to spot most of the errors in the context of this article. However, during a code review or while writing code, when we're not looking at a single function but rather going through hundreds or thousands of code lines without a break, it's easy to miss such issues.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;We discussed this and other issues related to error handling in Go in the "&lt;a href="https://pvs-studio.com/en/blog/posts/go/1371/" rel="noopener noreferrer"&gt;Error handling in Go: Common pitfalls&lt;/a&gt;" article.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  The parameter is overwritten before it is used
&lt;/h3&gt;

&lt;p&gt;The example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;Translate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;numericValue&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;numericValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReadInt32&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;   &lt;span class="c1"&gt;// &amp;lt;= the initial parameter value &lt;/span&gt;
                                        &lt;span class="c1"&gt;//    isn't used anywhere&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The PVS-Studio warning: &lt;a href="https://pvs-studio.com/en/docs/warnings/v8038/" rel="noopener noreferrer"&gt;V8038&lt;/a&gt;. A parameter is always rewritten in the function body before being used.&lt;/p&gt;

&lt;p&gt;This is a rather unfortunate error because the value passed to the function parameter is never read; it's immediately overwritten inside the function body. &lt;/p&gt;

&lt;p&gt;Technically, this isn't a compilation error, so everything should work as expected. However, it usually indicates one of two things: either the input value wasn't used, or the variables got mixed up during refactoring.&lt;/p&gt;

&lt;h2&gt;
  
  
  Basic tools aren't always enough
&lt;/h2&gt;

&lt;p&gt;Having a nice set of tools right out of the box—and, of course, various open-source solutions—is always great, but they might not be enough for more demanding tasks.&lt;/p&gt;

&lt;p&gt;Let's take the very first diagnostic rule of our Go analyzer as an example:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://pvs-studio.com/en/docs/warnings/v8001/" rel="noopener noreferrer"&gt;V8001&lt;/a&gt;. Identical sub-expressions to the left and to the right of the 'foo' operator.&lt;/p&gt;

&lt;p&gt;Look at the example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;rgb1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="n"&gt;float32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;g&lt;/span&gt; &lt;span class="n"&gt;float32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="n"&gt;float32&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;g&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;....&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The error lies in the identical sub-expressions within the binary expression. This issue may arise from carelessly copying code. Such errors are common and nothing out of the ordinary; so, go vet can spot them.&lt;/p&gt;

&lt;p&gt;However, things aren't always that simple... Let's take a look at this code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;rgb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="n"&gt;float32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;g&lt;/span&gt; &lt;span class="n"&gt;float32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="n"&gt;float32&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;g&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;....&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The only change is that &lt;code&gt;1&lt;/code&gt; and &lt;code&gt;r&lt;/code&gt; have switched places. Here's the catch, though: go vet doesn't issue any warnings, but the problem remains, since the &lt;code&gt;r &amp;gt; 1&lt;/code&gt; sub-expression is equivalent to &lt;code&gt;1 &amp;lt; r&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Impossible type assertion
&lt;/h3&gt;

&lt;p&gt;Here's another case involving the &lt;a href="https://pvs-studio.com/en/docs/warnings/v8035/" rel="noopener noreferrer"&gt;V8035&lt;/a&gt; diagnostic rule: an impossible type assertion.&lt;/p&gt;

&lt;p&gt;Check out this example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;var&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="n"&gt;interface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Read&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;Read2&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;Read3&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;Read4&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;Read5&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;.(&lt;/span&gt;&lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Reader&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The idea is simple: &lt;code&gt;v&lt;/code&gt; is declared as an anonymous interface with the &lt;code&gt;Read()&lt;/code&gt; method, whose signature doesn't match &lt;code&gt;Read([]byte) (int, error)&lt;/code&gt; from &lt;code&gt;io.Reader/io.ReadCloser&lt;/code&gt; (in the example, &lt;code&gt;Read()&lt;/code&gt; has no arguments). &lt;/p&gt;

&lt;p&gt;So, no specific type can implement both the &lt;code&gt;v&lt;/code&gt; anonymous interface and &lt;code&gt;io.Reader/io.ReadCloser&lt;/code&gt; simultaneously. So, this implementation guarantees that &lt;code&gt;assertion&lt;/code&gt; will throw a panic at runtime. The compiler doesn't catch this because it's technically valid Go code, and everything runs smoothly.&lt;/p&gt;

&lt;p&gt;Now wait for it... Go vet can detect it! This is a well-known and well-documented issue, so it should come as no surprise.&lt;/p&gt;

&lt;p&gt;By the way, PVS-Studio issues the following message for such code:&lt;/p&gt;

&lt;p&gt;The PVS-Studio warning: &lt;a href="https://pvs-studio.com/en/docs/warnings/v8035/" rel="noopener noreferrer"&gt;V8035&lt;/a&gt;. Type assertion is always false. Check the 'interface{Read(); Read2(); Read3(); Read4(); Read5()}' and 'io.Reader' interfaces, as they contain methods with incompatible signatures.&lt;/p&gt;

&lt;p&gt;Here's another example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;var&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="n"&gt;interface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Read&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;.(&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReadCloser&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nl"&gt;default:&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The PVS-Studio warning: &lt;a href="https://pvs-studio.com/en/docs/warnings/v8035/" rel="noopener noreferrer"&gt;V8035&lt;/a&gt;. Type assertion is always false. Check the 'interface{Read()}' and 'io.ReadCloser' interfaces, as they contain methods with incompatible signatures.&lt;/p&gt;

&lt;p&gt;In fact, it's exactly the same impossible &lt;code&gt;assertion&lt;/code&gt;. The only difference is that the assignment is now done using &lt;code&gt;case&lt;/code&gt; in the &lt;code&gt;switch&lt;/code&gt; statement and via &lt;code&gt;v.(type)&lt;/code&gt;, rather than via &lt;code&gt;v.(io.ReadCloser)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This is where I'm supposed to say that go vet can't detect it... but no! It can, but that's not the point here. A popular open-source analyzer won't detect the issue here, but it will spot it in the first case. This is a &lt;a href="https://pvs-studio.com/en/blog/terms/6460/" rel="noopener noreferrer"&gt;false negative&lt;/a&gt; that occurs when a warning isn't issued when it should be.&lt;/p&gt;

&lt;p&gt;This presents a dilemma: you can either look for a tool that covers all use cases and spend time trying out different options, or you can take a closer look at PVS-Studio. It's designed for in-depth analysis and comes with guaranteed support for many years to come. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you have any doubts about our claims, feel free to &lt;a href="https://pvs-studio.com/en/pvs-studio/try-free/?utm_source=website&amp;amp;utm_medium=devto&amp;amp;utm_campaign=article&amp;amp;utm_content=1413" rel="noopener noreferrer"&gt;try our tool&lt;/a&gt; and draw your own conclusions.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Well, enough with the synthetic code. Will we show some real code, though?&lt;/p&gt;

&lt;h3&gt;
  
  
  Some real code
&lt;/h3&gt;

&lt;p&gt;Do you remember the very first Go analyzer diagnostic rule I covered at the beginning of this section? Here's a real example of the warning from the &lt;a href="https://github.com/projectdiscovery/nuclei" rel="noopener noreferrer"&gt;Nuclei&lt;/a&gt; project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;NewEntityParser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dir&lt;/span&gt; &lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;EntityParser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="n"&gt;cfg&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;packages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Config&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;Mode:&lt;/span&gt; &lt;span class="n"&gt;packages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NeedName&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;packages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NeedFiles&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;packages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NeedImports&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;
      &lt;span class="n"&gt;packages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NeedTypes&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;packages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NeedSyntax&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;packages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NeedTypes&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;
      &lt;span class="n"&gt;packages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NeedModule&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;packages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NeedTypesInfo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nl"&gt;Tests:&lt;/span&gt; &lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nl"&gt;Dir:&lt;/span&gt;   &lt;span class="n"&gt;dir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nl"&gt;ParseFile:&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(....)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;ast&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;File&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ParseFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fset&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ParseComments&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The PVS-Studio warning: &lt;a href="https://pvs-studio.com/en/docs/warnings/v8001/" rel="noopener noreferrer"&gt;V8001&lt;/a&gt; There are identical sub-expressions 'packages.NeedTypes' to the left and to the right of the '|' operator. &lt;a href="https://github.com/projectdiscovery/nuclei/blob/ee8287a7b756d07e09e22b8945cddeb58e727a22/pkg/js/devtools/tsgen/parser.go#L33" rel="noopener noreferrer"&gt;parser.go 33&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If we take a closer look, we can see that the &lt;code&gt;packages.NeedTypes&lt;/code&gt; flag is pointlessly repeated here. This error may have occurred due to code autocompletion or a typo. Most likely, there should be the &lt;code&gt;packages.NeedTypesSizes&lt;/code&gt; flag here:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;....&lt;/span&gt;
  &lt;span class="c1"&gt;// NeedTypes adds Types, Fset, and IllTyped.&lt;/span&gt;
  &lt;span class="n"&gt;NeedTypes&lt;/span&gt;

  &lt;span class="c1"&gt;// NeedSyntax adds Syntax and Fset.&lt;/span&gt;
  &lt;span class="n"&gt;NeedSyntax&lt;/span&gt;

  &lt;span class="c1"&gt;// NeedTypesInfo adds TypesInfo and Fset.&lt;/span&gt;
  &lt;span class="n"&gt;NeedTypesInfo&lt;/span&gt;

  &lt;span class="c1"&gt;// NeedTypesSizes adds TypesSizes.&lt;/span&gt;
  &lt;span class="n"&gt;NeedTypesSizes&lt;/span&gt;

  &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It might seem like a simple mistake, but the standard go vet won't catch it. Yet the open-source tool I mentioned in the previous case study does find it. So, I'd like to reiterate the issue: go vet sometimes finds problems that other tools don't, and vice versa.&lt;/p&gt;

&lt;p&gt;We discussed this and other errors that the standard go vet can't detect in the "&lt;a href="https://pvs-studio.com/en/blog/posts/go/1342/" rel="noopener noreferrer"&gt;Go vet can't go: How PVS-Studio analyzes Go projects&lt;/a&gt;" article.&lt;/p&gt;

&lt;h2&gt;
  
  
  Go-specific issues
&lt;/h2&gt;

&lt;p&gt;Of course, Go has its own pitfalls. Even seasoned Go developers may not be familiar with all of the language's unique features and tricky parts (not to mention those coming from other languages).&lt;/p&gt;

&lt;p&gt;For such cases, our comprehensive documentation provides detailed explanations of why this or that error occurred. We also have examples of common mistakes and how to fix them :)&lt;/p&gt;

&lt;p&gt;Well, let's look at a couple of diagnostic rules.&lt;/p&gt;

&lt;h3&gt;
  
  
  recover() inside an anonymous function that isn't wrapped in defer
&lt;/h3&gt;

&lt;p&gt;In Go, &lt;code&gt;recover&lt;/code&gt; resumes execution only if called inside a deferred (&lt;code&gt;defer&lt;/code&gt;) function. &lt;/p&gt;

&lt;p&gt;However, if an anonymous function with &lt;code&gt;recover&lt;/code&gt; is called immediately as &lt;code&gt;(func() { ... }())&lt;/code&gt;, by the time a potential panic occurs, that call will have long since completed—&lt;code&gt;recover&lt;/code&gt; is physically unable to catch it. So, if a panic occurs, the goroutine can't resume execution.&lt;/p&gt;

&lt;p&gt;Here's the example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;recover&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Recovered"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}()&lt;/span&gt;                        &lt;span class="c1"&gt;// &amp;lt;= recover started and finished immediately&lt;/span&gt;
    &lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;bits&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Div64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hi&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// panic, recover won't help here anymore&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After defining the anonymous function and calling it, the &lt;code&gt;bits.Div64&lt;/code&gt; function is called. This function can trigger a panic if &lt;code&gt;y&lt;/code&gt; equals &lt;code&gt;0&lt;/code&gt;. If that panic reaches the top of the stack, the program will crash.&lt;/p&gt;

&lt;p&gt;Of course, the documentation explains how to fix this: the anonymous function call needs to be deferred using the &lt;code&gt;defer&lt;/code&gt; keyword:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;recover&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Recovered"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}()&lt;/span&gt;
  &lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;bits&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Div64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hi&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For more details, refer to the &lt;a href="https://pvs-studio.com/en/docs/warnings/v8007/" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  They couldn't have made such a mistake, right?
&lt;/h3&gt;

&lt;p&gt;Here's an error so interesting that we wrote an article about it titled "&lt;a href="https://pvs-studio.com/en/blog/posts/go/1393/" rel="noopener noreferrer"&gt;One mistake no one has ever made. Right?"&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Since the article describes it pretty thoroughly and includes examples from real projects, I'll just give a brief overview:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;SimpleExample&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arr&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Collection indices always start at 0. So, for a slice of the &lt;code&gt;n&lt;/code&gt; length, the valid indices range from 0 to &lt;code&gt;n – 1&lt;/code&gt;. Then &lt;code&gt;len(arr)&lt;/code&gt; returns &lt;code&gt;n&lt;/code&gt;. As a result, accessing &lt;code&gt;arr[len(arr)]&lt;/code&gt; always leads to a program panic.&lt;/p&gt;

&lt;p&gt;Here's an interesting thing: when developing this diagnostic rule, we thought it was "far-fetched" and that "no one would make a mistake like that" because any test would catch it. But the results were fascinating! You can check them out in the &lt;a href="https://pvs-studio.com/en/blog/posts/go/1393/" rel="noopener noreferrer"&gt;article&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Confusing XOR (^) with exponentiation
&lt;/h3&gt;

&lt;p&gt;Here's another interesting Go-specific mistake.&lt;/p&gt;

&lt;p&gt;Unlike in Lua, VB.NET, and R, in Go, &lt;code&gt;^&lt;/code&gt; has nothing to do with exponentiation, which can be a trap for developers switching between languages. This mistake is exciting because, if we recall the problem with universal mistakes from the beginning of the article, it results in an unfortunate combination.&lt;/p&gt;

&lt;p&gt;Binary expressions meant for exponentiation become incorrect when a developer chooses &lt;code&gt;^&lt;/code&gt;. This operator actually performs a bitwise exclusive &lt;code&gt;OR&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The example is painfully simple:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In reality, the value here is 18 instead of the expected 2 to the power of 16 (65,536). As the &lt;a href="https://pvs-studio.com/en/docs/warnings/v8015/" rel="noopener noreferrer"&gt;documentation&lt;/a&gt; suggests, we can use the left bitwise shift operator to get the power of &lt;code&gt;2&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What's next?
&lt;/h2&gt;

&lt;p&gt;If you're familiar with our work, then you've probably heard that PVS-Studio detects code quality issues and serves as a static application security testing (SAST) solution. This means our analyzer can also spot potential vulnerabilities.&lt;/p&gt;

&lt;p&gt;Our new Go analyzer currently includes only a basic set of diagnostic rules that cover common code quality issues. This is just the beginning, though! &lt;/p&gt;

&lt;p&gt;Consider this an announcement: we've already started working on SAST coverage for our Go analyzer. Stay tuned to &lt;a href="https://pvs-studio.com/en/blog/posts/" rel="noopener noreferrer"&gt;our blog&lt;/a&gt; for updates :)&lt;/p&gt;

&lt;p&gt;To back that up, let me introduce one of the first diagnostic rules in the code security section. &lt;/p&gt;

&lt;h3&gt;
  
  
  Trojan Source
&lt;/h3&gt;

&lt;p&gt;Take a look at this code fragment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;isAuthorized&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;false&lt;/span&gt;
&lt;span class="cm"&gt;/* verify before transfer */&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;isAuthorized&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;TransferFunds&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;account&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="cm"&gt;/* end verify */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What do you think it would look like to the compiler (without all the conventions and low-level details)?&lt;/p&gt;

&lt;p&gt;If you think it should look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;isAuthorized&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;false&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;isAuthorized&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;TransferFunds&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;account&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Well, you're almost right... &lt;/p&gt;

&lt;p&gt;It looks as though the funds transfer is indeed protected by the &lt;code&gt;isAuthorized&lt;/code&gt; check.&lt;/p&gt;

&lt;p&gt;However, the issue lurks where we can't see it, because the compiler will interpret this as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;isAuthorized&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;false&lt;/span&gt;
&lt;span class="n"&gt;TransferFunds&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;account&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It doesn't look that great anymore, does it? The &lt;code&gt;isAuthorized&lt;/code&gt; check never runs because the &lt;code&gt;if&lt;/code&gt; statement and &lt;code&gt;{...}&lt;/code&gt; ended up inside what the reviewer considered to be "commented-out" text, so the &lt;code&gt;TransferFunds&lt;/code&gt; call executes unconditionally.&lt;/p&gt;

&lt;p&gt;The code contains special characters that may not be displayed. They can change how the code appears in the development environment. Combinations of such characters can cause a human and a compiler to interpret the code differently.&lt;/p&gt;

&lt;p&gt;Here's what the code actually looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;isAuthorized&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;false&lt;/span&gt;
&lt;span class="cm"&gt;/*[RLO] } [LRI] if isAuthorized[PDI] [LRI] verify before transfer */&lt;/span&gt;  
    &lt;span class="n"&gt;TransferFunds&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;account&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="cm"&gt;/* end verify [RLO]{ [LRI]*/&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's briefly go over what these characters do here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;[LRI] if isAuthorized[PDI]&lt;/code&gt;: the fragment between &lt;code&gt;LRI&lt;/code&gt; and &lt;code&gt;PDI&lt;/code&gt; is isolated and evaluated from left to right as a single block (&lt;code&gt;if isAuthorized&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;[LRI] verify before transfer */&lt;/code&gt;: to the end of the line; this is also an isolated block (&lt;code&gt;verify before transfer */&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;[RLO]&lt;/code&gt;: reverses from right to left everything that follows it, and each of the obtained isolated blocks is treated as a single, indivisible character.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The final order is as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="n"&gt;verify&lt;/span&gt; &lt;span class="n"&gt;before&lt;/span&gt; &lt;span class="n"&gt;transfer&lt;/span&gt; &lt;span class="err"&gt;*/'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;isAuthorized&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;space&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="sc"&gt;'{'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;space&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And, lo and behold! With a couple of simple gestures, the closing brace visually turns into an opening one.&lt;/p&gt;

&lt;p&gt;This is an issue that PVS-Studio will highlight:&lt;/p&gt;

&lt;p&gt;The PVS-Studio warning: &lt;a href="https://pvs-studio.com/en/docs/warnings/v5901/" rel="noopener noreferrer"&gt;V5901&lt;/a&gt;. OWASP. Code contains invisible characters that may alter its logic. Consider enabling the display of invisible characters in the code editor.&lt;/p&gt;

&lt;p&gt;This vulnerability is listed in the &lt;a href="https://pvs-studio.com/en/pvs-studio/sast/owasptopten/" rel="noopener noreferrer"&gt;OWASP standard&lt;/a&gt;, and our other analyzers can detect similar issues:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;V5801 — JS\TS;&lt;/li&gt;
&lt;li&gt;V5340 — Java;&lt;/li&gt;
&lt;li&gt;V5629 — C#;&lt;/li&gt;
&lt;li&gt;V1076 — C++.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We've covered this diagnostic rule in more detail in the &lt;a href="https://pvs-studio.com/en/docs/warnings/v5901/" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Is this the end? No, it's just the beginning!
&lt;/h2&gt;

&lt;p&gt;The new analyzer for Go projects is here, but this is only the beginning of its story! The 40 diagnostic rules introduced with PVS-Studio 8.0 mark the start of that journey, and your input can make a real difference. If you're a Go developer, we invite you to &lt;a href="https://pvs-studio.com/en/pvs-studio/try-free/?utm_source=website&amp;amp;utm_medium=devto&amp;amp;utm_campaign=article&amp;amp;utm_content=1413" rel="noopener noreferrer"&gt;try our tool for free&lt;/a&gt;. If you have ideas for new diagnostic rules or suggestions for improving the existing ones, feel free to &lt;a href="https://pvs-studio.com/en/about-feedback/" rel="noopener noreferrer"&gt;reach out to us&lt;/a&gt; through the feedback form!&lt;/p&gt;

&lt;p&gt;Thanks for reading. Take care of yourself and your code!&lt;/p&gt;

</description>
      <category>go</category>
      <category>softwaredevelopment</category>
      <category>programming</category>
    </item>
    <item>
      <title>What's new in Java 27</title>
      <dc:creator>Unicorn Developer</dc:creator>
      <pubDate>Tue, 15 Sep 2026 13:22:03 +0000</pubDate>
      <link>https://dev.to/pvsdev/whats-new-in-java-27-8b3</link>
      <guid>https://dev.to/pvsdev/whats-new-in-java-27-8b3</guid>
      <description>&lt;p&gt;Java 27 is here, with four targeted updates and five previews/incubators. We take a closer look at the garbage collector changes, JFR improvements, post-quantum TLS 1.3, and compact object headers (which cut memory usage).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcw2k4qtwof54j6lq4dcw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcw2k4qtwof54j6lq4dcw.png" alt="1412_java27/image1.png" width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Java platform changes
&lt;/h2&gt;

&lt;h3&gt;
  
  
  JEP 534: Compact Object Headers by Default
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://openjdk.org/jeps/534" rel="noopener noreferrer"&gt;Link to JEP&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the &lt;a href="https://pvs-studio.com/en/blog/posts/java/1284/" rel="noopener noreferrer"&gt;article about Java 25,&lt;/a&gt; we already mentioned compact object headers that we could turn on with a flag. Now there's no need to use the flag.&lt;/p&gt;

&lt;p&gt;At that time, we only touched on this topic briefly. Now that it's on by default, we're going to break it down once again, in more depth.&lt;/p&gt;

&lt;p&gt;Every object in the heap begins with a header. In the classic layout (in most JVMs), that's two blocks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;lock status, object's age for GC, identity hash;&lt;/li&gt;
&lt;li&gt;a compact pointer to the class's metadata.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In total, we get 96 bits (12 bytes) per object, even if it contains very little useful data. Compact object headers compress all of this into 64 bits: the pointer to the class metadata is compressed down to 22 bits.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fijku5fpjhbi0c1hwdavz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fijku5fpjhbi0c1hwdavz.png" alt="1412_java27/image2.png" width="671" height="673"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In theory, saving a few bits is a good thing, though, but what benefits shall we (as JRE users) actually get out of it? &lt;/p&gt;

&lt;p&gt;Not long ago, we &lt;a href="https://pvs-studio.com/en/blog/posts/1406/" rel="noopener noreferrer"&gt;released&lt;/a&gt; a JavaScript/TypeScript analyzer powered by Java 25. We'll use it as a test subject, "set it loose" on the &lt;a href="https://github.com/grafana/grafana" rel="noopener noreferrer"&gt;Grafana source code&lt;/a&gt;, and run it with and without compact object headers.&lt;/p&gt;

&lt;p&gt;Three minutes later, we get this:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Benchmark&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;With flag&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Without flag&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Time&lt;/td&gt;
&lt;td&gt;81.4 sec&lt;/td&gt;
&lt;td&gt;79.4 sec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Committed heap&lt;/td&gt;
&lt;td&gt;1 290 240K (~1.23 GB)&lt;/td&gt;
&lt;td&gt;1 126 400K (~1.07 GB)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Used heap: output&lt;/td&gt;
&lt;td&gt;1 150 092K (~1.1 GB)&lt;/td&gt;
&lt;td&gt;773 062K (~738 MB)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Committed heap represents the amount of memory the virtual machine has allocated from the OS and is keeping reserved. Used heap is the memory in use right now—in other words, the number of bytes occupied by live objects that haven't yet been removed by the garbage collector.&lt;/p&gt;

&lt;p&gt;As a result, analysis time remained almost unchanged (within margin of error), committed heap decreased by 13%, and used heap shrank by 33% in total! Just one flag reduced our app's memory usage by a full third, wow!&lt;/p&gt;

&lt;p&gt;What's the cost of our joy? A 22-bit pointer limits the number of loaded classes to approximately four million. There's no automatic rollback to a non-compact mode—if the limit is exceeded, we'll get an &lt;code&gt;OutOfMemoryError&lt;/code&gt;. If your app really hits this limit, you must really love long-lived streams. But if you want to revert to the previous mode, you can do it with another flag:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;java&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;XX&lt;/span&gt;&lt;span class="o"&gt;:-&lt;/span&gt;&lt;span class="n"&gt;UseCompactObjectHeaders&lt;/span&gt; &lt;span class="n"&gt;Application&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  JEP 523: Make G1 the Default Garbage Collector in All Environments
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://openjdk.org/jeps/523" rel="noopener noreferrer"&gt;Link to JEP&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Prior to Java 27, the JVM would check the machine at startup, and if it detected fewer than two processors or less than 1,792 MB of memory, it'd just use Serial GC instead of G1. That kind of machine got labeled a "client" machine, and the memory allocator best suited for it was used.&lt;/p&gt;

&lt;p&gt;Now, guess what a modest JVM container with a limit of one CPU and 512 MB of memory looks like?&lt;/p&gt;

&lt;p&gt;Right. A chunk of containerized Java apps has been running on a client-oriented collector all this time, even though no one consciously made that decision. Worse yet, the same app could get different GCs on the server and in the developer's IDE, which turned reproducing pausing issues into a thrilling quest with a touch of manic laughter.&lt;/p&gt;

&lt;p&gt;Java 27 stopped taking the environment into account and now G1 is selected by default:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="cp"&gt;# Java 25
&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt; &lt;span class="n"&gt;java&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;XX&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;ActiveProcessorCount&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Xmx256m&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Xlog&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;gc&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;version&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mx"&gt;0.001s&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;gc&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;Using&lt;/span&gt; &lt;span class="n"&gt;Serial&lt;/span&gt;

&lt;span class="cp"&gt;# Java 27
&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt; &lt;span class="n"&gt;java&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;XX&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;ActiveProcessorCount&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Xmx256m&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Xlog&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;gc&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;version&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mx"&gt;0.001s&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;gc&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;Using&lt;/span&gt; &lt;span class="n"&gt;G1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The reasoning is simple: improvements to G1's throughput in previous releases have reduced the gap with Serial to almost zero, and G1's pauses are noticeably more pleasant because it can operate concurrently and in parallel. Plus, predictability: the application's behavior no longer depends on how many cores the JVM detected at startup.&lt;/p&gt;

&lt;p&gt;If you specifically want to use &lt;code&gt;Serial&lt;/code&gt;—it still has the lowest memory footprint and faster startup time—you can still use it: &lt;code&gt;-XX:+UseSerialGC&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Security
&lt;/h2&gt;

&lt;h3&gt;
  
  
  JEP 527: Post-Quantum Hybrid Key Exchange for TLS 1.3
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://openjdk.org/jeps/527" rel="noopener noreferrer"&gt;Link to JEP&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ever heard of "harvest now, decrypt later"?&lt;/p&gt;

&lt;p&gt;This is an amusing category of threats, though: attackers, having access to your traffic but unable to break the TLS connection, simply save the encrypted traffic for later.&lt;/p&gt;

&lt;p&gt;Why would they do that, what's the purpose? It's very curious: attackers have a strong faith in global progress and are waiting for a quantum computer capable of breaking elliptic curve key exchange. Medical and banking records, encryption keys, personal data—all of these will still be valuable ten years from now, so the scheme is quite viable.&lt;/p&gt;

&lt;p&gt;Following HTTP/3 (see the &lt;a href="https://pvs-studio.com/en/blog/posts/java/1370/#ID6A3D58AEB3" rel="noopener noreferrer"&gt;previous article&lt;/a&gt;), support for TLS 1.3 is now available. The session key in TLS 1.3 now gets generated using two algorithms simultaneously: a classic elliptic curve key exchange plus a quantum-resistant algorithm. Such a pairing is called &lt;em&gt;a hybrid group&lt;/em&gt;, and the point is that the connection remains secure as long as at least one of the two algorithms is still in service. So this update makes it pointless to wait for a quantum computer to arrive.&lt;/p&gt;

&lt;p&gt;For the application, this is free in terms of code: &lt;code&gt;javax.net.ssl&lt;/code&gt; automatically sets the hybrid group as the first in the preference list. If the other side supports it, the exchange gets a hybrid approach; if not, everything works as before. There's nothing to touch, unless you've manually set a list of groups via &lt;code&gt;jdk.tls.namedGroups&lt;/code&gt; or &lt;code&gt;SSLParameters::setNamedGroups&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;But in some cases, we'll still have to pay a little extra: a TLS handshake costs about two KB more. For most applications, this goes unnoticed, but with millions of short connections in the traffic, you'll see it.&lt;/p&gt;

&lt;p&gt;An important note: this JEP applies only to key exchange. Certificate signatures are still in the classic format, and this is a deliberate choice: it is impossible to forge a signature retroactively, but it is entirely possible to decrypt recorded traffic.&lt;/p&gt;

&lt;h2&gt;
  
  
  JFR enhancements
&lt;/h2&gt;

&lt;h3&gt;
  
  
  JEP 536: JFR In-Process Data Redaction
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://openjdk.org/jeps/536" rel="noopener noreferrer"&gt;Link to JEP&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When recording, &lt;a href="https://openjdk.org/jeps/328" rel="noopener noreferrer"&gt;JFR&lt;/a&gt; carefully preserves the entire process environment: environment variables, system properties, and command-line arguments. And that's where, as we all know, database passwords, tokens, and keys to everything tend to live. That's why sending a &lt;code&gt;.jfr&lt;/code&gt; file to a colleague—and especially attaching it to a public issue—always came with a slight twinge of anxiety. In most cases, you shouldn't make &lt;code&gt;.jfr&lt;/code&gt; files publicly available at all without cleaning them up first.&lt;/p&gt;

&lt;p&gt;Starting with Java 27, JFR scrubs sensitive values within the JVM before they're passed to disk. And what does JFR consider to be sensitive data? By default, any environment variable or system property whose name matches one of these patterns gets replaced with &lt;code&gt;[REDACTED]&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;api&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;      &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;auth&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;        &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;secret&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;  &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;credential&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;
&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;jaas&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;  &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;passphrase&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;  &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;passwd&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;         &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;
&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;  &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;pwd&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;         &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;secret&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;         &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Command-line arguments of the form &lt;code&gt;--db-password qwerty123&lt;/code&gt; are handled in the same way.&lt;/p&gt;

&lt;p&gt;We can expand the list of properties using the &lt;code&gt;-XX:FlightRecorderOptions:redact-key=+&amp;lt;your-pattern&amp;gt;&lt;/code&gt; flag.&lt;/p&gt;

&lt;p&gt;It's worth understanding the limits here: the mechanism covers start events (environment variables, system properties, arguments, and JVM information) and is explicitly described as best-effort. It doesn't filter your app's events, exception messages, or child process command lines. In other words, &lt;code&gt;.jfr&lt;/code&gt; has become significantly safer now, but not sterile in total. We're still worried, but not as much as before.&lt;/p&gt;

&lt;h2&gt;
  
  
  In preview
&lt;/h2&gt;

&lt;p&gt;A few more JEPs have been included in the release as previews. We won't cover them for now, we'll wait for their final versions. Here are some links for you to explore on your own:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://openjdk.org/jeps/531" rel="noopener noreferrer"&gt;JEP 531: Lazy Constants (Third Preview)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://openjdk.org/jeps/532" rel="noopener noreferrer"&gt;JEP 532: Primitive Types in Patterns, instanceof, and switch (Fifth Preview)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://openjdk.org/jeps/533" rel="noopener noreferrer"&gt;JEP 533: Structured Concurrency (Seventh Preview)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://openjdk.org/jeps/537" rel="noopener noreferrer"&gt;JEP 537: Vector API (Twelfth Incubator)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://openjdk.org/jeps/538" rel="noopener noreferrer"&gt;JEP 538: PEM Encodings of Cryptographic Objects (Third Preview)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The full list of JEPs is &lt;a href="https://openjdk.org/projects/jdk/27/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This was a minor release, and there was nothing here in the way of earth-shattering, 180-degree changes: they've updated the preview and polished up the platform. And that brings useful thing right out of the box for the JVM: objects on the heap are more compact, the garbage collector is the same for both the server and a tiny pod, JFR logs are no longer brimming with secrets, and TLS is preparing for a quantum future.&lt;/p&gt;

&lt;p&gt;Essentially, this is preparation for the next LTS. &lt;a href="https://openjdk.org/jeps/533" rel="noopener noreferrer"&gt;Structured Concurrency&lt;/a&gt; is now on its seventh preview, &lt;a href="https://openjdk.org/jeps/532" rel="noopener noreferrer"&gt;primitives in patterns&lt;/a&gt; are in their fifth preview, and the &lt;a href="https://openjdk.org/jeps/537" rel="noopener noreferrer"&gt;Vector API&lt;/a&gt; is waiting for &lt;a href="https://openjdk.org/projects/valhalla/" rel="noopener noreferrer"&gt;Valhalla&lt;/a&gt;. All of this is being finalized so that it can be delivered ready to go with Java 29. Well, for now, though, let's just update and get a more compact heap for free.&lt;/p&gt;

</description>
      <category>java</category>
      <category>programming</category>
      <category>softwaredevelopment</category>
      <category>news</category>
    </item>
  </channel>
</rss>
