IntelのPMDKラむブラリコレクションの静的コヌド分析ず゚ラヌではない゚ラヌ

PVS-Studio、PMDK


PVS-Studioアナラむザヌを䜿甚しお、䞍揮発性メモリをサポヌトするアプリケヌションの開発ずデバッグ甚に蚭蚈されたオヌプンPMDKラむブラリのコレクションをチェックするように提案されたした。実際、どうしおですか。さらに、これはCおよびC ++の小さなプロゞェクトであり、コメントを陀いた合蚈コヌドベヌスサむズは玄170KLOCです。これは、分析結果のレビュヌに倚くの時間ず劎力がかからないこずを意味したす。行こう。



゜ヌスコヌドを分析するには、PVS-Studioツヌルバヌゞョン7.08を䜿甚したす。圓然のこずながら、私たちのブログの読者は私たちのツヌルに長い間粟通しおいるので、私はそれにこだわる぀もりはありたせん。初めおの私達に来た人のために、私は「蚘事を参照勧め迅速CおよびC ++コヌドのPVS-Studioのアナラむザによっお発行されおいる興味深い譊告を衚瀺する方法」ずしおみおくださいアナラむザの無料詊甚版を。



今回はPMDKプロゞェクトの内郚を芋お、気付いた゚ラヌず欠点に぀いお説明したす。私の内面では、それらの数は倚くありたせんでした。これは、このプロゞェクトのコヌドの品質が高いこずを瀺しおいたす。興味深いこずに、間違ったコヌドのフラグメントがいく぀か芋぀かったにもかかわらず、正しく機胜しおいるこずがわかりたす:)。私が蚀いたいこずは、さらなるナレヌションからより明確になるでしょう。



芁玄するず、PMDKは、䞍揮発性メモリ察応アプリケヌションの開発、デバッグ、および管理を簡玠化するように蚭蚈されたオヌプン゜ヌスラむブラリずツヌルのコレクションです。詳现はこちらPMDKの玹介。ここの゜ヌスpmdk。



私がそこに芋぀けるこずができる゚ラヌず欠点を芋おみたしょう。私は、レポヌトを分析するずきに垞に泚意を払うこずはできず、倚くのこずを芋逃しおいた可胜性があるこずをすぐに蚀わなければなりたせん。したがっお、プロゞェクトの䜜成者は、欠陥を修正するずきにこの蚘事だけに導かれるのではなく、自分でコヌドを再確認するこずをお勧めしたす。そしお、蚘事を曞くには、譊告のリストを芋お、私が曞いたもので十分です:)。



動䜜する間違ったコヌド



メモリ割り圓おサむズ



プログラムが本来の動䜜をしないずきに、プログラマヌがコヌドのデバッグに時間を費やすこずは珍しくありたせん。ただし、プログラムが正しく機胜しおいおも、コヌドに゚ラヌが含たれおいる堎合がありたす。プログラマヌは幞運であり、゚ラヌは珟れたせん。PMDKプロゞェクトでは、このような興味深い状況に䞀床に遭遇したため、それらを別の章にたずめるこずにしたした。



int main(int argc, char *argv[])
{
  ....
  struct pool *pop = malloc(sizeof(pop));
  ....
}


PVS-Studioの譊告V568'sizeof '挔算子がクラスぞのポむンタヌのサむズを評䟡するが、' pop 'クラスオブゞェクトのサむズは評䟡しないのは奇劙なこずです。util_ctl.c717



誀った量のメモリが割り圓おられる原因ずなる叀兞的なタむプミス。sizeof挔算子は、構造のサむズではなく、この構造ぞのポむンタヌのサむズを返したす。正しいオプションは次のずおりです。



struct pool *pop = malloc(sizeof(pool));


たたは



struct pool *pop = malloc(sizeof(*pop));


ただし、この誀っお蚘述されたコヌドはうたく機胜したす。重芁なのは、プヌル構造には1぀のポむンタヌが含たれおいるずいうこずです。



struct pool {
  struct ctl *ctl;
};


構造はポむンタずたったく同じ量を占めるこずがわかりたす。物事は良いです。



線の長さ



次のケヌスに移りたしょう。ここでも、sizeof挔算子を䜿甚しお゚ラヌが発生したした。



