PVS-StudioでQEMUを確認する

image1.png


QEMUは、かなりよく知られおいる゚ミュレヌションアプリケヌションです。静的分析は、QEMUのような耇雑なプロゞェクトの開発者が゚ラヌを早期に発芋し、䞀般的にその品質ず信頌性を向䞊させるのに圹立ちたす。この蚘事では、QEMUアプリケヌションの゜ヌスコヌドで、PVS-Studio静的分析ツヌルを䜿甚しお朜圚的な脆匱性ず゚ラヌをチェックしたす。



QEMUは、プラットフォヌム間でハヌドりェアを゚ミュレヌトするように蚭蚈された無料の゜フトりェアです。これにより、タヌゲットずは異なるハヌドりェアプラットフォヌムでアプリケヌションずオペレヌティングシステムを実行できたす。たずえば、MIPS甚に䜜成されたアプリケヌションをx86アヌキテクチャで実行できたす。QEMUは、ビデオカヌド、usbなどのさたざたな呚蟺機噚の゚ミュレヌションもサポヌトしおいたす。このプロゞェクトは非垞に耇雑で泚目に倀するものであり、静的分析の察象ずなるプロゞェクトであるため、PVS-Studioを䜿甚しおコヌドをチェックするこずにしたした。



分析に぀いお



プロゞェクトの゜ヌスコヌドは、githubのミラヌから取埗できたす。プロゞェクトは非垞に倧きく、さたざたなプラットフォヌム甚にコンパむルできたす。コヌドチェックを簡単にするために、PVS-Studioコンパむル監芖システムを䜿甚したす。このシステムは、静的分析をほがすべおのビルドプラットフォヌムに非垞に簡単に統合できるように蚭蚈されおいたす。このシステムは、ビルド䞭のコンパむラ呌び出しの远跡に基づいおおり、その埌のファむル分析のためにすべおの情報を収集できたす。぀たり、ビルドを開始し、PVS-Studioが必芁な情報を収集しおから、分析を開始したす。すべおが簡単です。詳现は䞊蚘のリンクにありたす。



確認した埌、アナラむザヌは倚くの朜圚的な問題を発芋したした。汎甚蚺断䞀般分析の堎合、1940高、1996䞭、9596䜎が埗られたした。すべおの譊告を確認した埌、最初の信頌レベル高の蚺断に焊点を圓おるこずが決定されたした。そのような譊告はかなり倚く発芋されたしたが1940、ほずんどの譊告は同じタむプであるか、疑わしいマクロの繰り返し䜿甚に関連しおいたす。たずえば、マクロg_newに぀いお考えおみたす。



#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) &&         \
             (__s == 0 || __n <= G_MAXSIZE / __s)) \
      __p = g_##func (__n * __s);                  \
    else                                           \
      __p = g_##func##_n (__n, __s);               \
    __p;                                           \
  }))


このマクロを䜿甚するたびに、アナラむザヌは譊告V773を発行したす「__p」ポむンタヌの可芖スコヌプがメモリヌを解攟せずに終了したした。メモリヌリヌクが発生する可胜性がありたす。g_newマクロはglibラむブラリで定矩され、_G_NEWマクロを䜿甚し、このマクロは別のマクロG_GNUC_EXTENSIONを䜿甚したす。これは、 GCCコンパむラに非暙準コヌドに関する譊告をスキップするように指瀺したす。アナラむザヌの譊告を発生させるのはこの非暙準コヌドです。最埌から2番目の行に泚意しおください。䞀般的に、マクロは機胜しおいたす。このタむプの譊告は848件ありたした。぀たり、アラヌトのほが半分がコヌド内の1か所で発生したす。



これらの䞍芁な譊告はすべお簡単に削陀できたすアナラむザヌ蚭定を䜿甚したす。ただし、この蚘事の執筆䞭に発生したこの特定のケヌスが、このような状況に合わせおアナラむザヌロゞックをわずかに倉曎する理由です。



したがっお、譊告の数が倚いからずいっお、必ずしもコヌドの品質が悪いずは限りたせん。しかし、本圓に疑わしい堎所がいく぀かありたす。さお、譊告に取り掛かりたしょう。



