{"id":405512,"date":"2024-06-29T18:22:07","date_gmt":"2024-06-29T18:22:07","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=405512"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=405512","title":{"rendered":"<span>Checking QEMU using PVS-Studio<\/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-1\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/post_images\/a1f\/6ef\/6ac\/a1f6ef6acfaffd9b6db3abd1167472cc.png\" alt=\"image1.png\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/a1f\/6ef\/6ac\/a1f6ef6acfaffd9b6db3abd1167472cc.png\"\/><\/div>\n<p>  QEMU is a rather well-known application for emulation. Static analysis can help developers of complex projects such as QEMU catch errors at early stages and generally improve quality and reliability of a project. In this article, we will check the source code of the QEMU application for potential vulnerabilities and errors using the PVS-Studio static analysis tool.<br \/>  <a name=\"habracut\"><\/a><br \/>  QEMU is free software designed to emulate the hardware of various platforms. It allows you to run applications and operating systems on hardware platforms that are different from target ones. For example, it is possible to run an application written for MIPS for the x86 architecture. QEMU also supports emulation of various peripherals, such as video cards, usb, etc. The project is quite complex and worthy of attention. Such projects are of interest in terms of static analysis, so we decided to scan its code using PVS-Studio.<\/p>\n<h2>About the analysis<\/h2>\n<p>  The source code of the project can be obtained from the mirror on <a href=\"https:\/\/github.com\/qemu\/qemu\">github<\/a>. The project is quite large and can be compiled for various platforms. For easier code checking, let&#8217;s use the <a href=\"https:\/\/www.viva64.com\/en\/m\/0031\/\">PVS-Studio compilation monitoring system<\/a>. This system is designed for very simple integration of static analysis into almost any build platform. The system is based on tracking compiler calls during the build and allows you to collect all the information for later files analysis. In other words, we just run the build, PVS-Studio collects the necessary information, and then we run the analysis \u2014 everything is simple. Details can be found by the link above.<\/p>\n<p>  After checking, the analyzer found a lot of potential problems. As for diagnostics related to general analysis, we got: 1940 diagnostics of High level, 1996 \u2014 Medium level, 9596 \u2014 Low level. After viewing all the warnings, I decided to focus on the diagnostics of the High level of certainty. There were quite a few such warnings (1940), but most of them are either of the same type or are associated with repeated use of a suspicious macro. For example, let&#8217;s take a look at the <i>g_new<\/i> macro.<\/p>\n<pre><code class=\"cpp\">#define g_new(struct_type, n_structs)                         _G_NEW (struct_type, n_structs, malloc)  #define _G_NEW(struct_type, n_structs, func)       \\   (struct_type *) (G_GNUC_EXTENSION ({             \\     gsize __n = (gsize) (n_structs);               \\     gsize __s = sizeof (struct_type);              \\     gpointer __p;                                  \\     if (__s == 1)                                  \\       __p = g_##func (__n);                        \\     else if (__builtin_constant_p (__n) &amp;&amp;         \\              (__s == 0 || __n &lt;= G_MAXSIZE \/ __s)) \\       __p = g_##func (__n * __s);                  \\     else                                           \\       __p = g_##func##_n (__n, __s);               \\     __p;                                           \\   }))<\/code><\/pre>\n<p>  For each use of this macro, the analyzer issues the V773 warning (Visibility scope of the &#8216;__p&#8217; pointer was exited without releasing the memory. A memory leak is possible). The <i>g_new<\/i> macro is defined in the glib library, it uses the <i>_g_new<\/i> macro, and this macro in turn uses another <i>G_GNUC_EXTENSION<\/i> macro that tells the GCC compiler to skip warnings about non-standard code. It is this non-standard code that triggers the analyzer&#8217;s warning. Just look as the last but one line of code. In fact, the macro is valid. There were 848 warnings of this type, which means that almost half of the warnings occur in just one single place in the code.<\/p>\n<p>  All these unnecessary warnings can be easily <a href=\"https:\/\/www.viva64.com\/en\/b\/0523\/\">removed<\/a> using the analyzer settings. However, this particular case, which occurred when writing the article, is the reason for our team to slightly refine the logic of the analyzer for such situations.<\/p>\n<p>  Thus, a large number of warnings doesn&#8217;t always indicate poor code quality. However, there are some really suspicious places. Well, let&#8217;s get down to reviewing the warnings.<\/p>\n<p>  <b>Warning N1<\/b><\/p>\n<p>  <a href=\"https:\/\/www.viva64.com\/en\/w\/v517\/\">V517<\/a> The use of &#8216;if (A) {&#8230;} else if (A) {&#8230;}&#8217; pattern was detected. There is a probability of logical error presence. Check lines: 2395, 2397. megasas.c 2395<\/p>\n<pre><code class=\"cpp\">#define MEGASAS_MAX_SGE 128             \/* Firmware limit *\/ .... static void megasas_scsi_realize(PCIDevice *dev, Error **errp) {   ....   if (s->fw_sge >= MEGASAS_MAX_SGE - MFI_PASS_FRAME_SIZE) {     ....   } else if (s->fw_sge >= 128 - MFI_PASS_FRAME_SIZE) {     ....   }   .... }<\/code><\/pre>\n<p>  Any use of &#171;magic&#187; numbers in the code is always suspicious. There are two conditions here, and at a first glance, they seem different, but if you look at the value of the <i>MEGASAS_MAX_SGE<\/i> macro, it turns out that the conditions duplicate each other. Most likely, there is a typo and a different number should be written instead of 128. Sure, this is the problem with all &#171;magic&#187; numbers, one can easily mistype them. Using macros and constants will help a developer a lot in this case.<\/p>\n<p>  <b>Warning N2<\/b><\/p>\n<p>  <a href=\"https:\/\/www.viva64.com\/en\/w\/v523\/\">V523<\/a> The &#8216;then&#8217; statement is equivalent to the &#8216;else&#8217; statement. cp0_helper.c 383<\/p>\n<pre><code class=\"cpp\">target_ulong helper_mftc0_cause(CPUMIPSState *env) {   ....   CPUMIPSState *other = mips_cpu_map_tc(env, &amp;other_tc);    if (other_tc == other->current_tc) {     tccause = other->CP0_Cause;   } else {     tccause = other->CP0_Cause;   }   .... }<\/code><\/pre>\n<p>  In the code above, <i>then<\/i> and <i>else<\/i> bodies of the <i>if<\/i> statement are identical. Most likely, it&#8217;s copy-paste. The author just copied the body of <i>then<\/i> branch, and forgot to fix it. As far as I can see, <i>env<\/i> should have been used instead of the <i>other<\/i> object. Fixing this suspicious place can look like this: <\/p>\n<pre><code class=\"cpp\">if (other_tc == other->current_tc) {   tccause = other->CP0_Cause; } else {   tccause = env->CP0_Cause; }<\/code><\/pre>\n<p>  Only the developers of this code can clearly say how it should actually be. Another similar fragment:<\/p>\n<ul>\n<li>V523 The &#8216;then&#8217; statement is equivalent to the &#8216;else&#8217; statement. translate.c 641<\/li>\n<\/ul>\n<p>  <b>Warning N3<\/b><\/p>\n<p>  <a href=\"https:\/\/www.viva64.com\/en\/w\/v547\/\">V547<\/a> Expression &#8216;ret &lt; 0&#8217; is always false. qcow2-cluster.c 1557<\/p>\n<pre><code class=\"cpp\">static int handle_dependencies(....) {   ....   if (end &lt;= old_start || start >= old_end) {     ....   } else {      if (bytes == 0 &amp;&amp; *m) {       ....       return 0;           \/\/ &lt;= 3     }      if (bytes == 0) {       ....       return -EAGAIN;     \/\/ &lt;= 4     }   ....   }   return 0;               \/\/ &lt;= 5 }  int qcow2_alloc_cluster_offset(BlockDriverState *bs, ....) {   ....   ret = handle_dependencies(bs, start, &amp;cur_bytes, m);   if (ret == -EAGAIN) {   \/\/ &lt;= 2     ....   } else if (ret &lt; 0) {   \/\/ &lt;= 1     ....   } }<\/code><\/pre>\n<p>  Here, the analyzer found that the condition (comment 1) will never be met. The value of the <i>ret<\/i> variable is initialized by the result of executing the <i>handle_dependencies<\/i> function. This function returns only <i>0<\/i> or <i>-EAGAIN<\/i> (comments 3, 4, 5). Just above, in the first condition, we checked the value of ret for <i>-EAGAIN<\/i> (comment 2), so the result of executing the expression <i>ret &lt; 0<\/i> will always be false. It is possible that the <i>handle_dependencies<\/i> function used to return other values, but then, as a result of refactoring, for example, the behavior changed. Here one just has to complete the refactoring. Similar warnings:<\/p>\n<ul>\n<li>V547 Expression is always false. qcow2.c 1070<\/li>\n<li>V547 Expression &#8216;s->state != MIGRATION_STATUS_COLO&#8217; is always false. colo.c 595<\/li>\n<li>V547 Expression &#8216;s->metadata_entries.present &amp; 0x20&#8217; is always false. vhdx.c 769<\/li>\n<\/ul>\n<p>  <b>Warning N4<\/b><\/p>\n<p>  <a href=\"https:\/\/www.viva64.com\/en\/w\/v557\/\">V557<\/a> Array overrun is possible. The &#8216;dwc2_glbreg_read&#8217; function processes value &#8216;[0..63]&#8217;. Inspect the third argument. Check lines: 667, 1040. hcd-dwc2.c 667<\/p>\n<pre><code class=\"cpp\">#define HSOTG_REG(x) (x)                                             \/\/ &lt;= 5 .... struct DWC2State {   .... #define DWC2_GLBREG_SIZE    0x70   uint32_t glbreg[DWC2_GLBREG_SIZE \/ sizeof(uint32_t)];              \/\/ &lt;= 1   .... } .... static uint64_t dwc2_glbreg_read(void *ptr, hwaddr addr, int index,                                  unsigned size) {   ....   val = s->glbreg[index];                                            \/\/ &lt;= 2   .... } static uint64_t dwc2_hsotg_read(void *ptr, hwaddr addr, unsigned size) {   ....   switch (addr) {     case HSOTG_REG(0x000) ... HSOTG_REG(0x0fc):                      \/\/ &lt;= 4         val = dwc2_glbreg_read(ptr, addr,                               (addr - HSOTG_REG(0x000)) >> 2, size); \/\/ &lt;= 3     ....   }   .... }<\/code><\/pre>\n<p>  This code has a potential problem \u2014 an index outside the array bounds. The <i>DWC2State<\/i> structure defines a <i>glbreg<\/i> array consisting of 28 elements (comment 1). In the <i>dwc2_glbreg_read<\/i> function, our array is accessed by index (comment 2). Now note that the function <i>dwc2_glbreg_read<\/i> is passed the expression (<i>addr \u2014 HSOTG_REG(0x000)) >> 2 <\/i> (comment 3) as an index, which can take a value in the range [0..63]. To make sure of it, pay attention to comments 4 and 5. Perhaps, the range of values from comment 4 has to be fixed.<\/p>\n<p>  More similar warnings:<\/p>\n<ul>\n<li>V557 Array overrun is possible. The &#8216;dwc2_hreg0_read&#8217; function processes value &#8216;[0..63]&#8217;. Inspect the third argument. Check lines: 814, 1050. hcd-dwc2.c 814<\/li>\n<li>V557 Array overrun is possible. The &#8216;dwc2_hreg1_read&#8217; function processes value &#8216;[0..191]&#8217;. Inspect the third argument. Check lines: 927, 1053. hcd-dwc2.c 927<\/li>\n<li>V557 Array overrun is possible. The &#8216;dwc2_pcgreg_read&#8217; function processes value &#8216;[0..127]&#8217;. Inspect the third argument. Check lines: 1012, 1060. hcd-dwc2.c 1012<\/li>\n<\/ul>\n<p>  <b>Warning N5<\/b><\/p>\n<p>  <a href=\"https:\/\/www.viva64.com\/en\/w\/v575\/\">V575<\/a> The &#8216;strerror_s&#8217; function processes &#8216;0&#8217; elements. Inspect the second argument. commands-win32.c 1642<\/p>\n<pre><code class=\"cpp\">void qmp_guest_set_time(bool has_time, int64_t time_ns,                          Error **errp) {   ....   if (GetLastError() != 0) {     strerror_s((LPTSTR) &amp; msg_buffer, 0, errno);     ....   } }<\/code><\/pre>\n<p>  The <i>strerror_s<\/i> function returns the text description of the system error code. Its signature looks like this: <\/p>\n<pre><code class=\"cpp\">errno_t strerror_s( char *buf, rsize_t bufsz, errno_t errnum );<\/code><\/pre>\n<p>  The first parameter is a pointer to the buffer where the text description will be copied, the second parameter is the buffer size, and the third parameter \u2014 the error code. The code passes 0 as the buffer size, which is clearly an incorrect value. By the way, it is possible to find out in advance how many bytes to allocate: one just needs to call <i>strerrorlen_s<\/i>, which returns the length of the error text description. This value can be used to allocate a buffer of sufficient size.<\/p>\n<p>  <b>Warning N6<\/b><\/p>\n<p>  <a href=\"https:\/\/www.viva64.com\/en\/w\/v595\/\">V595<\/a> The &#8216;blen2p&#8217; pointer was utilized before it was verified against nullptr. Check lines: 103, 106. dsound_template.h 103<\/p>\n<pre><code class=\"cpp\">static int glue (     ....     DWORD *blen1p,     DWORD *blen2p,     int entire,     dsound *s     ) {   ....   dolog(\"DirectSound returned misaligned buffer %ld %ld\\n\",         *blen1p, *blen2p);                         \/\/ &lt;= 1   glue(.... p2p ? *p2p : NULL, *blen1p,                             blen2p ? *blen2p : 0); \/\/ &lt;= 2 .... }<\/code><\/pre>\n<p>  In this code, the value of the <i>blen2p<\/i> argument is first used (comment 1), and then checked for <i>nullptr<\/i> (comment 2). This extremely suspicious place looks as if one just forgot to insert a check before the first use (comment 1). As a correction option, one can just add a check:<\/p>\n<pre><code class=\"cpp\">dolog(\"DirectSound returned misaligned buffer %ld %ld\\n\",       *blen1p, blen2p ? *blen2p : 0);<\/code><\/pre>\n<p>  There is also a question about the <i>blen1p<\/i> argument. It can probably also be a null pointer, and you will also need to add a check here. A few more similar warnings:<\/p>\n<ul>\n<li>V595 The &#8216;ref&#8217; pointer was utilized before it was verified against nullptr. Check lines: 2191, 2193. uri.c 2191<\/li>\n<li>V595 The &#8216;cmdline&#8217; pointer was utilized before it was verified against nullptr. Check lines: 420, 425. qemu-io.c 420<\/li>\n<li>V595 The &#8216;dp&#8217; pointer was utilized before it was verified against nullptr. Check lines: 288, 294. onenand.c 288<\/li>\n<li>V595 The &#8216;omap_lcd&#8217; pointer was utilized before it was verified against nullptr. Check lines: 81, 87. omap_lcdc.c 81<\/li>\n<\/ul>\n<p>  <b>Warning N7<\/b><\/p>\n<p>  <a href=\"https:\/\/www.viva64.com\/en\/w\/v597\/\">V597<\/a> The compiler could delete the &#8216;memset&#8217; function call, which is used to flush &#8216;op_info&#8217; object. The RtlSecureZeroMemory() function should be used to erase the private data. virtio-crypto.c 354<\/p>\n<pre><code class=\"cpp\">static void virtio_crypto_free_request(VirtIOCryptoReq *req) {   if (req) {     if (req->flags == CRYPTODEV_BACKEND_ALG_SYM) {       ....       \/* Zeroize and free request data structure *\/       memset(op_info, 0, sizeof(*op_info) + max_len); \/\/ &lt;= 1       g_free(op_info);     }     g_free(req);   } }<\/code><\/pre>\n<p>  In this code fragment, the <i>memset<\/i> function is called for the <i>op_info<\/i> object (comment 1). After that, <i>op_info<\/i> is immediately deleted. In other words, after clearing, this object isn&#8217;t modified anywhere else. This is exactly the case when the compiler can delete the <i>memset<\/i> call during optimization. To avoid this potential behavior, you can use special functions that the compiler never deletes. See also the article &#171;<a href=\"https:\/\/www.viva64.com\/en\/b\/0388\/\">Safe Clearing of Private Data<\/a>&#171;.<\/p>\n<p>  <b>Warning N8<\/b><\/p>\n<p>  <a href=\"https:\/\/www.viva64.com\/en\/w\/v610\/\">V610<\/a> Unspecified behavior. Check the shift operator &#8216;>>&#8217;. The left operand is negative (&#8216;number&#8217; = [-32768..2147483647]). cris.c 2111<\/p>\n<pre><code class=\"cpp\">static void print_with_operands (const struct cris_opcode *opcodep,          unsigned int insn,          unsigned char *buffer,          bfd_vma addr,          disassemble_info *info,          const struct cris_opcode *prefix_opcodep,          unsigned int prefix_insn,          unsigned char *prefix_buffer,          bfd_boolean with_reg_prefix) {   ....   int32_t number;   ....   if (signedp &amp;&amp; number > 127)     number -= 256;            \/\/ &lt;= 1   ....   if (signedp &amp;&amp; number > 32767)     number -= 65536;          \/\/ &lt;= 2   ....   unsigned int highbyte = (number >> 24) &amp; 0xff;   .... }<\/code><\/pre>\n<p>  Since the <i>number<\/i> variable can have a negative value, a bitwise shift to the right is an unspecified behavior. To make sure that the variable in question can take a negative value, look at comments 1 and 2. To eliminate differences in the behavior of your code on different platforms, you should avoid such cases. <\/p>\n<p>  More warnings:<\/p>\n<ul>\n<li>V610 Undefined behavior. Check the shift operator &#8216;&lt;&lt;&#8216;. The left operand is negative (&#8216;(hclk_div \u2014 1)&#8217; = [-1..15]). aspeed_smc.c 1041<\/li>\n<li>V610 Undefined behavior. Check the shift operator &#8216;&lt;&lt;&#8216;. The left operand &#8216;(target_long) \u2014 1&#8217; is negative. exec-vary.c 99<\/li>\n<li>V610 Undefined behavior. Check the shift operator &#8216;&lt;&lt;&#8216;. The left operand is negative (&#8216;hex2nib(words[3][i * 2 + 2])&#8217; = [-1..15]). qtest.c 561<\/li>\n<\/ul>\n<p>  There are also several warnings of the same type, the difference is that the left operand is <i>-1<\/i>.<\/p>\n<p>  <a href=\"https:\/\/www.viva64.com\/en\/w\/v610\/\">V610<\/a> Undefined behavior. Check the shift operator &#8216;&lt;&lt;&#8216;. The left operand &#8216;-1&#8217; is negative. hppa.c 2702<\/p>\n<pre><code class=\"cpp\">int print_insn_hppa (bfd_vma memaddr, disassemble_info *info) {   ....   disp = (-1 &lt;&lt; 10) | imm10;   .... }<\/code><\/pre>\n<p>  Other similar warnings:<\/p>\n<ul>\n<li>V610 Undefined behavior. Check the shift operator &#8216;&lt;&lt;&#8216;. The left operand &#8216;-1&#8217; is negative. hppa.c 2718<\/li>\n<li>V610 Undefined behavior. Check the shift operator &#8216;&lt;&lt;&#8216;. The left operand &#8216;-0x8000&#8217; is negative. fmopl.c 1022<\/li>\n<li>V610 Undefined behavior. Check the shift operator &#8216;&lt;&lt;&#8216;. The left operand &#8216;(intptr_t) \u2014 1&#8217; is negative. sve_helper.c 889<\/li>\n<\/ul>\n<p>  <b>Warning N9<\/b><\/p>\n<p>  <a href=\"https:\/\/www.viva64.com\/en\/w\/v616\/\">V616<\/a> The &#8216;TIMER_NONE&#8217; named constant with the value of 0 is used in the bitwise operation. sys_helper.c 179<\/p>\n<pre><code class=\"cpp\">#define HELPER(name) ....  enum {   TIMER_NONE = (0 &lt;&lt; 30),        \/\/ &lt;= 1   .... }  void HELPER(mtspr)(CPUOpenRISCState *env, ....) {   ....   if (env->ttmr &amp; TIMER_NONE) {  \/\/ &lt;= 2     ....   } }<\/code><\/pre>\n<p>  You can easily make sure that the value of the TIMER_NONE macro is zero (comment 1). This macro is then used in a bitwise operation, the result of which is always 0. As a result, the body of the conditional if statement <i>if (env->ttmr &amp; TIMER_NONE)<\/i> will never be executed.<\/p>\n<p>  <b>Warning N10<\/b><\/p>\n<p>  <a href=\"https:\/\/www.viva64.com\/en\/w\/v629\/\">V629<\/a> Consider inspecting the &#8216;n &lt;&lt; 9&#8217; expression. Bit shifting of the 32-bit value with a subsequent expansion to the 64-bit type. qemu-img.c 1839<\/p>\n<pre><code class=\"cpp\">#define BDRV_SECTOR_BITS   9 static int coroutine_fn convert_co_read(ImgConvertState *s,                    int64_t sector_num, int nb_sectors, uint8_t *buf) {   uint64_t single_read_until = 0;   int n;   ....   while (nb_sectors > 0) {     ....     uint64_t offset;     ....     single_read_until = offset + (n &lt;&lt; BDRV_SECTOR_BITS);     ....   }   .... }<\/code><\/pre>\n<p>  In this code fragment, the <i>n<\/i> variable of the 32-bit signed type is shifted, then this 32-bit signed result is expanded to a 64-bit signed type. After that this result is added to the <i>offset<\/i> unsigned 64-bit variable as an unsigned type. Let&#8217;s assume that at the time of executing the expression, the variable <i>n<\/i> has some significant high 9 bits. We perform a 9-bit shift operation (<i>BDRV_SECTOR_BITS<\/i>), and this, in turn, is undefined behavior, then we can get the set bit in the highest order as a result. Let me quickly remind you that this bit in the signed type is responsible for the sign, so the result can become negative. Since the n variable is of the signed type, the extension will take the sign into account. Further, the result is added to the <i>offset<\/i> variable. From these considerations, it is not difficult to see that the result of executing an expression may differ from the intended one. One possible solution is to replace the type of the <i>n<\/i> variable with a 64-bit unsigned type, i.e. <i>uint64_t<\/i>.<\/p>\n<p>  Here are other similar warnings:<\/p>\n<ul>\n<li>V629 Consider inspecting the &#8216;1 &lt;&lt; refcount_order&#8217; expression. Bit shifting of the 32-bit value with a subsequent expansion to the 64-bit type. qcow2.c 3204<\/li>\n<li>V629 Consider inspecting the &#8216;s->cluster_size &lt;&lt; 3&#8217; expression. Bit shifting of the 32-bit value with a subsequent expansion to the 64-bit type. qcow2-bitmap.c 283<\/li>\n<li>V629 Consider inspecting the &#8216;i &lt;&lt; s->cluster_bits&#8217; expression. Bit shifting of the 32-bit value with a subsequent expansion to the 64-bit type. qcow2-cluster.c 983<\/li>\n<li>V629 Consider inspecting the expression. Bit shifting of the 32-bit value with a subsequent expansion to the 64-bit type. vhdx.c 1145<\/li>\n<li>V629 Consider inspecting the &#8216;delta &lt;&lt; 2&#8217; expression. Bit shifting of the 32-bit value with a subsequent expansion to the 64-bit type. mips.c 4341<\/li>\n<\/ul>\n<p>  <b>Warning N11<\/b><\/p>\n<p>  <a href=\"https:\/\/www.viva64.com\/en\/w\/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. nand.c 310<\/p>\n<pre><code class=\"cpp\">static void nand_command(NANDFlashState *s) {   ....   s->addr &amp;= (1ull &lt;&lt; s->addrlen * 8) - 1;   .... }<\/code><\/pre>\n<p>  This fragment is simply suspicious. It is not clear what the developer wanted to do first: shift or multiplication. Even if there is no error here, one still needs to look at the code again and put the parentheses correctly. This is just one of the places that developers should check out to make sure that their algorithm is correct. Other such fragments:<\/p>\n<ul>\n<li>V634 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. exynos4210_mct.c 449<\/li>\n<li>V634 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. exynos4210_mct.c 1235<\/li>\n<li>V634 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. exynos4210_mct.c 1264<\/li>\n<\/ul>\n<p>  <b>Warning N12<\/b><\/p>\n<p>  <a href=\"https:\/\/www.viva64.com\/en\/w\/v646\/\">V646<\/a> Consider inspecting the application&#8217;s logic. It&#8217;s possible that &#8216;else&#8217; keyword is missing. pl181.c 400<\/p>\n<pre><code class=\"cpp\">static void pl181_write(void *opaque, hwaddr offset,                         uint64_t value, unsigned size) {   ....   if (s->cmd &amp; PL181_CMD_ENABLE) {     if (s->cmd &amp; PL181_CMD_INTERRUPT) {       ....     } if (s->cmd &amp; PL181_CMD_PENDING) { \/\/ &lt;= else if       ....     } else {       ....     }     ....   }   .... }<\/code><\/pre>\n<p>  In this code, judging by the formatting, the use of <i>else if<\/i> instead of <i>if<\/i> seems most attractive. Perhaps the author forgot to add <i>else<\/i> here. This way, the fragment can be fixed as follows:<\/p>\n<pre><code class=\"cpp\">} else if (s->cmd &amp; PL181_CMD_PENDING) { \/\/ &lt;= else if<\/code><\/pre>\n<p>  However, there is a chance that this code is all right, and there is incorrect formatting of the program text, which is confusing. Then the correct code could look like this:<\/p>\n<pre><code class=\"cpp\">if (s->cmd &amp; PL181_CMD_INTERRUPT) {   .... } if (s->cmd &amp; PL181_CMD_PENDING) { \/\/ &lt;= if   .... } else {   .... }<\/code><\/pre>\n<p>  <b>Warning N13<\/b><\/p>\n<p>  <a href=\"https:\/\/www.viva64.com\/en\/w\/v773\/\">V773<\/a> The function was exited without releasing the &#8216;rule&#8217; pointer. A memory leak is possible. blkdebug.c 218<\/p>\n<pre><code class=\"cpp\">static int add_rule(void *opaque, QemuOpts *opts, Error **errp) {   ....   struct BlkdebugRule *rule;   ....   rule = g_malloc0(sizeof(*rule));                   \/\/ &lt;= 1   ....   if (local_error) {     error_propagate(errp, local_error);     return -1;                                       \/\/ &lt;= 2   }   ....   \/* Add the rule *\/   QLIST_INSERT_HEAD(&amp;s->rules[event], rule, next);   \/\/ &lt;= 3   .... }<\/code><\/pre>\n<p>  In this code, the <i>rule<\/i> object is allocated (comment 1) and added to the list for later use (comment 3), but in case of an error, the function returns without deleting the previously created <i>rule<\/i> object (comment 2). The error just has to be handled correctly: one can delete the previously created object, otherwise there will be a memory leak.<\/p>\n<p>  <b>Warning N14<\/b><\/p>\n<p>  <a href=\"https:\/\/www.viva64.com\/en\/w\/v781\/\">V781<\/a> The value of the &#8216;ix&#8217; index is checked after it was used. Perhaps there is a mistake in program logic. uri.c 2110<\/p>\n<pre><code class=\"cpp\">char *uri_resolve_relative(const char *uri, const char *base) {   ....   ix = pos;   if ((ref->path[ix] == '\/') &amp;&amp; (ix > 0)) {   .... }<\/code><\/pre>\n<p>  Here, the analyzer detected a potential array index out of bounds. First, the <i>ref->path<\/i> array element is read by the <i>ix<\/i> index, and then <i>ix<\/i> is checked for correctness (<i>ix > 0<\/i>). The right solution here is to reverse these actions:<\/p>\n<pre><code class=\"cpp\">if ((ix > 0) &amp;&amp; (ref->path[ix] == '\/')) {<\/code><\/pre>\n<p>  There were several such places:<\/p>\n<ul>\n<li>V781 The value of the &#8216;ix&#8217; index is checked after it was used. Perhaps there is a mistake in program logic. uri.c 2112<\/li>\n<li>V781 The value of the &#8216;offset&#8217; index is checked after it was used. Perhaps there is a mistake in program logic. keymaps.c 125<\/li>\n<li>V781 The value of the &#8216;quality&#8217; variable is checked after it was used. Perhaps there is a mistake in program logic. Check lines: 326, 335. vnc-enc-tight.c 326<\/li>\n<li>V781 The value of the &#8216;i&#8217; index is checked after it was used. Perhaps there is a mistake in program logic. mem_helper.c 1929<\/li>\n<\/ul>\n<p>  <b>Warning N15<\/b><\/p>\n<p>  <a href=\"https:\/\/www.viva64.com\/en\/w\/v784\/\">V784<\/a> The size of the bit mask is less than the size of the first operand. This will cause the loss of higher bits. cadence_gem.c 1486<\/p>\n<pre><code class=\"cpp\">typedef struct CadenceGEMState {   ....   uint32_t regs_ro[CADENCE_GEM_MAXREG]; } .... static void gem_write(void *opaque, hwaddr offset, uint64_t val,         unsigned size) {   ....   val &amp;= ~(s->regs_ro[offset]);   .... }<\/code><\/pre>\n<p>  This code performs a bitwise operation with objects of different types. The left operand is the <i>val<\/i> argument that has a 64-bit unsigned type. The right operand is the received value of the array element <i>s->regs_ro<\/i> by the <i>offset<\/i> index, which has a 32-bit unsigned type. The result of the operation in the right side <i>(~(s->regs_ro[offset]))<\/i> is a 32-bit unsigned type. Before bitwise multiplication it will expand into the 64-bit type with zeros, that is, after evaluating the entire expression, all the higher bits of the <i>val<\/i> variable will be reset to zero. These places always look dubious. Here we can only recommend that developers review this code again. More similar fragments:<\/p>\n<ul>\n<li>V784 The size of the bit mask is less than the size of the first operand. This will cause the loss of higher bits. xlnx-zynq-devcfg.c 199<\/li>\n<li>V784 The size of the bit mask is less than the size of the first operand. This will cause the loss of higher bits. soc_dma.c 214<\/li>\n<li>V784 The size of the bit mask is less than the size of the first operand. This will cause the loss of higher bits. fpu_helper.c 418<\/li>\n<\/ul>\n<p>  <b>Warning N16<\/b><\/p>\n<p>  <a href=\"https:\/\/www.viva64.com\/en\/w\/v1046\/\">V1046<\/a> Unsafe usage of the &#8216;bool&#8217; and &#8216;unsigned int&#8217; types together in the operation &#8216;&amp;=&#8217;. helper.c 10821<\/p>\n<pre><code class=\"cpp\">static inline uint32_t extract32(uint32_t value, int start, int length); .... static ARMVAParameters aa32_va_parameters(CPUARMState *env, uint32_t va,                                           ARMMMUIdx mmu_idx) {   ....   bool epd, hpd;   ....   hpd &amp;= extract32(tcr, 6, 1); }<\/code><\/pre>\n<p>  In this code snippet, a bitwise AND operation is performed with the <i>hpd<\/i> variable, which has the <i>bool<\/i> type, and with the result of executing the <i>extract32<\/i> function, which is of the <i>uint32_t<\/i> type. Since the bit value of a boolean variable can only be 0 or 1, the result of the expression will always be <i>false<\/i> if the lowest bit returned by the <i>extract32<\/i> function is zero. Let&#8217;s consider this case using the example. Let&#8217;s assume that the <i>hpd<\/i> value is true, and the function returns the value 2. So in the binary representation, the operation will look like 01 &amp; 10 = 0, and the result of the expression will be <i>false<\/i>. Most likely, the programmer wanted to set the <i>true<\/i> value if the function returns something other than zero. Apparently, one has to fix the code so that the result of executing the function is cast to the <i>bool<\/i> type, for example, like this:<\/p>\n<pre><code class=\"cpp\">hpd = hpd &amp;&amp; (bool)extract32(tcr, 6, 1);<\/code><\/pre>\n<p>  <\/p>\n<h2>Conclusion<\/h2>\n<p>  As you can see, the analyzer found a lot of hinky places. It is possible that these potential problems so far do not manifest themselves in any way, but their presence can not but worry, since they are able to reveal themselves at the most unexpected moment. It&#8217;s better to view all iffy places in advance and tweak them than keep fixing an endless flow of bugs. Obviously, for complex projects like this, static analysis can bring significant benefits, especially if you organize regular checks of the project. If you want to try PVS-Studio for your project, you can download the analyzer and get a free trial key on <a href=\"https:\/\/www.viva64.com\/en\/pvs-studio-download\/\">this<\/a> page.<\/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\/517792\/\"> https:\/\/habr.com\/ru\/articles\/517792\/<\/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-1\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/post_images\/a1f\/6ef\/6ac\/a1f6ef6acfaffd9b6db3abd1167472cc.png\" alt=\"image1.png\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/a1f\/6ef\/6ac\/a1f6ef6acfaffd9b6db3abd1167472cc.png\"\/><\/div>\n<p>  QEMU is a rather well-known application for emulation. Static analysis can help developers of complex projects such as QEMU catch errors at early stages and generally improve quality and reliability of a project. In this article, we will check the source code of the QEMU application for potential vulnerabilities and errors using the PVS-Studio static analysis tool.  <\/p>\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-405512","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/405512","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=405512"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/405512\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=405512"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=405512"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=405512"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}