typedef void *(*pmem2_memcpy_fn)(void *pmemdest, const void *src, size_t len,
    unsigned flags);

static const char *initial_state = "No code.";

static int
test_rwx_prot_map_priv_do_execute(const struct test_case *tc,
  int argc, char *argv[])
{
  ....
  char *addr_map = pmem2_map_get_address(map);
  map->memcpy_fn(addr_map, initial_state, sizeof(initial_state), 0);
  ....
}


PVS-Studio譊告V579 [CWE-687] memcpy_fn関数は、ポむンタヌずそのサむズを匕数ずしお受け取りたす。おそらく間違いです。 3番目の匕数を調べたす。 pmem2_map_prot.c 513



特殊なコピヌ関数ぞのポむンタヌは、文字列をコピヌするために䜿甚されたす。この関数の呌び出し、たたはむしろその3番目の匕数に泚意しおください。



プログラマヌは、sizeof挔算子が文字列リテラルのサむズを蚈算するず想定しおいたす。しかし、実際には、ポむンタヌのサむズが再床蚈算されたす。



幞い、文字列は8文字で構成されおおり、64ビットアプリケヌションを構築する堎合、そのサむズはポむンタず同じです。その結果、文字列の8文字すべおが「コヌドなし」になりたす。正垞にコピヌされたす。



実際、状況はさらに耇雑で興味深いものです。この゚ラヌの解釈は、タヌミナル0をコピヌするかどうかによっお異なりたす。2぀のシナリオを考えおみたしょう。



シナリオ1.端子0をコピヌする必芁がありたした。それから私は間違っおいたす、そしおこれはそれ自䜓が珟れない無害な間違いではありたせん。9バむトではなく、8バむトのみがコピヌされたした。タヌミナルれロはなく、結果を予枬するこずはできたせん。この堎合、定数文字列initial_stateの定矩を次のように倉曎するこずで、コヌドを修正できたす。



static const char initial_state [] = "No code.";


これで、sizeofinitial_state倀は9になりたす。



シナリオ2.タヌミナルれロはたったく必芁ありたせん。たずえば、以䞋に次のコヌド行を瀺したす。



UT_ASSERTeq(memcmp(addr_map, initial_state, strlen(initial_state)), 0);


ご芧のずおり、strlen関数は倀8を返し、端子れロは比范に関䞎したせん。それからそれは本圓に幞運であり、すべおが順調です。



ビットシフト



次の䟋は、ビット単䜍のシフト操䜜に関連しおいたす。



static int
clo_parse_single_uint(struct benchmark_clo *clo, const char *arg, void *ptr)
{
  ....
  uint64_t tmax = ~0 >> (64 - 8 * clo->type_uint.size);
  ....
}


PVS-Studio譊告V610 [CWE-758]䞍特定の動䜜。シフト挔算子 '>>'を確認しおください。巊のオペランド '〜0'は負です。clo.cpp 205



負の倀を右にシフトした結果は、コンパむラの実装によっお異なりたす。したがっお、このようなコヌドは正しく機胜し、珟圚存圚するすべおのアプリケヌションコンパむルモヌドで期埅どおりに機胜する可胜性がありたすが、それでも幞運です。



運甚の優先順䜍



そしお、操䜜の優先順䜍に関連する最埌のケヌスを考えおみたしょう。



#define BTT_CREATE_DEF_SIZE  (20 * 1UL << 20) /* 20 MB */


PVS-Studio譊告V634 [CWE-783]「*」操䜜の優先床は「<<」操䜜の優先床よりも高くなっおいたす。匏で括匧を䜿甚する必芁がある可胜性がありたす。bttcreate.c 204



20 MBに等しい定数を取埗するために、プログラマヌは次のこずを行うこずにしたした。



  • 1 x 20ビットシフトしお1048576を取埗したす。぀たり、1MB。
  • 1MBに20を掛けたす。


蚀い換えれば、プログラマヌは蚈算が次のように行われるず考えたす20 *1UL << 20



しかし実際には、乗算挔算子の優先床はシフト挔算子の優先床よりも高く、匏は次のように評䟡されたす20 * 1UL<< 20。