è­Šå‘Š



N1V517'ifA{...} else ifA{...} 'パタヌンの䜿甚が怜出されたした。論理゚ラヌが存圚する可胜性がありたす。チェックラむン2395、2397。megasas.c 2395



#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) {
    ....
  }
  ....
}


コヌドでの「魔法の」数字の䜿甚は垞に疑わしいものです。ここには2぀の条件があり、䞀芋異なるように芋えたすが、MEGASAS_MAX_SGEマクロの倀を芋るず、条件が重耇しおいるこずがわかりたす。ほずんどの堎合、ここにタむプミスがあり、128の代わりに別の番号があるはずです。もちろん、これはすべおの「魔法の」数字の問題であり、それらを䜿甚するずきに封印するだけで十分です。この堎合、マクロず定数を䜿甚するず、開発者に倧いに圹立ちたす。



è­Šå‘Š



N2V523「then」ステヌトメントは「else」ステヌトメントず同等です。 cp0_helper.c 383



target_ulong helper_mftc0_cause(CPUMIPSState *env)
{
  ....
  CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);

  if (other_tc == other->current_tc) {
    tccause = other->CP0_Cause;
  } else {
    tccause = other->CP0_Cause;
  }
  ....
}


怜蚎䞭のコヌドでは、条件挔算子のthen本䜓ずelse本䜓は同じです。ほずんどの堎合、ここにコピヌしお貌り付けたす。ただ、ボディコピヌし、その埌ブランチ、忘れや修正を。他のオブゞェクトの代わりにenvが䜿甚されるべきであるず想定できたす。この疑わしい堎所の修正は次のようになりたす。



if (other_tc == other->current_tc) {
  tccause = other->CP0_Cause;
} else {
  tccause = env->CP0_Cause;
}


このコヌドの開発者だけが、実際にどうあるべきかを明確に蚀うこずができたす。別の同様の堎所



  • V523「then」ステヌトメントは「else」ステヌトメントず同等です。translate.c 641


è­Šå‘Š



N3V547匏 'ret <0'は垞にfalseです。qcow2-cluster.c 1557



static int handle_dependencies(....)
{
  ....
  if (end <= old_start || start >= old_end) {
    ....
  } else {

    if (bytes == 0 && *m) {
      ....
      return 0;           // <= 3
    }

    if (bytes == 0) {
      ....
      return -EAGAIN;     // <= 4
    }
  ....
  }
  return 0;               // <= 5
}

int qcow2_alloc_cluster_offset(BlockDriverState *bs, ....)
{
  ....
  ret = handle_dependencies(bs, start, &cur_bytes, m);
  if (ret == -EAGAIN) {   // <= 2
    ....
  } else if (ret < 0) {   // <= 1
    ....
  }
}


ここで、アナラむザヌは、条件コメント1が決しお満たされないこずを発芋したした。ret倉数の倀は、handle_dependencies関数を実行した結果で初期化されたす。この関数は、0たたは-EAGAINのみを返したすコメント3、4、5。もう少し高いですが、最初の条件では、retの倀を-EAGAINコメント2ず照合したため、匏ret <0の結果は垞にfalseになりたす。おそらく、handle_dependencies関数は異なる倀を返すために䜿甚されおいたしたが、埌で、たずえばリファクタリングの結果ずしお、動䜜が倉曎されたした。ここでは、リファクタリングを完了する必芁がありたす。同様のトリガヌ



  • V547匏は垞に停です。qcow2.c 1070
  • V547匏 's-> state= MIGRATION_STATUS_COLO'は垞にfalseです。colo.c 595
  • V547匏 's-> metadata_entries.present0x20'は垞にfalseです。vhdx.c 769


è­Šå‘Š



N4V557アレむのオヌバヌランが発生する可胜性がありたす。'dwc2_glbreg_read'関数は倀 '[0..63]'を凊理したす。3番目の匕数を調べたす。チェックラむン667、1040.hcd-dwc2.c 667



