{"id":388523,"date":"2024-06-29T07:59:40","date_gmt":"2024-06-29T07:59:40","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=388523"},"modified":"-0001-11-30T00:00:00","modified_gmt":"2024-06-29T07:59:40","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=388523","title":{"rendered":"<span>Top 10 bugs found in C++ projects in 2021<\/span>"},"content":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>It&#8217;s freezing outside, everyone has already decorated the Christmas tree and bought tangerines. New Year is coming! So, it&#8217;s time to meet the Top 10 interesting bugs found by the PVS-Studio C++ analyzer in 2021.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/74e\/d03\/1a2\/74ed031a258eeebfb66e0aacd6d3b860.png\" width=\"580\" height=\"327\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/74e\/d03\/1a2\/74ed031a258eeebfb66e0aacd6d3b860.png\"\/><figcaption><\/figcaption><\/figure>\n<h3>10th: pretty typo in a loop<\/h3>\n<p><a href=\"https:\/\/pvs-studio.com\/en\/docs\/warnings\/v533\/\">V533<\/a> [CWE-691] It is likely that a wrong variable is being incremented inside the &#8216;for&#8217; operator. Consider reviewing &#8216;i&#8217;. gskvulkanimage.c 721<\/p>\n<pre><code class=\"cpp\">void gsk_vulkan_image_upload_regions (GskVulkanImage    *self,                                  GskVulkanUploader *uploader,                                  guint              num_regions,                                  GskImageRegion    *regions) {   ....   for (int i = 0; i &lt; num_regions; i++)   {     m = mem + offset;     if (regions[i].stride == regions[i].width * 4)     {       memcpy (m, regions[i].data, regions[i].stride * regions[i].height);     }     else     {       for (gsize r = 0; r &lt; regions[i].height; i++)          \/\/ &lt;=         memcpy (m + r * regions[i].width * 4,                 regions[i].data + r * regions[i].stride, regions[i].width * 4);     }     ....   }   .... } <\/code><\/pre>\n<p>Note that in a nested loop the <em>i<\/em> variable is incremented instead of the <em>r<\/em> variable. No need to comment. It&#8217;s a golden classic!<\/p>\n<p>My colleague described this error in the &#171;<a href=\"https:\/\/pvs-studio.com\/en\/blog\/posts\/cpp\/0793\/\">Finding typos in the GTK 4 project by PVS-Studio<\/a>&#187; article.<\/p>\n<h3>9th: suddenly, let&#8217;s talk about&#8230; HTML!<\/h3>\n<p><a href=\"https:\/\/pvs-studio.com\/en\/docs\/warnings\/v735\/\">V735<\/a> Possibly an incorrect HTML. The &#171;&lt;\/body>&#187; closing tag was encountered, while the &#171;&lt;\/ul>&#187; tag was expected. qpixeltool.cpp 707<\/p>\n<pre><code class=\"cpp\">QString QPixelTool::aboutText() const {   const QList&lt;QScreen *> screens = QGuiApplication::screens();   const QScreen *windowScreen = windowHandle()->screen();    QString result;   QTextStream str(&amp;result);   str &lt;&lt; \"&lt;html>&lt;\/head>&lt;body>&lt;h2>Qt Pixeltool&lt;\/h2>&lt;p>Qt \" &lt;&lt; QT_VERSION_STR     &lt;&lt; \"&lt;\/p>&lt;p>Copyright (C) 2017 The Qt Company Ltd.&lt;\/p>&lt;h3>Screens&lt;\/h3>&lt;ul>\";   for (const QScreen *screen : screens)     str &lt;&lt; \"&lt;li>\" &lt;&lt; (screen == windowScreen ? \"* \" : \"  \")         &lt;&lt; screen &lt;&lt; \"&lt;\/li>\";   str &lt;&lt; \"&lt;ul>&lt;\/body>&lt;\/html>\";   return result; } <\/code><\/pre>\n<p>PVS-Studio provides diagnostics that don&#8217;t just check code \u2013 they also look for abnormalities in string literals. The code above triggered one of these diagnostics. Such cases are quite rare. That&#8217;s why, this one is so intriguing.<\/p>\n<p>Someone intended to create one list but added two tags that open this list instead of one. This is clearly a typo. The first tag must open the list, and the second one must close it. Here is the correct code:<\/p>\n<pre><code class=\"cpp\">str &lt;&lt; \"&lt;\/ul>&lt;\/body>&lt;\/html>\";<\/code><\/pre>\n<p>This error was described in the article: &#171;<a href=\"https:\/\/pvs-studio.com\/en\/blog\/posts\/cpp\/0801\/\">Date processing attracts bugs or 77 defects in Qt 6<\/a>&#171;.<\/p>\n<h3>8th: an unsafe macro<\/h3>\n<p><a href=\"https:\/\/pvs-studio.com\/en\/docs\/warnings\/v634\/\">V634<\/a> The priority of the &#8216;*&#8217; operation is higher than that of the &#8216;&lt;&lt;&#8216; operation. It&#8217;s possible that parentheses should be used in the expression. bug34427.c 160<\/p>\n<pre><code class=\"cpp\">#define PM_EXP2(A) 1 &lt;&lt; A  int process_val(const u_int8_t *data, u_int32_t data_len,                                u_int32_t *retvalue, ....)  {   *retvalue = 0;   ....   \/* Now find the actual value *\/   for (; i &lt; data_len; i++) {     *retvalue += data[i] * PM_EXP2(8 * (data_len - i - 1));   }   return(0); } <\/code><\/pre>\n<p>The analyzer warns that after the macro expands, it may produce an incorrect expression. The function will first multiply the variable by one, and then conduct the bitwise shift to the expression in parentheses. It was a lucky coincidence that in this line the <em>x * 1 &lt;&lt; y<\/em> expression is equal to <em>x * (1  &lt;&lt; y)<\/em>.  If to its left or right the macro has <em>\/<\/em>, <em>%<\/em>, <em>+<\/em>, <em>&#8212;<\/em>, or other operations with a priority greater than <em>&lt;&lt;,<\/em> or if the macro contains an operation that has a lesser priority than <em>&lt;&lt;<\/em>, the expression will not be evaluated correctly. Always wrap the macro and its arguments in parentheses to avoid problems in the future. The following is correct:<\/p>\n<pre><code class=\"cpp\">Define PM_EXP2(A) (1 &lt;&lt; (A))<\/code><\/pre>\n<p>You can find this error in the &#171;<a href=\"https:\/\/pvs-studio.com\/en\/blog\/posts\/cpp\/0812\/\">PVS-Studio analyzer scans Snort, network traffic scanner<\/a>&#187; article.<\/p>\n<h3>7th: mixed-up divisor and dividend<\/h3>\n<p><a href=\"https:\/\/pvs-studio.com\/en\/docs\/warnings\/v1064\/\">V1064<\/a> The &#8216;gPEClockFrequencyInfo.bus_clock_rate_hz&#8217; operand of integer division is less than the &#8216;gPEClockFrequencyInfo.dec_clock_rate_hz&#8217; one. The result will always be zero. pe_identify_machine.c 72<\/p>\n<pre><code class=\"cpp\">void pe_identify_machine(__unused boot_args *args) {   ....   \/\/ Start with default values.   gPEClockFrequencyInfo.timebase_frequency_hz = 1000000000;   gPEClockFrequencyInfo.bus_frequency_hz      =  100000000;   ....   gPEClockFrequencyInfo.dec_clock_rate_hz =      gPEClockFrequencyInfo.timebase_frequency_hz;   gPEClockFrequencyInfo.bus_clock_rate_hz =    gPEClockFrequencyInfo.bus_frequency_hz;   ....    gPEClockFrequencyInfo.bus_to_dec_rate_den =     gPEClockFrequencyInfo.bus_clock_rate_hz \/     gPEClockFrequencyInfo.dec_clock_rate_hz; } <\/code><\/pre>\n<p>All fields used here have integer types:<\/p>\n<pre><code class=\"cpp\">extern clock_frequency_info_t gPEClockFrequencyInfo;  struct clock_frequency_info_t {   unsigned long bus_clock_rate_hz;   unsigned long dec_clock_rate_hz;   unsigned long bus_to_dec_rate_den;   unsigned long long bus_frequency_hz;   unsigned long timebase_frequency_hz;   .... }; <\/code><\/pre>\n<p>Through intermediate assignments, the dividend data member <em>gPEClockFrequencyInfo.bus_clock_rate_hz,<\/em> is assigned the 100000000 value, and the divisor data member <em>gPEClockFrequencyInfo.dec_clock_rate_hz<\/em> is assigned the 1000000000 value. In this case, the divisor is ten times greater than the dividend. Since all the data members here are integers, the <em>gPEClockFrequencyInfo.bus_to_dec_rate_den<\/em> data member is 0.<\/p>\n<p>Judging by the name of the resulting <em>bus_to_dec_rate_den<\/em> data member, the divisor and the dividend are mixed up.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/f76\/ee2\/2a5\/f76ee22a5a1292c162e1fcc484707837.png\" width=\"580\" height=\"580\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/f76\/ee2\/2a5\/f76ee22a5a1292c162e1fcc484707837.png\"\/><figcaption><\/figcaption><\/figure>\n<p>My colleague described this error in the following article: &#171;<a href=\"https:\/\/pvs-studio.com\/en\/blog\/posts\/cpp\/0818\/\">MacOS Kernel, how good is this apple?<\/a>&#171;.<\/p>\n<h3>6th: error in selecting types<\/h3>\n<p><a href=\"https:\/\/pvs-studio.com\/en\/docs\/warnings\/v610\/\">V610<\/a> Undefined behavior. Check the shift operator &#8216;>>=&#8217;. The right operand (&#8216;bitpos % 64&#8217; = [0..63]) is greater than or equal to the length in bits of the promoted left operand. master.c 354<\/p>\n<pre><code class=\"cpp\">\/\/ bitsperlong.h #ifdef CONFIG_64BIT #define BITS_PER_LONG 64 #else #define BITS_PER_LONG 32 #endif \/* CONFIG_64BIT *\/  \/\/ bits.h \/*  * Create a contiguous bitmask starting at bit position @l and ending at  * position @h. For example  * GENMASK_ULL(39, 21) gives us the 64bit vector 0x000000ffffe00000.  *\/ #define __GENMASK(h, l) ....  \/\/ master.h #define I2C_MAX_ADDR      GENMASK(6, 0)  \/\/ master.c static enum i3c_addr_slot_status i3c_bus_get_addr_slot_status(struct i3c_bus *bus, u16 addr) {   int status, bitpos = addr * 2;                   \/\/ &lt;=    if (addr > I2C_MAX_ADDR)     return I3C_ADDR_SLOT_RSVD;    status = bus->addrslots[bitpos \/ BITS_PER_LONG];   status >>= bitpos % BITS_PER_LONG;               \/\/ &lt;=    return status &amp; I3C_ADDR_SLOT_STATUS_MASK; } <\/code><\/pre>\n<p>Note that the <em>BITS_PER_LONG<\/em> macro can be 64-bit.<\/p>\n<p>The code contains undefined behavior:<\/p>\n<ul>\n<li>\n<p>after the check, the <em>addr<\/em> variable can be in the range [0..127]<\/p>\n<\/li>\n<li>\n<p>if the formal parameter is <em>addr >= 16<\/em>, then the <em>status<\/em> variable is right-shifted by a number of bits more than the <em>int<\/em> type contains (32 bits).<\/p>\n<\/li>\n<\/ul>\n<p>Perhaps, the author wanted to reduce the number of lines and declared the <em>bitpos<\/em> variable next to the <em>status<\/em> variable. However, the programmer did not take into account that <em>int<\/em> has a 32-bit size on 64-bit platforms, unlike the <em>long<\/em> type.<\/p>\n<p>To fix this, declare the <em>status<\/em> variable with the <em>long<\/em> type.<\/p>\n<p>You can read about this error in the &#171;<a href=\"https:\/\/pvs-studio.com\/en\/blog\/posts\/cpp\/0858\/\">Linux kernel turns 30: congratulations from PVS-Studio<\/a>&#187; article. Do read the article, if you haven&#8217;t already. You&#8217;ll find nice old-school pictures \ud83d\ude42<\/p>\n<h3>5th: intermodular analysis and lost memset<\/h3>\n<p>This year, the PVS-Studio developers added one major and necessary feature \u2013 intermodular analysis of C++ projects. Intermodular analysis helped to find this warning in the <a href=\"https:\/\/github.com\/eranif\/codelite\">codelite<\/a> project.<\/p>\n<p><a href=\"https:\/\/pvs-studio.com\/en\/docs\/warnings\/v597\/\">V597<\/a> The compiler could delete the &#8216;memset&#8217; function call, which is used to flush &#8216;current&#8217; object. The memset_s() function should be used to erase the private data. args.c 269<\/p>\n<pre><code class=\"cpp\">\/\/ args.c extern void eFree (void *const ptr);  extern void argDelete (Arguments* const current) {   Assert (current != NULL);   if (current->type ==  ARG_STRING  &amp;&amp;  current->item != NULL)     eFree (current->item);   memset (current, 0, sizeof (Arguments));  \/\/ &lt;=   eFree (current);                          \/\/ &lt;= }  \/\/ routines.c extern void eFree (void *const ptr) {   Assert (ptr != NULL);   free (ptr); } <\/code><\/pre>\n<p>LTO (Link Time Optimization) may optimize out the <em>memset<\/em> call. The compiler, using the <a href=\"https:\/\/en.cppreference.com\/w\/cpp\/language\/as_if\">as-if<\/a> rule, figures out that <em>eFree<\/em> doesn&#8217;t calculate any useful pointer-related data. <em>eFree<\/em> only calls the <em>free<\/em> function that frees memory.<\/p>\n<p>Without LTO, the <em>eFree<\/em> call looks like an unknown external function, so <em>memset<\/em> will remain.<\/p>\n<p>This error was described in the following article: &#171;<a href=\"https:\/\/pvs-studio.com\/en\/blog\/posts\/cpp\/0851\/\">Intermodular analysis of C++ projects in PVS-Studio<\/a>&#171;.<\/p>\n<h3>4th: senseless check &amp;&amp; Unreal Engine<\/h3>\n<p>Recently, PVS-Studio enhanced the check of Unreal Engine projects. My colleague wrote an article, describing this in detail \u2013 you&#8217;ll find the link below. First, let&#8217;s take a look at an interesting error that the analyzer found.<\/p>\n<p><a href=\"https:\/\/pvs-studio.com\/en\/docs\/warnings\/v547\/\">V547<\/a> Expression &#8216;m_trail == 0&#8217; is always false. unpack.hpp 699<\/p>\n<pre><code class=\"cpp\">std::size_t m_trail;  .... inline int context::execute(const char* data, std::size_t len,  std::size_t&amp; off) {   ....   case MSGPACK_CS_EXT_8: {                 uint8_t tmp;                 load&lt;uint8_t>(tmp, n);                 m_trail = tmp + 1;                 if(m_trail == 0) {                     unpack_ext(m_user, n, m_trail, obj);                     int ret = push_proc(obj, off);                     if (ret != 0) return ret;                 }                 else {                     m_cs = MSGPACK_ACS_EXT_VALUE;                     fixed_trail_again = true;                 }             } break;   .... } <\/code><\/pre>\n<p>Let&#8217;s see what&#8217;s going on in this code fragment.<\/p>\n<p>We have the <em>tmp<\/em> variable of the <em>uint8_t<\/em> type. Its value is limited with eight bits \u2013 <em>[0, 255]<\/em>. The programmer who wrote this code assumes that <em>tmp<\/em> can be <em>255<\/em>. After the <em>m_trail = tmp + 1<\/em> assignment, they check that there&#8217;s no integer overflow. An unsigned integer arithmetic can cause a wrap around.  So, the result of the <em>tmp + 1<\/em> operation can be <em>0<\/em>.<\/p>\n<p>However, the analyzer says that the <em>m_trail == 0<\/em> check is always <em>false<\/em>. Let&#8217;s figure it out.<\/p>\n<p>At first, we need to recall <em>std::common_type<\/em>. By the way, we discussed it in our recent <a href=\"https:\/\/pvs-studio.com\/en\/blog\/posts\/cpp\/0892\/\">article<\/a>.<\/p>\n<p>Let&#8217;s consider the line. It contains the addition operation. For binary operations between values of different types, the compiler uses <em>usual arithmetic conversions<\/em> during which <em>integral promotion<\/em> is applied to the <em>tmp<\/em> variable. Its type in this expression is expanded to the type of the <em>1<\/em> literal, that is, to <em>int<\/em>. As a result, even if the <em>tmp<\/em> value is <em>255<\/em>, the addition operation results in <em>256<\/em>. The <em>int<\/em> type stores this value. So, the <em>m_trail == 0<\/em> check is senseless.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/2b3\/e66\/57c\/2b3e6657c718398e362710c76cd356ef.png\" width=\"580\" height=\"580\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/2b3\/e66\/57c\/2b3e6657c718398e362710c76cd356ef.png\"\/><figcaption><\/figcaption><\/figure>\n<p>My colleague described this error in the &#171;<a href=\"https:\/\/pvs-studio.com\/en\/blog\/posts\/cpp\/0888\/\">How the Carla car simulator helped us level up the static analysis of Unreal Engine 4 projects<\/a>&#187; article.<\/p>\n<h3>3rd: misinterpreted error in the date processing function<\/h3>\n<p>In this case, the PVS-Studio analyzer issued a whole bunch of warnings:<\/p>\n<ul>\n<li>\n<p><a href=\"https:\/\/pvs-studio.com\/en\/docs\/warnings\/v547\/\">V547<\/a> [CWE-571] Expression &#8216;month&#8217; is always true. qdatetime.cpp 4907<\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/pvs-studio.com\/en\/docs\/warnings\/v560\/\">V560<\/a> [CWE-570] A part of conditional expression is always false: !month. qdatetime.cpp 4911<\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/pvs-studio.com\/en\/docs\/warnings\/v547\/\">V547<\/a> [CWE-571] Expression &#8216;month&#8217; is always true. qdatetime.cpp 4913<\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/pvs-studio.com\/en\/docs\/warnings\/v560\/\">V560<\/a> [CWE-570] A part of conditional expression is always false: !month. qdatetime.cpp 4921<\/p>\n<\/li>\n<\/ul>\n<p>First, let&#8217;s take a look at the function that accepts a month&#8217;s abbreviated name and returns its number.<\/p>\n<pre><code class=\"cpp\">static const char qt_shortMonthNames[][4] = {     \"Jan\", \"Feb\", \"Mar\", \"Apr\", \"May\", \"Jun\",     \"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\" };  static int fromShortMonthName(QStringView monthName) {   for (unsigned int i = 0;        i &lt; sizeof(qt_shortMonthNames) \/ sizeof(qt_shortMonthNames[0]); ++i)   {     if (monthName == QLatin1String(qt_shortMonthNames[i], 3))       return i + 1;   }   return -1; } <\/code><\/pre>\n<p>If the operation succeeds, the function returns the month number (a value from 1 to 12). If the month&#8217;s name is incorrect, the function returns a negative value (-1). Note that the function cannot return 0.<\/p>\n<p>However, the function above is used where the developer expects it to return zero value in case of an error. Here&#8217;s the code fragment with the incorrect <em>fromShortMonthName<\/em> function:<\/p>\n<pre><code class=\"cpp\">QDateTime QDateTime::fromString(QStringView string, Qt::DateFormat format) {   ....   month = fromShortMonthName(parts.at(1));   if (month)     day = parts.at(2).toInt(&amp;ok);    \/\/ If failed, try day then month   if (!ok || !month || !day) {     month = fromShortMonthName(parts.at(2));     if (month) {       QStringView dayPart = parts.at(1);       if (dayPart.endsWith(u'.'))         day = dayPart.chopped(1).toInt(&amp;ok);     }   }   .... } <\/code><\/pre>\n<p>The program never reaches the code that checks the month number for zero value. It continues to run with an incorrect negative month number.<\/p>\n<p>This error was discussed in the &#171;<a href=\"https:\/\/pvs-studio.com\/en\/blog\/posts\/cpp\/0801\/\">Date processing attracts bugs or 77 defects in Qt 6<\/a>&#187; article.<\/p>\n<h3>2nd: an example of inattention<\/h3>\n<p><a href=\"https:\/\/pvs-studio.com\/en\/docs\/warnings\/v726\/\">V726<\/a> An attempt to free memory containing the &#8216;wbuf&#8217; array by using the &#8216;free&#8217; function. This is incorrect as &#8216;wbuf&#8217; was created on stack. log.cpp 216<\/p>\n<pre><code class=\"cpp\">template&lt;typename T> static ALWAYS_INLINE void FormatLogMessageAndPrintW(....) {   ....   wchar_t wbuf[512];   wchar_t* wmessage_buf = wbuf;   ....   if (wmessage_buf != wbuf)   {     std::free(wbuf);   }   if (message_buf != buf)   {     std::free(message_buf);   }   .... } <\/code><\/pre>\n<p>This code fragment triggered the analyzer. An attempt to delete an array allocated on the stack provokes an error. The memory has not been allocated on the heap. So, there&#8217;s no need to call any special functions like <em>std::free<\/em> to clear it. When the object is destroyed, the memory is cleared automatically.<\/p>\n<p>To my mind, the origin of this warning is more thrilling than the warning itself. I don&#8217;t want to spoil the story, so, I invite you to read the original article: &#171;<a href=\"https:\/\/pvs-studio.com\/en\/blog\/posts\/cpp\/0880\/\">How a PVS-Studio developer defended a bug in a checked project<\/a>&#171;.<\/p>\n<p>This is not the only bug we found in this project. To see the full list of curious warnings, read the following article: &#171;<a href=\"https:\/\/pvs-studio.com\/en\/blog\/posts\/cpp\/0881\/\">PVS-Studio searches for bugs in the DuckStation project<\/a>&#171;.<\/p>\n<h3>1st: an example of greater inattention<\/h3>\n<p>We always warn our users of making errors. But this year, we made the error. We are not afraid to talk about this. Such cases prove that a static analyzer is much more attentive than a programmer. Here&#8217;s an example:<\/p>\n<p><a href=\"https:\/\/pvs-studio.com\/en\/docs\/warnings\/v645\/\">V645<\/a> The &#8216;strncat&#8217; function call could lead to the &#8216;a.consoleText&#8217; buffer overflow. The bounds should not contain the size of the buffer, but a number of characters it can hold.<\/p>\n<pre><code class=\"cpp\">struct A {   char consoleText[512]; };  void foo(A a) {   char inputBuffer[1024];   ....   strncat(a.consoleText, inputBuffer, sizeof(a.consoleText) \u2013                                       strlen(a.consoleText) - 5);   .... } <\/code><\/pre>\n<p>At first glance, the code fragment seems to be correct. We are safe from undefined behavior. However, let&#8217;s take a closer look at an expression:<\/p>\n<pre><code class=\"cpp\">sizeof(a.consoleText) \u2013 strlen(a.consoleText) \u2013 5<\/code><\/pre>\n<p>The expression may receive a negative number! For example, such may happen if <em>strlen(a.consoleText) = 508<\/em>. In this case, an unsigned integer overflow happens. The expression results in the maximum value of the resulting type \u2013 <em>size_t<\/em>.<\/p>\n<p>This error was described in the following article: &#171;<a href=\"https:\/\/pvs-studio.com\/en\/blog\/posts\/cpp\/0842\/\">One day in the life of PVS-Studio developer, or how I debugged diagnostic that surpassed three programmers<\/a>&#171;.<\/p>\n<h3>Conclusion<\/h3>\n<p>This year, we checked lots of C++ projects. We could even write several reviews about top bugs. If you have your Top 10 bugs list, feel free to share them in the comments after reading articles from our <a href=\"https:\/\/pvs-studio.com\/en\/blog\/posts\/cpp\/\">blog<\/a>.<\/p>\n<p>Every year we write New Year&#8217;s articles about Top 10 bugs. I invite you to read articles about Top 10 bugs in C++ projects for the past years: <a href=\"https:\/\/www.pvs-studio.com\/en\/b\/0483\/\">2016<\/a>, <a href=\"https:\/\/www.pvs-studio.com\/en\/b\/0565\/\">2017<\/a>, <a href=\"https:\/\/www.pvs-studio.com\/en\/b\/0619\/\">2018<\/a>, <a href=\"https:\/\/www.pvs-studio.com\/en\/b\/0700\/\">2019<\/a>, <a href=\"https:\/\/pvs-studio.com\/en\/blog\/posts\/cpp\/0784\/\">2020<\/a>.<\/p>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/596973\/\"> https:\/\/habr.com\/ru\/articles\/596973\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>It&#8217;s freezing outside, everyone has already decorated the Christmas tree and bought tangerines. New Year is coming! So, it&#8217;s time to meet the Top 10 interesting bugs found by the PVS-Studio C++ analyzer in 2021.<\/p>\n<figure class=\"full-width\"><figcaption><\/figcaption><\/figure>\n<h3>10th: pretty typo in a loop<\/h3>\n<p><a href=\"https:\/\/pvs-studio.com\/en\/docs\/warnings\/v533\/\">V533<\/a> [CWE-691] It is likely that a wrong variable is being incremented inside the &#8216;for&#8217; operator. Consider reviewing &#8216;i&#8217;. gskvulkanimage.c 721<\/p>\n<pre><code class=\"cpp\">void gsk_vulkan_image_upload_regions (GskVulkanImage    *self,                                  GskVulkanUploader *uploader,                                  guint              num_regions,                                  GskImageRegion    *regions) {   ....   for (int i = 0; i &lt; num_regions; i++)   {     m = mem + offset;     if (regions[i].stride == regions[i].width * 4)     {       memcpy (m, regions[i].data, regions[i].stride * regions[i].height);     }     else     {       for (gsize r = 0; r &lt; regions[i].height; i++)          \/\/ &lt;=         memcpy (m + r * regions[i].width * 4,                 regions[i].data + r * regions[i].stride, regions[i].width * 4);     }     ....   }   .... } <\/code><\/pre>\n<p>Note that in a nested loop the <em>i<\/em> variable is incremented instead of the <em>r<\/em> variable. No need to comment. It&#8217;s a golden classic!<\/p>\n<p>My colleague described this error in the &#171;<a href=\"https:\/\/pvs-studio.com\/en\/blog\/posts\/cpp\/0793\/\">Finding typos in the GTK 4 project by PVS-Studio<\/a>&#187; article.<\/p>\n<h3>9th: suddenly, let&#8217;s talk about&#8230; HTML!<\/h3>\n<p><a href=\"https:\/\/pvs-studio.com\/en\/docs\/warnings\/v735\/\">V735<\/a> Possibly an incorrect HTML. The &#171;&lt;\/body>&#187; closing tag was encountered, while the &#171;&lt;\/ul>&#187; tag was expected. qpixeltool.cpp 707<\/p>\n<pre><code class=\"cpp\">QString QPixelTool::aboutText() const {   const QList&lt;QScreen *> screens = QGuiApplication::screens();   const QScreen *windowScreen = windowHandle()->screen();    QString result;   QTextStream str(&amp;result);   str &lt;&lt; \"&lt;html>&lt;\/head>&lt;body>&lt;h2>Qt Pixeltool&lt;\/h2>&lt;p>Qt \" &lt;&lt; QT_VERSION_STR     &lt;&lt; \"&lt;\/p>&lt;p>Copyright (C) 2017 The Qt Company Ltd.&lt;\/p>&lt;h3>Screens&lt;\/h3>&lt;ul>\";   for (const QScreen *screen : screens)     str &lt;&lt; \"&lt;li>\" &lt;&lt; (screen == windowScreen ? \"* \" : \"  \")         &lt;&lt; screen &lt;&lt; \"&lt;\/li>\";   str &lt;&lt; \"&lt;ul>&lt;\/body>&lt;\/html>\";   return result; } <\/code><\/pre>\n<p>PVS-Studio provides diagnostics that don&#8217;t just check code \u2013 they also look for abnormalities in string literals. The code above triggered one of these diagnostics. Such cases are quite rare. That&#8217;s why, this one is so intriguing.<\/p>\n<p>Someone intended to create one list but added two tags that open this list instead of one. This is clearly a typo. The first tag must open the list, and the second one must close it. Here is the correct code:<\/p>\n<pre><code class=\"cpp\">str &lt;&lt; \"&lt;\/ul>&lt;\/body>&lt;\/html>\";<\/code><\/pre>\n<p>This error was described in the article: &#171;<a href=\"https:\/\/pvs-studio.com\/en\/blog\/posts\/cpp\/0801\/\">Date processing attracts bugs or 77 defects in Qt 6<\/a>&#171;.<\/p>\n<h3>8th: an unsafe macro<\/h3>\n<p><a href=\"https:\/\/pvs-studio.com\/en\/docs\/warnings\/v634\/\">V634<\/a> The priority of the &#8216;*&#8217; operation is higher than that of the &#8216;&lt;&lt;&#8216; operation. It&#8217;s possible that parentheses should be used in the expression. bug34427.c 160<\/p>\n<pre><code class=\"cpp\">#define PM_EXP2(A) 1 &lt;&lt; A  int process_val(const u_int8_t *data, u_int32_t data_len,                                u_int32_t *retvalue, ....)  {   *retvalue = 0;   ....   \/* Now find the actual value *\/   for (; i &lt; data_len; i++) {     *retvalue += data[i] * PM_EXP2(8 * (data_len - i - 1));   }   return(0); } <\/code><\/pre>\n<p>The analyzer warns that after the macro expands, it may produce an incorrect expression. The function will first multiply the variable by one, and then conduct the bitwise shift to the expression in parentheses. It was a lucky coincidence that in this line the <em>x * 1 &lt;&lt; y<\/em> expression is equal to <em>x * (1  &lt;&lt; y)<\/em>.  If to its left or right the macro has <em>\/<\/em>, <em>%<\/em>, <em>+<\/em>, <em>&#8212;<\/em>, or other operations with a priority greater than <em>&lt;&lt;,<\/em> or if the macro contains an operation that has a lesser priority than <em>&lt;&lt;<\/em>, the expression will not be evaluated correctly. Always wrap the macro and its arguments in parentheses to avoid problems in the future. The following is correct:<\/p>\n<pre><code class=\"cpp\">Define PM_EXP2(A) (1 &lt;&lt; (A))<\/code><\/pre>\n<p>You can find this error in the &#171;<a href=\"https:\/\/pvs-studio.com\/en\/blog\/posts\/cpp\/0812\/\">PVS-Studio analyzer scans Snort, network traffic scanner<\/a>&#187; article.<\/p>\n<h3>7th: mixed-up divisor and dividend<\/h3>\n<p><a href=\"https:\/\/pvs-studio.com\/en\/docs\/warnings\/v1064\/\">V1064<\/a> The &#8216;gPEClockFrequencyInfo.bus_clock_rate_hz&#8217; operand of integer division is less than the &#8216;gPEClockFrequencyInfo.dec_clock_rate_hz&#8217; one. The result will always be zero. pe_identify_machine.c 72<\/p>\n<pre><code class=\"cpp\">void pe_identify_machine(__unused boot_args *args) {   ....   \/\/ Start with default values.   gPEClockFrequencyInfo.timebase_frequency_hz = 1000000000;   gPEClockFrequencyInfo.bus_frequency_hz      =  100000000;   ....   gPEClockFrequencyInfo.dec_clock_rate_hz =      gPEClockFrequencyInfo.timebase_frequency_hz;   gPEClockFrequencyInfo.bus_clock_rate_hz =    gPEClockFrequencyInfo.bus_frequency_hz;   ....    gPEClockFrequencyInfo.bus_to_dec_rate_den =     gPEClockFrequencyInfo.bus_clock_rate_hz \/     gPEClockFrequencyInfo.dec_clock_rate_hz; } <\/code><\/pre>\n<p>All fields used here have integer types:<\/p>\n<pre><code class=\"cpp\">extern clock_frequency_info_t gPEClockFrequencyInfo;  struct clock_frequency_info_t {   unsigned long bus_clock_rate_hz;   unsigned long dec_clock_rate_hz;   unsigned long bus_to_dec_rate_den;   unsigned long long bus_frequency_hz;   unsigned long timebase_frequency_hz;   .... }; <\/code><\/pre>\n<p>Through intermediate assignments, the dividend data member <em>gPEClockFrequencyInfo.bus_clock_rate_hz,<\/em> is assigned the 100000000 value, and the divisor data member <em>gPEClockFrequencyInfo.dec_clock_rate_hz<\/em> is assigned the 1000000000 value. In this case, the divisor is ten times greater than the dividend. Since all the data members here are integers, the <em>gPEClockFrequencyInfo.bus_to_dec_rate_den<\/em> data member is 0.<\/p>\n<p>Judging by the name of the resulting <em>bus_to_dec_rate_den<\/em> data member, the divisor and the dividend are mixed up.<\/p>\n<figure class=\"full-width\"><figcaption><\/figcaption><\/figure>\n<p>My colleague described this error in the following article: &#171;<a href=\"https:\/\/pvs-studio.com\/en\/blog\/posts\/cpp\/0818\/\">MacOS Kernel, how good is this apple?<\/a>&#171;.<\/p>\n<h3>6th: error in selecting types<\/h3>\n<p><a href=\"https:\/\/pvs-studio.com\/en\/docs\/warnings\/v610\/\">V610<\/a> Undefined behavior. Check the shift operator &#8216;>>=&#8217;. The right operand (&#8216;bitpos % 64&#8217; = [0..63]) is greater than or equal to the length in bits of the promoted left operand. master.c 354<\/p>\n<pre><code class=\"cpp\">\/\/ bitsperlong.h #ifdef CONFIG_64BIT #define BITS_PER_LONG 64 #else #define BITS_PER_LONG 32 #endif \/* CONFIG_64BIT *\/  \/\/ bits.h \/*  * Create a contiguous bitmask starting at bit position @l and ending at  * position @h. For example  * GENMASK_ULL(39, 21) gives us the 64bit vector 0x000000ffffe00000.  *\/ #define __GENMASK(h, l) ....  \/\/ master.h #define I2C_MAX_ADDR      GENMASK(6, 0)  \/\/ master.c static enum i3c_addr_slot_status i3c_bus_get_addr_slot_status(struct i3c_bus *bus, u16 addr) {   int status, bitpos = addr * 2;                   \/\/ &lt;=    if (addr > I2C_MAX_ADDR)     return I3C_ADDR_SLOT_RSVD;    status = bus->addrslots[bitpos \/ BITS_PER_LONG];   status >>= bitpos % BITS_PER_LONG;               \/\/ &lt;=    return status &amp; I3C_ADDR_SLOT_STATUS_MASK; } <\/code><\/pre>\n<p>Note that the <em>BITS_PER_LONG<\/em> macro can be 64-bit.<\/p>\n<p>The code contains undefined behavior:<\/p>\n<ul>\n<li>\n<p>after the check, the <em>addr<\/em> variable can be in the range [0..127]<\/p>\n<\/li>\n<li>\n<p>if the formal parameter is <em>addr >= 16<\/em>, then the <em>status<\/em> variable is right-shifted by a number of bits more than the <em>int<\/em> type contains (32 bits).<\/p>\n<\/li>\n<\/ul>\n<p>Perhaps, the author wanted to reduce the number of lines and declared the <em>bitpos<\/em> variable next to the <em>status<\/em> variable. However, the programmer did not take into account that <em>int<\/em> has a 32-bit size on 64-bit platforms, unlike the <em>long<\/em> type.<\/p>\n<p>To fix this, declare the <em>status<\/em> variable with the <em>long<\/em> type.<\/p>\n<p>You can read about this error in the &#171;<a href=\"https:\/\/pvs-studio.com\/en\/blog\/posts\/cpp\/0858\/\">Linux kernel turns 30: congratulations from PVS-Studio<\/a>&#187; article. Do read the article, if you haven&#8217;t already. You&#8217;ll find nice old-school pictures \ud83d\ude42<\/p>\n<h3>5th: intermodular analysis and lost memset<\/h3>\n<p>This year, the PVS-Studio developers added one major and necessary feature \u2013 intermodular analysis of C++ projects. Intermodular analysis helped to find this warning in the <a href=\"https:\/\/github.com\/eranif\/codelite\">codelite<\/a> project.<\/p>\n<p><a href=\"https:\/\/pvs-studio.com\/en\/docs\/warnings\/v597\/\">V597<\/a> The compiler could delete the &#8216;memset&#8217; function call, which is used to flush &#8216;current&#8217; object. The memset_s() function should be used to erase the private data. args.c 269<\/p>\n<pre><code class=\"cpp\">\/\/ args.c extern void eFree (void *const ptr);  extern void argDelete (Arguments* const current) {   Assert (current != NULL);   if (current->type ==  ARG_STRING  &amp;&amp;  current->item != NULL)     eFree (current->item);   memset (current, 0, sizeof (Arguments));  \/\/ &lt;=   eFree (current);                          \/\/ &lt;= }  \/\/ routines.c extern void eFree (void *const ptr) {   Assert (ptr != NULL);   free (ptr); } <\/code><\/pre>\n<p>LTO (Link Time Optimization) may optimize out the <em>memset<\/em> call. The compiler, using the <a href=\"https:\/\/en.cppreference.com\/w\/cpp\/language\/as_if\">as-if<\/a> rule, figures out that <em>eFree<\/em> doesn&#8217;t calculate any useful pointer-related data. <em>eFree<\/em> only calls the <em>free<\/em> function that frees memory.<\/p>\n<p>Without LTO, the <em>eFree<\/em> call looks like an unknown external function, so <em>memset<\/em> will remain.<\/p>\n<p>This error was described in the following article: &#171;<a href=\"https:\/\/pvs-studio.com\/en\/blog\/posts\/cpp\/0851\/\">Intermodular analysis of C++ projects in PVS-Studio<\/a>&#171;.<\/p>\n<h3>4th: senseless check &amp;&amp; Unreal Engine<\/h3>\n<p>Recently, PVS-Studio enhanced the check of Unreal Engine projects. My colleague wrote an article, describing this in detail \u2013 you&#8217;ll find the link below. First, let&#8217;s take a look at an interesting error that the analyzer found.<\/p>\n<p><a href=\"https:\/\/pvs-studio.com\/en\/docs\/warnings\/v547\/\">V547<\/a> Expression &#8216;m_trail == 0&#8217; is always false. unpack.hpp 699<\/p>\n<pre><code class=\"cpp\">std::size_t m_trail;  .... inline int context::execute(const char* data, std::size_t len,  std::size_t&amp; off) {   ....   case MSGPACK_CS_EXT_8: {                 uint8_t tmp;                 load&lt;uint8_t>(tmp, n);                 m_trail = tmp + 1;                 if(m_trail == 0) {                     unpack_ext(m_user, n, m_trail, obj);                     int ret = push_proc(obj, off);                     if (ret != 0) return ret;                 }                 else {                     m_cs = MSGPACK_ACS_EXT_VALUE;                     fixed_trail_again = true;                 }             } break;   .... } <\/code><\/pre>\n<p>Let&#8217;s see what&#8217;s going on in this code fragment.<\/p>\n<p>We have the <em>tmp<\/em> variable of the <em>uint8_t<\/em> type. Its value is limited with eight bits \u2013 <em>[0, 255]<\/em>. The programmer who wrote this code assumes that <em>tmp<\/em> can be <em>255<\/em>. After the <em>m_trail = tmp + 1<\/em> assignment, they check that there&#8217;s no integer overflow. An unsigned integer arithmetic can cause a wrap around.  So, the result of the <em>tmp + 1<\/em> operation can be <em>0<\/em>.<\/p>\n<p>However, the analyzer says that the <em>m_trail == 0<\/em> check<\/p>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-388523","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/388523","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=388523"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/388523\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=388523"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=388523"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=388523"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}