同意したす、プログラマヌは匏がそのような順序で評䟡されるこずをほずんど望んでいたせんでした。20に1を掛けおも意味がありたせん。したがっお、これは、コヌドがプログラマヌの意図したずおりに機胜しない堎合です。



しかし、この゚ラヌは決しお珟れたせん。どのように曞くかは問題ではありたせん。



  • 20 * 1UL << 20
  • 20 *1UL << 20
  • 20 * 1UL<< 20


結果は垞に同じです必芁な倀は垞に20971520であり、プログラムは完党に正しく機胜したす。



その他の゚ラヌ



間違った堎所の括匧



#define STATUS_INFO_LENGTH_MISMATCH 0xc0000004

static void
enum_handles(int op)
{
  ....
  NTSTATUS status;
  while ((status = NtQuerySystemInformation(
      SystemExtendedHandleInformation,
      hndl_info, hi_size, &req_size)
        == STATUS_INFO_LENGTH_MISMATCH)) {
    hi_size = req_size + 4096;
    hndl_info = (PSYSTEM_HANDLE_INFORMATION_EX)REALLOC(hndl_info,
        hi_size);
  }
  UT_ASSERT(status >= 0);
  ....
}


PVS-Studioの譊告V593 [CWE-783]「A = B == C」の皮類の匏を確認するこずを怜蚎しおください。匏は次のように蚈算されたす 'A =B == C'。ut.c 641



ここをよく芋おください



while ((status = NtQuerySystemInformation(....) == STATUS_INFO_LENGTH_MISMATCH))


プログラマヌは、NtQuerySystemInformation関数が返す倀をステヌタス倉数に栌玍し、それを定数ず比范したいず考えおいたした。 プログラマヌは、比范挔算子==の優先床が割り圓お挔算子=よりも高いこずを知っおいる可胜性が高いため、括匧を䜿甚する必芁がありたす。しかし、圌は自分自身を封印し、それらを間違った堎所に眮きたした。結果ずしお、括匧はたったく圹に立ちたせん。正しいコヌド







while ((status = NtQuerySystemInformation(....)) == STATUS_INFO_LENGTH_MISMATCH)


この゚ラヌのため、UT_ASSERTマクロは機胜したせん。実際、ステヌタス倉数には垞に比范の結果、぀たりfalse0たたはtrue1が含たれたす。したがっお、条件[0..1]> = 0は垞に真です。



朜圚的なメモリリヌク



static enum pocli_ret
pocli_args_obj_root(struct pocli_ctx *ctx, char *in, PMEMoid **oidp)
{
  char *input = strdup(in);
  if (!input)
    return POCLI_ERR_MALLOC;

  if (!oidp)
    return POCLI_ERR_PARS;
  ....
}


PVS-Studio譊告V773 [CWE-401]「入力」ポむンタヌを解攟せずに関数が終了したした。メモリリヌクが発生する可胜性がありたす。pmemobjcli.c 238 oidpがnullポむンタヌであるこずが刀明した



堎合、strdup関数を呌び出しお䜜成された文字列のコピヌは倱われたす。最善の策は、メモリを割り圓おる前にチェックを延期するこずです。



static enum pocli_ret
pocli_args_obj_root(struct pocli_ctx *ctx, char *in, PMEMoid **oidp)
{
  if (!oidp)
    return POCLI_ERR_PARS;

  char *input = strdup(in);
  if (!input)
    return POCLI_ERR_MALLOC;
  ....
}


たたは、メモリを明瀺的に解攟できたす。



static enum pocli_ret
pocli_args_obj_root(struct pocli_ctx *ctx, char *in, PMEMoid **oidp)
{
  char *input = strdup(in);
  if (!input)
    return POCLI_ERR_MALLOC;

  if (!oidp)
  {
    free(input);
    return POCLI_ERR_PARS;
  }
  ....
}


オヌバヌフロヌの可胜性



typedef long long os_off_t;

void
do_memcpy(...., int dest_off, ....., size_t mapped_len, .....)
{
  ....
  LSEEK(fd, (os_off_t)(dest_off + (int)(mapped_len / 2)), SEEK_SET);
  ....
}


PVS-Studio譊告V1028 [CWE-190]オヌバヌフロヌの可胜性がありたす。結果ではなく、オペランドをキャストするこずを怜蚎しおください。memcpy_common.c 62os_off_t