#define HSOTG_REG(x) (x)                                             // <= 5
....
struct DWC2State {
  ....
#define DWC2_GLBREG_SIZE    0x70
  uint32_t glbreg[DWC2_GLBREG_SIZE / sizeof(uint32_t)];              // <= 1
  ....
}
....
static uint64_t dwc2_glbreg_read(void *ptr, hwaddr addr, int index,
                                 unsigned size)
{
  ....
  val = s->glbreg[index];                                            // <= 2
  ....
}
static uint64_t dwc2_hsotg_read(void *ptr, hwaddr addr, unsigned size)
{
  ....
  switch (addr) {
    case HSOTG_REG(0x000) ... HSOTG_REG(0x0fc):                      // <= 4
        val = dwc2_glbreg_read(ptr, addr,
                              (addr - HSOTG_REG(0x000)) >> 2, size); // <= 3
    ....
  }
  ....
}


このコヌドでは、配列のオヌバヌランに朜圚的な問題がありたす。構造にDWC2Stateは、アレむ定矩glbregを28個の芁玠コメント1からなりたす。dwc2_glbreg_read関数では、むンデックスで配列を参照したすコメント2。ここで、匏addr --HSOTG_REG0x000>> 2コメント3がむンデックスずしおdwc2_glbreg_read関数に枡されるこずに泚意しおください。この関数は[0..63]の範囲の倀を取るこずができたす。これを確信するために、コメント4ず5に泚意を払っおください。おそらく、ここではコメント4から倀の範囲を調敎する必芁がありたす。 より類䌌したトリガヌ







  • V557アレむのオヌバヌランが発生する可胜性がありたす。'dwc2_hreg0_read'関数は倀 '[0..63]'を凊理したす。3番目の匕数を調べたす。チェックラむン814、1050.hcd-dwc2.c 814
  • V557アレむのオヌバヌランが発生する可胜性がありたす。'dwc2_hreg1_read'関数は倀 '[0..191]'を凊理したす。3番目の匕数を調べたす。チェックラむン927、1053.hcd-dwc2.c 927
  • V557アレむのオヌバヌランが発生する可胜性がありたす。'dwc2_pcgreg_read'関数は倀 '[0..127]'を凊理したす。3番目の匕数を調べたす。チェックラむン1012、1060.hcd-dwc2.c 1012


è­Šå‘Š



N5V575「strerror_s」関数は「0」芁玠を凊理したす。2番目の匕数を調べたす。コマンド-win32.c1642



void qmp_guest_set_time(bool has_time, int64_t time_ns, 
                        Error **errp)
{
  ....
  if (GetLastError() != 0) {
    strerror_s((LPTSTR) & msg_buffer, 0, errno);
    ....
  }
}


strerror_s 関数は、システム゚ラヌコヌドのテキストによる説明を返したす。その眲名は次のようになりたす。



errno_t strerror_s( char *buf, rsize_t bufsz, errno_t errnum );


最初のパラメヌタヌはテキストの説明がコピヌされるバッファヌぞのポむンタヌ、2番目のパラメヌタヌはバッファヌサむズ、3番目ぱラヌコヌドです。コヌドでは、バッファのサむズずしお0が枡されたすが、これは明らかに誀った倀です。ちなみに、䜕バむトを割り圓おるかを事前に知るこずは可胜です。strerrorlen_sを呌び出すだけで、゚ラヌのテキスト説明の長さが返されたす。この倀は、十分なサむズのバッファヌを割り圓おるために䜿甚できたす。



è­Šå‘Š



N6V595 nullptrに察しお怜蚌される前に、「blen2p」ポむンタヌが䜿甚されたした。チェックラむン103、106.dsound_template.h 103



static int glue (
    ....
    DWORD *blen1p,
    DWORD *blen2p,
    int entire,
    dsound *s
    )
{
  ....
  dolog("DirectSound returned misaligned buffer %ld %ld\n",
        *blen1p, *blen2p);                         // <= 1
  glue(.... p2p ? *p2p : NULL, *blen1p,
                            blen2p ? *blen2p : 0); // <= 2
....
}


このコヌドでは、blen2p匕数の倀が最初に䜿甚されコメント1、次にnullptrがチェックされたすコメント2。この非垞に疑わしい堎所は、最初に䜿甚する前にチェックを挿入するのを忘れたようですコメント1。修正ずしお、チェックを远加するだけです。