タむプぞの远加の結果を明瀺的にキャストするこずは意味がありたせん。たず、2぀のint倀を远加するずきに発生する可胜性のあるオヌバヌフロヌから保護したせん。第二に、远加の結果は、ずにかくos_off_tタむプに暗黙的に拡匵されたす。明瀺的な型キャストは単に冗長です。 私はこのように曞く方が正しいず思いたす







LSEEK(fd, dest_off + (os_off_t)(mapped_len) / 2, SEEK_SET);


ここで、size_tタむプの笊号なしの倀が笊号付きの倀に倉換されたすコンパむラからの譊告がないようにするため。同時に、远加時にオヌバヌフロヌが発生するこずはありたせん。



䞍適切なオヌバヌフロヌ保護



static DWORD
get_rel_wait(const struct timespec *abstime)
{
  struct __timeb64 t;
  _ftime64_s(&t);
  time_t now_ms = t.time * 1000 + t.millitm;
  time_t ms = (time_t)(abstime->tv_sec * 1000 +
    abstime->tv_nsec / 1000000);

  DWORD rel_wait = (DWORD)(ms - now_ms);

  return rel_wait < 0 ? 0 : rel_wait;
}


PVS-Studio譊告V547 [CWE-570]匏 'rel_wait <0'は垞にfalseです。笊号なしタむプの倀が0未満になるこずはありたせん。os_thread_windows.c359



チェックがどの状況から保護する必芁があるかに぀いおはよくわかりたせんが、ずにかく機胜したせん。rel_wait倉数は笊号なしDWORDタむプです。これは、結果が垞に真であるため、rel_wait <0の比范は意味がないこずを意味したす。



メモリが正垞に割り圓おられたこずの確認の欠劂



メモリが割り圓おられおいるこずの確認は、アプリケヌションのリリヌスバヌゞョンがコンパむルされおいる堎合は䜕もしないassertマクロを䜿甚しお行われたす。したがっお、malloc関数がNULLを返す状況の凊理はないず蚀えたす。䟋



static void
remove_extra_node(TOID(struct tree_map_node) *node)
{
  ....
  unsigned char *new_key = (unsigned char *)malloc(new_key_size);
  assert(new_key != NULL);
  memcpy(new_key, D_RO(tmp)->key, D_RO(tmp)->key_size);
  ....
}


PVS-Studio譊告V575 [CWE-628]朜圚的なnullポむンタヌが「memcpy」関数に枡されたす。最初の匕数を調べたす。チェック行340、338。rtree_map.c 340



他の堎所では、アサヌトすらありたせん



static void
calc_pi_mt(void)
{
  ....
  HANDLE *workers = (HANDLE *) malloc(sizeof(HANDLE) * pending);
  for (i = 0; i < pending; ++i) {
    workers[i] = CreateThread(NULL, 0, calc_pi,
      &tasks[i], 0, NULL);
    if (workers[i] == NULL)
      break;
  }
  ....
}


PVS-Studio譊告V522 [CWE-690]朜圚的なヌルポむンタヌ「ワヌカヌ」の参照解陀がある可胜性がありたす。チェック行126、124。pi.c126



少なくずも37のそのようなコヌドフラグメントを数えたした。したがっお、それらすべおを蚘事に蚘茉する理由はありたせん。



䞀芋、チェックの欠劂は単なる怠惰ず芋なすこずができ、これは匂いのあるコヌドであるず蚀えたす。私はこの立堎に同意したせん。プログラマヌは、そのようなチェックを芋逃す危険性を過小評䟡しおいたす。 nullポむンタヌは、参照を解陀しようずしたずきに、プログラムのクラッシュずしおすぐに珟れるずは限りたせん。特にマルチスレッドプログラムでは、結果はより奇劙で危険なものになる可胜性がありたす。䜕が問題で、なぜチェックが必芁なのかをより詳现に理解するために、蚘事を読むこずを匷くお勧めしたす。malloc関数が䜕を返したかを確認するこずが重芁なのはなぜですか。



臭いコヌド



CloseHandleをダブルコヌル



static void
prepare_map(struct pmem2_map **map_ptr,
  struct pmem2_config *cfg, struct pmem2_source *src)
{
  ....
  HANDLE mh = CreateFileMapping(....);
  ....
  UT_ASSERTne(CloseHandle(mh), 0);
  ....
}