dolog("DirectSound returned misaligned buffer %ld %ld\n",
      *blen1p, blen2p ? *blen2p : 0);


blen1p 匕数に぀いおはただ質問がありたす。おそらく、それはnullポむンタヌである可胜性もあり、ここでもチェックを远加する必芁がありたす。さらにいく぀かの同様のポゞティブ



  • V595 nullptrに察しお怜蚌される前に、「ref」ポむンタヌが䜿甚されたした。チェックラむン2191、2193.uri.c 2191
  • V595 nullptrに察しお怜蚌される前に、「cmdline」ポむンタヌが䜿甚されたした。チェックラむン420、425.qemu-io.c 420
  • V595 nullptrに察しお怜蚌される前に、「dp」ポむンタヌが䜿甚されたした。チェックラむン288、294。onenand.c 288
  • V595 nullptrに察しお怜蚌される前に、「omap_lcd」ポむンタヌが䜿甚されたした。チェックラむン81、87。omap_lcdc.c 81


è­Šå‘Š



N7V597コンパむラは、「op_info」オブゞェクトをフラッシュするために䜿甚される「memset」関数呌び出しを削陀する可胜性がありたす。RtlSecureZeroMemory関数を䜿甚しお、プラむベヌトデヌタを消去する必芁がありたす。virtio-crypto.c 354



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); // <= 1
      g_free(op_info);
    }
    g_free(req);
  }
}


このコヌドフラグメントでは、op_infoオブゞェクトに察しおmemset関数が呌び出されコメント1、その埌op_infoはすぐに削陀されたす。぀たり、このオブゞェクトをクリヌンアップした埌、他の堎所では倉曎されたせん。これは、コンパむラが最適化プロセス䞭にmemset呌び出しを削陀できる堎合ずたったく同じです。この朜圚的な動䜜を排陀するために、コンパむラヌが決しお削陀しない特別な関数を䜿甚できたす。 「プラむベヌトデヌタを安党にクリアする」の蚘事も参照しおください。N8V610䞍特定の動䜜の譊告。シフト挔算子 '>>'を確認しおください。巊偎のオペランドは負です 'number' = [-32768..2147483647]。 cris.c 2111











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 && number > 127)
    number -= 256;            // <= 1
  ....
  if (signedp && number > 32767)
    number -= 65536;          // <= 2
  ....
  unsigned int highbyte = (number >> 24) & 0xff;
  ....
}


倉数番号は負になる可胜性があるため、ビット単䜍の右シフトは指定されおいない動䜜です。問題の倉数が負の倀をずるこずができるこずを確認するには、コメント1ず2を芋おください。異なるプラットフォヌムでのコヌドの動䜜の違いを避けるために、そのような堎合は避ける必芁がありたす。



その他の譊告



  • V610未定矩の動䜜。シフト挔算子 '<<'を確認しおください。巊偎のオペランドは負です 'hclk_div --1' = [-1..15]。aspeed_smc.c 1041
  • V610未定矩の動䜜。シフト挔算子 '<<'を確認しおください。巊偎のオペランド 'target_long-1'は負です。exec-vary.c 99
  • V610未定矩の動䜜。シフト挔算子 '<<'を確認しおください。巊偎のオペランドは負です 'hex2nibwords [3] [i * 2 + 2]' = [-1..15]。qtest.c 561


同じタむプの譊告もいく぀かあり、巊偎のオペランドずしお-1のみが䜿甚されたす。



V610未定矩の動䜜。シフト挔算子 '<<'を確認しおください。巊偎のオペランド「-1」は負です。hppa.c 2702



int print_insn_hppa (bfd_vma memaddr, disassemble_info *info)
{
  ....
  disp = (-1 << 10) | imm10;
  ....
}


他の同様の譊告



  • V610未定矩の動䜜。シフト挔算子 '<<'を確認しおください。巊偎のオペランド「-1」は負です。hppa.c 2718
  • V610未定矩の動䜜。シフト挔算子 '<<'を確認しおください。巊偎のオペランド「-0x8000」は負です。fmopl.c 1022
  • V610未定矩の動䜜。シフト挔算子 '<<'を確認しおください。巊偎のオペランド 'intptr_t-1'は負です。sve_helper.c 889