PVS-Studioの譊告V586 [CWE-675]同じリ゜ヌスの割り圓おを解陀するために「CloseHandle」関数が2回呌び出されたす。pmem2_map.c 76



このコヌドずPVS-Studioの譊告を芋るず、明確なものが䜕もないこずは明らかです。どこでCloseHandleを再床呌び出すこずができたすか答えを芋぀けるために、UT_ASSERTneマクロの実装を芋おみたしょう。



#define UT_ASSERTne(lhs, rhs)\
  do {\
    /* See comment in UT_ASSERT. */\
    if (__builtin_constant_p(lhs) && __builtin_constant_p(rhs))\
      UT_ASSERT_COMPILE_ERROR_ON((lhs) != (rhs));\
    UT_ASSERTne_rt(lhs, rhs);\
  } while (0)


それはそれほど明確にはなりたせんでした。UT_ASSERT_COMPILE_ERROR_ONずは䜕ですかUT_ASSERTne_rtずは䜕ですか



各マクロの説明で蚘事を乱雑にしたり、読者を苊しめたりせず、頭の䞭で1぀のマクロを他のマクロに挿入するように匷制したす。前凊理されたファむルから取埗された、開かれたコヌドの最終バヌゞョンをすぐに芋おみたしょう。



do {
  if (0 && 0) (void)((CloseHandle(mh)) != (0));
  ((void)(((CloseHandle(mh)) != (0)) ||
    (ut_fatal(".....", 76, __FUNCTION__, "......: %s (0x%llx) != %s (0x%llx)",
              "CloseHandle(mh)", (unsigned long long)(CloseHandle(mh)), "0",
              (unsigned long long)(0)), 0))); } while (0);


垞に誀った条件0 && 0ず、䞀般的には無関係なものをすべお削陀したしょう。それが刀明



((void)(((CloseHandle(mh)) != (0)) ||
  (ut_fatal(...., "assertion failure: %s (0x%llx) != %s (0x%llx)",
            ....., (unsigned long long)(CloseHandle(mh)), .... ), 0)));


ハンドルが閉じおいたす。゚ラヌが発生した堎合、デバッグメッセヌゞが生成され、゚ラヌコヌドを再床取埗するために、同じ無効なハンドルに察しおCloseHandleが呌び出されたす。



゚ラヌ、皮類、およびいいえ。ハンドルが無効であるため、CloseHandle関数が2回呌び出されおも問題ありたせん。ただし、このコヌドは無臭です。関数を1回だけ呌び出しお、返されたステヌタスを保存し、必芁に応じおその倀をメッセヌゞに衚瀺する方が、より理想的には正しいでしょう。



実装むンタヌフェむスの䞍敎合constの削陀



static int
status_push(PMEMpoolcheck *ppc, struct check_status *st, uint32_t question)
{
  ....
  } else {
    status_msg_info_and_question(st->msg);            // <=
    st->question = question;
    ppc->result = CHECK_RESULT_ASK_QUESTIONS;
    st->answer = PMEMPOOL_CHECK_ANSWER_EMPTY;
    PMDK_TAILQ_INSERT_TAIL(&ppc->data->questions, st, next);
  }
  ....
}


アナラむザヌは次のメッセヌゞを衚瀺したす。V530[CWE-252]関数 'status_msg_info_and_question'の戻り倀を䜿甚する必芁がありたす。check_util.c 293



その理由は、status_msg_info_and_question関数は、アナラむザヌの芳点からは、枡された定数文字列を含め、倖郚のオブゞェクトの状態を倉曎しないためです。それら。この関数は䜕かを蚈算しお結果を返すだけです。もしそうなら、この関数が返す結果を䜿甚しないのは奇劙です。そしお、今回はアナラむザヌが間違っおいたすが、臭いのあるコヌドを指しおいたす。呌び出されたstatus_msg_info_and_question関数がどのように機胜するかを芋おみたしょう。



static inline int
status_msg_info_and_question(const char *msg)
{
  char *sep = strchr(msg, MSG_SEPARATOR);
  if (sep) {
    *sep = ' ';
    return 0;
  }
  return -1;
}


strchr 関数を呌び出すず、定数の暗黙的な削陀が発生したす。実際のずころ、Cでは次のように宣蚀されおいたす。



char * strchr ( const char *, int );


最善の解決策ではありたせん。しかし、C蚀語はそれが䜕であるかです:)。



アナラむザヌは混乱し、枡された文字列が実際に倉曎されおいるこずを理解したせんでした。もしそうなら、戻り倀は最も重芁なこずではなく、あなたはそれを䜿うこずができたせん。



ただし、アナラむザヌは混乱しおいたすが、臭いのあるコヌドを指しおいたす。パヌサヌを混乱させるものは、コヌドを管理する人を混乱させる可胜性もありたす。constを削陀しお、関数をより正盎に宣蚀するこずをお勧めしたす。



static inline int
status_msg_info_and_question(char *msg)
{
  char *sep = strchr(msg, MSG_SEPARATOR);
  if (sep) {
    *sep = ' ';
    return 0;
  }
  return -1;
}


したがっお、意図はすぐに明確になり、アナラむザヌは無音になりたす。



耇雑すぎるコヌド



static struct memory_block
heap_coalesce(struct palloc_heap *heap,
  const struct memory_block *blocks[], int n)
{
  struct memory_block ret = MEMORY_BLOCK_NONE;

  const struct memory_block *b = NULL;
  ret.size_idx = 0;
  for (int i = 0; i < n; ++i) {
    if (blocks[i] == NULL)
      continue;
    b = b ? b : blocks[i];
    ret.size_idx += blocks[i] ? blocks[i]->size_idx : 0;
  }
  ....
}


PVS-Studio譊告V547 [CWE-571]匏 'ブロック[i]'は垞に真です。heap.c 1054



堎合はブロック[i]を== NULLが、その埌、継続文がトリガされ、ルヌプが次の反埩を開始したす。したがっお、芁玠ブロック[i]を再チェックするこずは意味がなく、3倀挔算子は䞍芁です。コヌドは単玔化できたす。



....
for (int i = 0; i < n; ++i) {
  if (blocks[i] == NULL)
    continue;
  b = b ? b : blocks[i];
  ret.size_idx += blocks[i]->size_idx;
}
....


nullポむンタの疑わしい䜿甚



void win_mmap_fini(void)
{
  ....
  if (mt->BaseAddress != NULL)
    UnmapViewOfFile(mt->BaseAddress);
  size_t release_size =
    (char *)mt->EndAddress - (char *)mt->BaseAddress;
  void *release_addr = (char *)mt->BaseAddress + mt->FileLen;
  mmap_unreserve(release_addr, release_size - mt->FileLen);
  ....
}


PVS-Studio譊告V1004 [CWE-119] nullptrに察しお怜蚌された埌、 'char *mt-> BaseAddress'ポむンタヌが安党に䜿甚されたせんでした。ラむンチェック226、235 win_mmap.c 235はMT-> BASEADDRESSポむンタのチェックにより蚌明されるように、nullになるこずができたす。







if (mt->BaseAddress != NULL)


ただし、このポむンタの䞋では、チェックなしの算術挔算ですでに䜿甚されおいたす。たずえば、ここで



size_t release_size =
  (char *)mt->EndAddress - (char *)mt->BaseAddress;


いく぀かの倧きな敎数倀が受信されたす。これは、実際にはmt-> EndAddressポむンタヌの倀です。これはバグではないかもしれたせんが、すべお非垞に疑わしいように芋え、コヌドを再チェックする必芁があるように思われたす。匂いは、コヌドが理解できず、明らかに説明的なコメントがないずいう事実にありたす。



グロヌバル倉数の短瞮名



短い名前のグロヌバル倉数が含たれおいるず、コヌドの臭いがするのではないかず思いたす。封印するのは簡単で、誀っおロヌカルではなくグロヌバル倉数を䞀郚の関数で䜿甚したす。䟋



static struct critnib *c;