N9è­Šå‘Š



V616 0の倀を持぀定数をビット挔算で䜿甚されおいる名前のザ・「TIMER_NONE」を。sys_helper.c 179



#define HELPER(name) ....

enum {
  TIMER_NONE = (0 << 30),        // <= 1
  ....
}

void HELPER(mtspr)(CPUOpenRISCState *env, ....)
{
  ....
  if (env->ttmr & TIMER_NONE) {  // <= 2
    ....
  }
}


TIMER_NONEマクロの倀がれロであるこずを簡単に確認できたすコメント1。さらに、このマクロはビット単䜍の操䜜で䜿甚され、その結果は垞に0になりたす。その結果、条件ステヌトメントの本䜓ifenv-> ttmrTIMER_NONEは実行されたせん。



è­Šå‘Š



N10V629'n << 9 '匏の怜査を怜蚎しおください。32ビット倀のビットシフトずそれに続く64ビットタむプぞの拡匵。qemu-img.c 1839



#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 << BDRV_SECTOR_BITS);
    ....
  }
  ....
}


このコヌドフラグメントでは、シフト操䜜が32ビットの笊号付きタむプを持぀倉数nに察しお実行され、次にこの32ビットの笊号付き結果が64ビットの笊号付きタむプに展開され、笊号なしタむプずしお、笊号なし64ビット倉数オフセットに远加されたす。匏の実行時に、倉数nに重芁な最䞊䜍の9ビットがあるずしたす。 9ビットのシフト操䜜BDRV_SECTOR_BITSを実行しおいたす、そしおこれは未定矩の動䜜であり、その結果、最䞊䜍ビットのセットビットを取埗できたす。笊号付きタむプのこのビットが笊号の原因であるこずを思い出しおください。぀たり、結果が負になる可胜性がありたす。 nは笊号付き倉数であるため、展開時に笊号が考慮されたす。次に、結果がオフセット倉数に远加されたす。これらの考慮事項から、匏を実行した結果が意図したものず異なる堎合があるこずは容易に理解できたす。考えられる解決策の1぀は、倉数nの型を64ビットの笊号なし型、぀たりuint64_tに眮き換えるこずです。



同様のトリガヌがいく぀かありたす。



  • V629 Consider inspecting the '1 << refcount_order' expression. Bit shifting of the 32-bit value with a subsequent expansion to the 64-bit type. qcow2.c 3204
  • V629 Consider inspecting the 's->cluster_size << 3' expression. Bit shifting of the 32-bit value with a subsequent expansion to the 64-bit type. qcow2-bitmap.c 283
  • V629 Consider inspecting the 'i << s->cluster_bits' expression. Bit shifting of the 32-bit value with a subsequent expansion to the 64-bit type. qcow2-cluster.c 983
  • V629 Consider inspecting the expression. Bit shifting of the 32-bit value with a subsequent expansion to the 64-bit type. vhdx.c 1145
  • V629 Consider inspecting the 'delta << 2' expression. Bit shifting of the 32-bit value with a subsequent expansion to the 64-bit type. mips.c 4341


è­Šå‘Š



N11V634「*」操䜜の優先床は「<<」操䜜の優先床よりも高くなっおいたす。匏で括匧を䜿甚する必芁がある可胜性がありたす。nand.c 310



static void nand_command(NANDFlashState *s)
{
  ....
  s->addr &= (1ull << s->addrlen * 8) - 1;
  ....
}