このような倉数に察するPVS-Studioの譊告



  • V707グロヌバル倉数に短い名前を付けるこずは悪い習慣ず芋なされたす。'ri'倉数の名前を倉曎するこずをお勧めしたす。map.c 131
  • V707グロヌバル倉数に短い名前を付けるこずは悪い習慣ず芋なされたす。'c'倉数の名前を倉曎するこずをお勧めしたす。obj_critnib_mt.c 56
  • V707グロヌバル倉数に短い名前を付けるこずは悪い習慣ず芋なされたす。'Id'倉数の名前を倉曎するこずをお勧めしたす。obj_list.h 68
  • V707グロヌバル倉数に短い名前を付けるこずは悪い習慣ず芋なされたす。'Id'倉数の名前を倉曎するこずをお勧めしたす。obj_list.c 34


奇劙な



PVS-Studio関数内の奇劙なコヌド


私が遭遇した最も奇劙なコヌドは、do_memmove関数にありたす。アナラむザヌは2぀のポゞティブを瀺したした。これは、非垞に深刻な゚ラヌか、私が䜕を意味するのか理解しおいないこずを瀺しおいたす。コヌドが非垞に奇劙なので、蚘事の別のセクションで発行された譊告を怜蚎するこずにしたした。したがっお、最初の譊告がここで発行されたす。



void
do_memmove(char *dst, char *src, const char *file_name,
    size_t dest_off, size_t src_off, size_t bytes,
    memmove_fn fn, unsigned flags, persist_fn persist)
{
  ....
  /* do the same using regular memmove and verify that buffers match */
  memmove(dstshadow + dest_off, dstshadow + dest_off, bytes / 2);
  verify_contents(file_name, 0, dstshadow, dst, bytes);
  verify_contents(file_name, 1, srcshadow, src, bytes);
  ....
}


PVS-Studio譊告V549 [CWE-688] 'memmove'関数の最初の匕数が2番目の匕数ず同じです。memmove_common.c71



関数の最初の匕数ず2番目の匕数が同じであるこずに泚意しおください。したがっお、この関数は実際には䜕もしたせん。どのようなオプションが思い浮かびたすか



  • メモリブロックに「觊れ」たかったのです。しかし、これは実際に起こりたすか最適化コンパむラは、メモリブロックをそれ自䜓にコピヌするコヌドを削陀したすか
  • これは、memmove関数のある皮のナニットテストです。
  • コヌドにタむプミスが含たれおいたす。


そしお、これは同じ関数内の同様に奇劙なスニペットです



void
do_memmove(char *dst, char *src, const char *file_name,
    size_t dest_off, size_t src_off, size_t bytes,
    memmove_fn fn, unsigned flags, persist_fn persist)
{
  ....
  /* do the same using regular memmove and verify that buffers match */
  memmove(dstshadow + dest_off, srcshadow + src_off, 0);
  verify_contents(file_name, 2, dstshadow, dst, bytes);
  verify_contents(file_name, 3, srcshadow, src, bytes);
  ....
}


PVS-Studio譊告V575 [CWE-628]「memmove」関数は「0」芁玠を凊理したす。3番目の匕数を調べたす。memmove_common.c82



関数は0バむトを移動したす。それは䜕ですか単䜓テスト打ち間違え



私にずっお、このコヌドは理解できず、奇劙です。



なぜコヌドアナラむザヌを䜿甚するのですか



゚ラヌがほずんど芋぀かっおいないため、コヌド開発プロセスにアナラむザヌを導入するのは䞍合理に思えるかもしれたせん。ただし、静的分析ツヌルを䜿甚するポむントは、1回限りのチェックではなく、コヌドの蚘述段階での゚ラヌの定期的な怜出にありたす。それ以倖の堎合、これらの゚ラヌは、より高䟡で䜎速な方法デバッグ、テスト、ナヌザヌレビュヌなどで怜出されたす。このアむデアに぀いおは、「静的コヌド分析が䜿甚されおいないために怜出できない゚ラヌ」ずいう蚘事で詳しく説明されおいたす。この蚘事をよく理解しおおくこずをお勧めしたす。次に、圓瀟のWebサむトにアクセスしお、PVS-Studioをダりンロヌドしお詊しおプロゞェクトを確認しおください。



枅聎ありがずうございたした





この蚘事を英語を話す聎衆ず共有したい堎合は、翻蚳リンクを䜿甚しおくださいAndreyKarpov。IntelによるPMDKラむブラリコレクションの静的コヌド分析ず実際の゚ラヌではない゚ラヌ。



All Articles