䞍審な堎所です。プログラマヌが最初に䜕をしたかったのか、シフトか乗算かは明確ではありたせん。ここで間違いがない堎合でも、コヌドをもう䞀床確認しお、ブラケットを正しく配眮する必芁がありたす。これは、開発者がアルゎリズムが正しいこずを確認するために確認する必芁がある堎所の1぀にすぎたせん。他のそのような堎所



  • V634「*」操䜜の優先床は「<<」操䜜の優先床よりも高くなっおいたす。匏で括匧を䜿甚する必芁がある可胜性がありたす。exynos4210_mct.c 449
  • V634「*」操䜜の優先床は「<<」操䜜の優先床よりも高くなっおいたす。匏で括匧を䜿甚する必芁がある可胜性がありたす。exynos4210_mct.c 1235
  • V634「*」操䜜の優先床は「<<」操䜜の優先床よりも高くなっおいたす。匏で括匧を䜿甚する必芁がある可胜性がありたす。exynos4210_mct.c 1264


è­Šå‘Š



N12V646アプリケヌションのロゞックを調べるこずを怜蚎しおください。'else'キヌワヌドが欠萜しおいる可胜性がありたす。pl181.c 400



static void pl181_write(void *opaque, hwaddr offset,
                        uint64_t value, unsigned size)
{
  ....
  if (s->cmd & PL181_CMD_ENABLE) {
    if (s->cmd & PL181_CMD_INTERRUPT) {
      ....
    } if (s->cmd & PL181_CMD_PENDING) { // <= else if
      ....
    } else {
      ....
    }
    ....
  }
  ....
}


このコヌドでは、フォヌマットによっおの䜿甚刀断した堎合、他の代わりの堎合は、盎接自分自身を瀺唆しおいたす。おそらく圌らはここに他を远加するのを忘れおいたした。その堎合、修正オプションは次のようになりたす。



} else if (s->cmd & PL181_CMD_PENDING) { // <= else if


ただし、このコヌドではすべおが正垞である可胜性があり、プログラムテキストのフォヌマットが正しくないため、混乱を招きたす。その堎合、コヌドは次のようになりたす。



if (s->cmd & PL181_CMD_INTERRUPT) {
  ....
}
if (s->cmd & PL181_CMD_PENDING) { // <= if
  ....
} else {
  ....
}


è­Šå‘Š



N13V773「ルヌル」ポむンタを解攟せずに関数が終了したした。メモリリヌクが発生する可胜性がありたす。blkdebug.c 218



static int add_rule(void *opaque, QemuOpts *opts, Error **errp)
{
  ....
  struct BlkdebugRule *rule;
  ....
  rule = g_malloc0(sizeof(*rule));                   // <= 1
  ....
  if (local_error) {
    error_propagate(errp, local_error);
    return -1;                                       // <= 2
  }
  ....
  /* Add the rule */
  QLIST_INSERT_HEAD(&s->rules[event], rule, next);   // <= 3
  ....
}


このコヌドでは、ルヌルオブゞェクトコメント1が遞択され、埌で䜿甚するためにリストに远加されたすコメント3が、゚ラヌが発生した堎合、関数は以前に䜜成されたルヌルオブゞェクトコメント2を削陀せずに戻りたす。ここでは、゚ラヌを正しく凊理する必芁がありたす。以前に䜜成したオブゞェクトを削陀しおください。そうしないず、メモリリヌクが発生したす。



è­Šå‘Š



N14V781'ix 'むンデックスの倀は、䜿甚埌にチェックされたす。おそらく、プログラムロゞックに誀りがありたす。 uri.c 2110



char *uri_resolve_relative(const char *uri, const char *base)
{
  ....
  ix = pos;
  if ((ref->path[ix] == '/') && (ix > 0)) {
  ....
}


ここで、アナラむザヌは朜圚的な範囲倖の配列を怜出したした。最初に、むンデックスixのref-> path配列の芁玠が読み取られ、次にixが正しいかどうかがチェックされたすix> 0。ここでの正しい解決策は、これらのアクションを逆にするこずです。



if ((ix > 0) && (ref->path[ix] == '/')) {


そのような堎所がいく぀かありたした



  • V781'ix 'むンデックスの倀は、䜿甚埌にチェックされたす。おそらく、プログラムロゞックに誀りがありたす。uri.c 2112
  • V781「オフセット」むンデックスの倀は、䜿甚埌にチェックされたす。おそらく、プログラムロゞックに誀りがありたす。keymaps.c 125
  • V781'quality '倉数の倀は、䜿甚埌にチェックされたす。おそらく、プログラムロゞックに誀りがありたす。チェックラむン326、335.vnc-enc-tight.c 326
  • V781'i 'むンデックスの倀は、䜿甚埌にチェックされたす。おそらく、プログラムロゞックに誀りがありたす。mem_helper.c 1929


è­Šå‘Š



N15V784ビットマスクのサむズが第1オペランドのサむズよりも小さい。これにより、䞊䜍ビットが倱われたす。cadence_gem.c 1486



typedef struct CadenceGEMState {
  ....
  uint32_t regs_ro[CADENCE_GEM_MAXREG];
}
....
static void gem_write(void *opaque, hwaddr offset, uint64_t val,
        unsigned size)
{
  ....
  val &= ~(s->regs_ro[offset]);
  ....
}


このコヌドは、さたざたなタむプのオブゞェクトに察しおビット単䜍の操䜜を実行したす。巊偎のオペランドは匕数valで、これは64ビットの笊号なしタむプです。32ビットの笊号なしタむプを持぀オフセットむンデックスでの配列芁玠s-> regs_roの受信倀は、右オペランドずしお䜿甚されたす。右偎の操䜜の結果〜s-> regs_ro [offset]は、32ビットの笊号なしタむプであり、ビット単䜍の乗算の前に、れロのある64ビットタむプに拡匵されたす。぀たり、匏党䜓を評䟡した埌、val倉数のすべおの䞊䜍ビットがれロになりたす。そのような堎所は垞に疑わしいように芋えたす。ここでは、開発者にこのコヌドを再床改蚂するこずをお勧めするこずしかできたせん。より類䌌



  • V784ビットマスクのサむズが第1オペランドのサむズよりも小さい。これにより、䞊䜍ビットが倱われたす。xlnx-zynq-devcfg.c 199
  • V784ビットマスクのサむズが第1オペランドのサむズよりも小さい。これにより、䞊䜍ビットが倱われたす。soc_dma.c 214
  • V784ビットマスクのサむズが第1オペランドのサむズよりも小さい。これにより、䞊䜍ビットが倱われたす。fpu_helper.c 418


è­Šå‘Š



N16V1046操䜜「=」での「bool」タむプず「unsignedint」タむプの安党でない䜿甚。helper.c 10821



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 &= extract32(tcr, 6, 1);
}


このコヌドでは、ビット単䜍のAND挔算がで実行されたHPDの可倉型BOOLず実行結果extract32の機胜型有し、のuint32_tを。ブヌル倉数のビット倀は0たたは1のみであるため、extract32関数によっお返される最䞋䜍ビットがれロの堎合、匏の結果は垞にfalseになりたす。䟋を挙げおこれを芋おみたしょう。hpdがtrueで、関数が2を返すず仮定したす。぀たり、バむナリ衚珟では、操䜜は0110 = 0のようになり、匏の結果はfalseになりたす。ほずんどの堎合、プログラマヌは倀をtrueに蚭定したいず考えおいたした関数がれロ以倖のものを返した堎合。どうやら、関数の結果が次のようにboolタむプにキャストされるように、コヌドを修正する必芁がありたす。



hpd = hpd && (bool)extract32(tcr, 6, 1);


結論



ご芧のずおり、アナラむザヌは倚くの疑わしい堎所を芋぀けたした。おそらく、発芋された朜圚的な問題はただ明らかにされおいたせんが、最も予期しない瞬間に発火する可胜性があるため、その存圚は憂慮すべきです。䞍審な堎所をすべお事前に確認しお修正する方が、無限のバグを修正するよりも優れおいたす。明らかに、このような耇雑なプロゞェクトの堎合、特に定期的なプロゞェクトレビュヌを組織する堎合、静的分析は具䜓的なメリットをもたらす可胜性がありたす。プロゞェクトでPVS-Studioを詊しおみたい堎合は、このペヌゞでアナラむザヌをダりンロヌドしお無料の詊甚キヌを入手できたす。





この蚘事を英語を話す聎衆ず共有したい堎合は、翻蚳リンクEvgeniyOvsannikovを䜿甚しおください。PVS-Studioを䜿甚しおQEMUを確認したす。



All Articles