EFLコアライブラリの例を使用したPVS-Studioアナライザーの特性、誤検知の10〜15%





EFLコアライブラリとPVS-Studio






Tizenオペレーティングシステムのチェックに関する長い記事の後、誤検知の割合とエラー密度(PVS-Studioがコード1000行ごとに検出するエラーの数)について多くの質問を受けました。 これは分析対象のプロジェクトに大きく依存しており、アナライザーの設定が本当の答えのようには見えないという私の考えです。 私は特定の数字を付けて、Tizenの一部であるプロジェクトの1つをより徹底的に研究することにしました。 Carsten Haitzlerがこの記事の議論に積極的に参加したので、彼が関与していたEFLコアライブラリの実験を行うのは面白いと思いました。 この記事が、Carstenがアナライザーのファンになるのに役立つことを願っています:)。





背景



読者の一人が見逃した場合、私は最近Tizen開発者に公開書簡を書きそれから記念碑的な記事「 Tizenオペレーティングシステムで27,000のエラー 」を書いことを知らせます。



その後、いくつかのサイトに関連するニュース記事が掲載され、いくつかの議論が始まりました。 それらのいくつかを次に示します。

Carsten Haitzlerに感謝したいと思います。CarstenHaitzlerは私の出版物に注意を払い、議論に積極的に参加してくれました。



さまざまなトピックが取り上げられましたが、そのうちのいくつかについては、記事「 Tizen:summarizing 」で詳細なコメントを述べました。



ただし、次の2つの永遠の質問があります。

静的分析方法論が何であるかをよく理解しているプログラマーは、そのような一般化された質問が意味をなさないことに同意します。 それはすべて私たちが取り組んでいるプロジェクトに依存します。 このような質問をすることは、「あなたの病院の患者の平均体温はどのくらいですか?」という質問に医師に尋ねることと同じです。



したがって、特定のプロジェクトの例について回答します。 EFL Core Librariesを選びました。 まず、このプロジェクトはTizenの一部です。 第二に、Carsten Haitzlerがその開発に参加しています。彼が私の結果を見るのは面白いと思います。



あなたはまだ啓発をチェックすることはできましたが、私にはそうする力がありませんでした。 これがないと、記事は非常に長くなると思います。



Enlightenment Foundation Libraries (EFL)は、ウィンドウマネージャおよびWaylandプロトコルであるEnlightenmentの開発に由来するグラフィックライブラリのコレクションです。



EFLコアライブラリを確認するとき、リポジトリhttps://git.enlightenment.org/から取得した新しいコードを使用しました。



また、調査対象のプロジェクトは、Coverity静的アナライザーを使用してチェックされることに注意してください。 このトピックに関するコメントは次のとおりです。



チェックを真剣に受け止めていると言います。 CoverityはEnlightenmentアップストリームのバグ率0を報告します(Coverityが指摘したすべての問題を修正したか、よく見てから偽として却下しました)。問題を見つけるのはコードベースが大きいほど簡単です。 それらはほとんどそれほど大きな影響を与えるものではありません。 私たちがリリースするたびにバグ率が下がり、リリースの数週間前に「問題を修正する」ことを繰り返す傾向があります。



さて、PVS-Studioアナライザーがどのようにそれ自体を実証するかを見てみましょう。



特徴



設定後のPVS-Studioアナライザーは、EFLコアライブラリプロジェクトのチェック時に約10〜15%の誤検知を生成します。



EFLコアライブラリで現在検出されているエラーの密度は、コード1000行あたり0.71を超えています



計算はどうだった



分析時のEFLコアライブラリプロジェクトには、CおよびC ++で約1,616,000行のコードが含まれています。 これらのうち、17.7%がコメントです。 したがって、コメントのないコードの行数は1,330,000です。



最初の実行後、次の数の汎用メッセージ(GA)が表示されました。

もちろん、これは悪い結果です。 そのため、抽象的な測定結果を書きたくないのです。 アナライザーを構成する必要がありますが、今回は時間をかけることにしました。



ほとんどすべてのプロジェクトはCで記述されており、その結果、マクロが広く使用されています。 誤検知の大半を引き起こすのはマクロです。 レポートをすばやく表示するのに約40分かかり、ファイルefl_settings.txtをコンパイルしました



ファイルには必要な設定が含まれています。 プロジェクトをチェックするときにそれらを使用するには、アナライザー構成ファイル(たとえば、PVS-Studio.cfg)で指定する必要があります。

rules-config=/path/to/efl_settings.txt
      
      





アナライザーは次のように起動できます。

 pvs-studio-analyzer analyze ... --cfg /path/to/PVS-Studio.cfg ...
      
      





かそこら

 pvs-studio ... --cfg /patn/to/PVS-Studio.cfg ...
      
      





使用する統合方法によって異なります。



設定を使用して、特定のマクロまたは式の名前を含むコード行に対して警告を出さないようアナライザーに指示しました。 また、いくつかの診断を完全に無効にしました。 たとえば、 V505をオフにしました 。 ループでalloca関数を使用するのは良くありませんが、これは明らかな間違いではありません。 警告が誤検知であるかどうかについてはあまり議論したくありません。何かを無効にする方が簡単だと思いました。



はい、最初の2つのレベルのアラートのみを見て設定していることに注意してください。 将来的にはそれらのみを検討します。 信頼度が低いという警告を考慮することはお勧めしません。 少なくとも、アナライザーの使用を開始してから、これらの警告を処理することは不合理です。 最初の2つのレベルを理解して初めて、3番目のレベルを見て、自分の意見で役立つ警告の種類を選択できます。



再起動により、次の結果が得られました。

番号1186は2回繰り返されますが、これはタイプミスではありません。 確かに、数字はとてもランダムに一致しました。



そのため、セットアップに40分を費やした後、誤検知の数を大幅に減らしました。 もちろん、私には多くの経験があり、このプロセスにはサードパーティの開発者からより多くの時間がかかりましたが、設定するのにひどく複雑なものはありません。



合計で、189 + 1186 = 1375のメッセージ(高+中)を受信し、それで作業を開始しました。



これらのメッセージを分析した後、アナライザーはエラーを含む950個のコードを検出したと考えています。 つまり、修正が必要な950個のコードが見つかりました。 これらのエラーについては、次の章で詳しく説明します。



ここで、検出されたエラーの密度を計算します。



950 * 1000/1330000 =コード1000行あたり約0.71エラー。



次に、誤検知の割合を計算してみましょう。



((1375-950)/ 1375)* 100%= 30%



停止、停止、停止! しかし実際には、記事の冒頭で、誤検知の約10〜15%と言われていました。 そして、ここは30%です。



これから説明します。 そこで、1375件のメッセージのレポートを見て、950はエラーを示しているという結論に達しました。 残り425メッセージ。



これらの残りの425メッセージのすべてが誤検知ではありません。 エラーが検出されたかどうかだけではわからない多くのメッセージを以下に示します。



見逃したメッセージの例を考えてみましょう。

 .... uint64_t callback_mask; .... static void _check_event_catcher_add(void *data, const Efl_Event *event) { .... Evas_Callback_Type type = EVAS_CALLBACK_LAST; .... else if ((type = _legacy_evas_callback_type(array[i].desc)) != EVAS_CALLBACK_LAST) { obj->callback_mask |= (1 << type); } .... }
      
      





PVS-Studio警告: V629 「1 << type」式の検査を検討してください。 32ビット値のビットシフトと、それに続く64ビットタイプへの拡張。 evas_callbacks.c 709



行を詳しく見てみましょう。

 obj->callback_mask |= (1 << type);
      
      





callback_mask変数の目的のビットに1を書き込むために使用されます。 callback_mask変数は64ビットであることに注意してください。



(1 << type)int型であるため、変数callback_maskの下部のビットのみを変更できます 。 ビット[32-63]は変更できません。



エラーがあるかどうかを理解するには、 _legacy_evas_callback_type関数が返すことができる値の範囲を把握する必要があります。 31より大きい値を返すことはできますか? 私はこのメッセージを知らず、スキップします。



ご理解ください。 このコードを見たのはこれが初めてで、何をするのか分かりません。 さらに、 何百ものアナライザーメッセージが私を待っています。 私はそのような各ケースに慎重に対処し始めることができません。



Carsten Haitzlerによるコメント。 上記-実際には、新しいイベントタイプを古いイベントタイプにマッピングしようとするかどうかを決定するためにビットを設定する最適化の結果であるバグです(新しいオブジェクトシステムの周りの内部の巨大なチャンクをリファクタリングしているため、互換性を維持するためにこれを行いますが、他のリファクタリングと同様に...何かが起こります。 はい-ビットシフトをラップし、マスク内の同じビットがラップアラウンドのために2つのイベントで再使用されるため、ifの束全体の追加作業を行います。 そのため、これはバグにつながることはなく、ビットが「タイプA」だけでなく「タイプA OR Bのイベントコールバックがある」ことを意味する場合、わずかに少ないマイクロ最適化が行われます...次のコードは実際に完全なチェックを行います/マッピング。 それは確かにラップすることを意図したものではなかったので、これはキャッチでしたが、使用方法は実際にはかなり無害であることを意味します。



残りの425個のメッセージの中には、エラーを示すものがあります。 見逃したばかりです。



PVS-Studioの通常の使用に関しては、引き続き構成できます。 私が言ったように、私はすでにセットアップに40分しか費やしていません。 しかし、これは私ができることをすべてやったという意味ではありません。 特定のソフトウェア構成の診断を無効にすることで、誤検知の数を減らすこともできます。



残りのメッセージと追加の設定をさらに慎重に検討すると、誤検知の10〜15%しか残りません。 良い結果。



見つかったバグ



次に、見つけたエラーについて考えてみましょう。 950をすべて説明することはできません。したがって、各タイプの警告のペアを解析することに限定します。 残りの警告は、個別のファイルとしてリストします。



また、読者自身がレポートファイルを開くことにより、すべての警告に精通することができます。 ファイルには高および中の信頼レベルの一般的な警告のみを残したことに注意してください。



このレポートをWindowsで見て、PVS-Studio Standaloneユーティリティを使用して開きました。



Linuxでは、レポートを次のいずれかの形式に変換するPlog Converterユーティリティを使用できます。

さらに、レポートを表示するには、QtCreator、Vim / gVim、GNU Emacs、LibreOffice Calcを使用できます。 これについては、ドキュメントセクション「 LinuxでPVS-Studioを実行する方法 」で詳しく説明しています(「アナライザーレポートの表示とフィルター処理」を参照)。



V501(1エラー)



Diagnostics V501は1つのエラーのみを明らかにしましたが、それは美しいものです。 エラーは比較機能にあり、最近の記事「 悪は比較機能に生きる 」のテーマを反映しています

 static int _ephysics_body_evas_stacking_sort_cb(const void *d1, const void *d2) { const EPhysics_Body_Evas_Stacking *stacking1, *stacking2; stacking1 = (const EPhysics_Body_Evas_Stacking *)d1; stacking2 = (const EPhysics_Body_Evas_Stacking *)d2; if (!stacking1) return 1; if (!stacking2) return -1; if (stacking1->stacking < stacking2->stacking) return -1; if (stacking2->stacking > stacking2->stacking) return 1; return 0; }
      
      





PVS-Studio警告:V501「>」演算子の左側と右側には、同一の部分式「stacking2-> stacking」があります。 ephysics_body.cpp 450



タイプミス。 最後の比較は次のようになります。

 if (stacking1->stacking > stacking2->stacking) return 1;
      
      







V512(8エラー)



まず、 Eina_Array構造体の定義を見てください。

 typedef struct _Eina_Array Eina_Array; struct _Eina_Array { int version; void **data; unsigned int total; unsigned int count; unsigned int step; Eina_Magic __magic; };
      
      





必要ではないことを慎重に検討してください。 ある種のフィールドを持つ単なる構造。



次に、 Eina_Accessor_Array構造体の定義を見てください。

 typedef struct _Eina_Accessor_Array Eina_Accessor_Array; struct _Eina_Accessor_Array { Eina_Accessor accessor; const Eina_Array *array; Eina_Magic __magic; };
      
      





Eina_Accessor_Array構造体がEina_Array構造体へのポインターを保持していることに注意してください 。 それ以外の場合、これらの構造は相互接続されておらず、サイズが異なります。



アナライザーが特定したコードで、私が理解できないコード:

 static Eina_Accessor * eina_array_accessor_clone(const Eina_Array *array) { Eina_Accessor_Array *ac; EINA_SAFETY_ON_NULL_RETURN_VAL(array, NULL); EINA_MAGIC_CHECK_ARRAY(array); ac = calloc(1, sizeof (Eina_Accessor_Array)); if (!ac) return NULL; memcpy(ac, array, sizeof(Eina_Accessor_Array)); return &ac->accessor; }
      
      





PVS-Studio警告: V512 「memcpy」関数を呼び出すと、「配列」バッファーが範囲外になります。 eina_array.c 186



不要な詳細をすべて削除して、簡単にします。

 .... eina_array_accessor_clone(const Eina_Array *array) { Eina_Accessor_Array *ac = calloc(1, sizeof (Eina_Accessor_Array)); memcpy(ac, array, sizeof(Eina_Accessor_Array)); }
      
      





Eina_Accessor_Array型のオブジェクトにメモリが割り当てられます。 その後、奇妙なことが起こります。



タイプEina_Arrayのオブジェクトは、割り当てられたメモリバッファにコピーされます。







なに?








考慮された関数が何をすべきかはわかりませんが、何か間違っています。



まず、コピーするとき、ソースは範囲外になります (構造Eina_Array )。



第二に、一般的にそのようなコピーは意味をなしません。 構造には、まったく異なるタイプのフィールドのセットがあります。



Carsten Haitzlerによるコメント。 関数の内容が正しい-パラメーターの入力が間違っています。 関数は正しい型を持つfunc ptrに割り当てられ、汎用の「親クラス」であるため、割り当ては汎用アクセサ型にキャストされるため、コンパイラは文句を言わず、これは機能するように見えたため、実際には問題ではありませんでした。



次のエラーを考慮してください。

 static Eina_Bool _convert_etc2_rgb8_to_argb8888(....) { const uint8_t *in = src; uint32_t *out = dst; int out_step, x, y, k; unsigned int bgra[16]; .... for (k = 0; k < 4; k++) memcpy(out + x + k * out_step, bgra + k * 16, 16); .... }
      
      





PVS-Studio警告:V512「memcpy」関数を呼び出すと、バッファー「bgra + k * 16」がオーバーフローします。 draw_convert.c 318



ここではすべてが簡単です。 通常出口の海外バッファー。



bgra配列は、 unsigned int型の16個の要素で構成されています。



変数kは、サイクルの0〜3の値を取ります。



式に注意してください: bgra + k * 16



変数kの値が0より大きい場合、配列の外側を指すポインターが計算されます。



ただし、一部のV512メッセージは、実際のエラーを含まないコードを示しています。 ただし、このようなアナライザーの応答は偽とは見なしません。 コードは悪いので、私の意見では、変更する必要があります。 この場合を検討してください。

 #define MATRIX_XX(m) (m)->xx typedef struct _Eina_Matrix4 Eina_Matrix4; struct _Eina_Matrix4 { double xx; double xy; double xz; double xw; double yx; double yy; double yz; double yw; double zx; double zy; double zz; double zw; double wx; double wy; double wz; double ww; }; EAPI void eina_matrix4_array_set(Eina_Matrix4 *m, const double *v) { memcpy(&MATRIX_XX(m), v, sizeof(double) * 16); }
      
      





PVS-Studio警告:V512「memcpy」関数を呼び出すと、バッファー「&(m)-> xx」がオーバーフローします。 eina_matrix.c 1003



配列を構造体にコピーするだけで済みます。 しかし、代わりに、最初のxxメンバーのアドレスが取得されます。 おそらく、将来、他のフィールドが構造の最初に現れると理解されています。 そして、プログラムの動作が壊れないように、そのような手法が使用されます。



Carsten Haitzlerによるコメント。 上記および関連するmemcpyの-バグではありません:構造体で保証されたmemレイアウトを利用します。



私は彼が好きではありません。 次のようなものを書くことをお勧めします。

 struct _Eina_Matrix4 { union { struct { double xx; double xy; double xz; double xw; double yx; double yy; double yz; double yw; double zx; double zy; double zz; double zw; double wx; double wy; double wz; double ww; }; double RawArray[16]; }; }; EAPI void void eina_matrix4_array_set(Eina_Matrix4 *m, const double *v) { memcpy(m->RawArray, v, sizeof(double) * 16); }
      
      





これは少し長くなりますが、イデオロギー的には真実です。 ただし、コードを編集したくない場合は、次のいずれかの方法で警告を抑制することができます。



最初の方法。 コードにコメントを追加します。

 memcpy(&MATRIX_XX(m), v, sizeof(double) * 16); //-V512
      
      





2番目の方法。 設定ファイルに次の行を追加します。

 //-V:MATRIX_:512
      
      





第三の方法。 マークアップデータベースを使用します



その他のエラー:



V517(3エラー)



 static Eina_Bool evas_image_load_file_head_bmp(void *loader_data, Evas_Image_Property *prop, int *error) { .... if (header.comp == 0) // no compression { // handled } else if (header.comp == 3) // bit field { // handled } else if (header.comp == 4) // jpeg - only printer drivers goto close_file; else if (header.comp == 3) // png - only printer drivers goto close_file; else goto close_file; .... }
      
      





PVS-Studio 警告V517 「if(A){...} else if(A){...}」パターンの使用が検出されました。 論理エラーが存在する可能性があります。 行を確認してください:433、439。evas_image_load_bmp.c 433



2回、変数header.compは定数3と比較されます。



その他のエラー:



V519(1エラー)



 EOLIAN static Efl_Object * _efl_net_ssl_context_efl_object_finalize(....) { Efl_Net_Ssl_Ctx_Config cfg; .... cfg.load_defaults = pd->load_defaults; // <= cfg.certificates = &pd->certificates; cfg.private_keys = &pd->private_keys; cfg.certificate_revocation_lists = &pd->certificate_revocation_lists; cfg.certificate_authorities = &pd->certificate_authorities; cfg.load_defaults = pd->load_defaults; // <= .... }
      
      





PVS-Studio警告: V519 「cfg.load_defaults」変数には連続して2回値が割り当てられます。 おそらくこれは間違いです。 行を確認してください:304、309。efl_net_ssl_context.c 309



割り当てが繰り返されます。 1つの割り当てが不要であるか、他の何かをコピーするのを忘れていました。



Carsten Haitzlerによるコメント。 バグではありません。 行の熱心なコピー&ペーストだけです。



別の単純なケース:

 EAPI Eina_Bool edje_edit_size_class_add(Evas_Object *obj, const char *name) { Eina_List *l; Edje_Size_Class *sc, *s; .... /* set default values for max */ s->maxh = -1; s->maxh = -1; .... }
      
      





PVS-Studio警告:V519 's-> maxh'変数には、連続して2回値が割り当てられます。 おそらくこれは間違いです。 行を確認してください:8132、8133。edje_edit.c 8133



もちろん、すべてのケースがそれほど明白ではありません。 ただし、以下の警告はエラーを示している可能性が高いと考えています。

ご注意 Carsten Haitzlerはこの記事にコメントして、記載されているV519警告は誤検知であると書いています。 私はこのアプローチに同意しません。 コードは正しく動作する可能性がありますが、とにかく注意と編集に値します。 読者が自分の観点から、変数の誤検出への割り当ての繰り返しかどうかを評価できるように、記事にリストを残すことにしました。 しかし、Carstenはこれらは間違いではないと言うので、計算では考慮しません。



V522(563エラー)















EFLプロジェクトには、チェックの存在に関する問題があります。メモリが割り当てられているかどうかです。 一般に、プロジェクトにはそのようなチェックがあります。 例:

 if (!(el = malloc(sizeof(Evas_Stringshare_El) + slen + 1))) return NULL;
      
      





さらに、それらは必要のない場所でもあります(警告V668については以下を参照)。



しかし、非常に多くの場所で検証は行われていません。 たとえば、アナライザーのメッセージをいくつか考えてみましょう。



Carsten Haitzlerによるコメント。 これは、少なくともLinuxが常に主な焦点であり、長い間唯一のターゲットであったため、malloc / calloc / reallocからの戻り値は特に少量では信頼できないという一般的な受け入れです。 Linuxはデフォルトでメモリをオーバーコミットします。 つまり、新しいメモリを取得しますが、カーネルは実際の物理メモリページをまだ割り当てていません。 仮想空間のみ。 触れるまでは。 カーネルがこのリクエストを処理できない場合、プログラムは有効なポインターのように見えるメモリにアクセスしようとしてクラッシュします。 したがって、少なくともLinuxで小さいallocの戻り値をチェックすることのすべての価値は低いです。 時にはそれを行います...時には行いません。 ただし、非常に大量のメモリがない限り、戻り値は一般的に信頼できません。たとえば、allocはサービスされません。たとえば、allocが仮想アドレス空間にまったく収まらない場合があります(32ビットの場合もあります)。 はい、オーバーコミットは調整できますが、ほとんどの人が決して支払いたくない、あるいは誰も調整できることさえ知らないというコストがかかります。 第二に、メモリの小さなチャンクでfi allocが失敗します。たとえば、リンクリストノード...現実的にNULLが返された場合...クラッシュはできることとほぼ同等です メモリが非常に少ないため、クラッシュする可能性があります。glibがg_mallocで行うように、abort()を呼び出します。20〜40バイトを割り当てることができない場合...作業メモリが残っていないため、システムが倒れるからです。 私はここで小さな組み込みシステムについて話しているのではなく、仮想メモリと数メガバイトのメモリを備えた大きなマシンなどについて話しています。 これが私たちの目標でした。 PVS-Studioがこれを好まない理由がわかります。 厳密には実際には正しいのですが、実際には、このようなものの処理に費やされるコードは、状況の現実を考えると、コードの無駄です。 これについては後で詳しく説明します。

 static Eina_Debug_Session * _session_create(int fd) { Eina_Debug_Session *session = calloc(1, sizeof(*session)); session->dispatch_cb = eina_debug_dispatch; session->fd = fd; // start the monitor thread _thread_start(session); return session; }
      
      





Carsten Haitzlerによるコメント。 これは2か月前に到着した新しいコードで、まだ構築およびテストされており、プライムタイムの準備ができていません。 ライブデバッグインフラストラクチャの一部であり、EFLを使用するアプリは、デバッガデーモン(実行されている場合)によって制御され、制御されます(メモリ内のすべてのオブジェクトと、実行中にイントロスペクションでオブジェクトツリーとその状態を検査します)、実行を収集しますタイムラインログ(どのスレッドでどの関数呼び出しツリーにどのくらいの時間が費やされているか-どのスレッドがどのスロットでms以下のスロットにCPU時間を使用しているか、関数呼び出し、アニメーションシステムの状態、およびウェイクアップ時に相関イベントが発生し、ウェイクアップをトリガーしたデバイスのタイムスタンプなど...そのシナリオを考えると...メモリの最初のページにアクセスするクラッシュのデバッグ中に小さなセッション構造体を呼び出すことができない場合は、何と同じくらい良いです...上記のメモリおよびアボートなど



アンドレイ・カルポフによるコメント。 あまり明確ではありませんが、ここに新しくテストされていないコードがあります。 静的アナライザーは、主に新しいコードのエラーを探すように設計されています。



PVS-Studio警告: V522潜在的なヌルポインター「セッション」の逆参照が存在する可能性があります。 eina_debug.c 440



calloc関数を使用してメモリを割り当て、すぐに使用しました。



別の例:

 static Reference * _entry_reference_add(Entry *entry, Client *client, unsigned int client_entry_id) { Reference *ref; // increase reference for this file ref = malloc(sizeof(*ref)); ref->client = client; ref->entry = entry; ref->client_entry_id = client_entry_id; ref->count = 1; entry->references = eina_list_append(entry->references, ref); return ref; }
      
      





PVS-Studio警告:V522潜在的なヌルポインター 'ref'の逆参照がある可能性があります。 evas_cserve2_cache.c 1404



563回です。 記事では引用できません。 EFL_V522.txtファイルへのリンクを提供します。



V547(39エラー)



 static void _ecore_con_url_dialer_error(void *data, const Efl_Event *event) { Ecore_Con_Url *url_con = data; Eina_Error *perr = event->info; int status; status = efl_net_dialer_http_response_status_get(url_con->dialer); if ((status < 500) && (status > 599)) { DBG("HTTP error %d reset to 1", status); status = 1; /* not a real HTTP error */ } WRN("HTTP dialer error url='%s': %s", efl_net_dialer_address_dial_get(url_con->dialer), eina_error_msg_get(*perr)); _ecore_con_event_url_complete_add(url_con, status); }
      
      





PVS-Studio 警告V547式 '(ステータス<500)&&(ステータス> 599)'は常にfalseです。 ecore_con_url.c 351



チェックの正しいバージョンは次のようになります。

 if ((status < 500) || (status > 599))
      
      





このエラーを含むコードスニペットは、さらに2つの場所にコピーされました。

次のエラー状況:

 EAPI void eina_rectangle_pool_release(Eina_Rectangle *rect) { Eina_Rectangle *match; Eina_Rectangle_Alloc *new; .... match = (Eina_Rectangle *) (new + 1); if (match) era->pool->empty = _eina_rectangle_skyline_list_update( era->pool->empty, match); .... }
      
      





PVS-Studio警告:V547式「一致」は常に真です。 eina_rectangle.c 798



ユニットがポインターに追加された後、 NULLをチェックしても意味がありません。



加算中にオーバーフローが発生した場合にのみ、 一致ポインターがゼロになることがあります。 ただし、ポインターオーバーフローは未定義の動作と見なされるため、このオプションは考慮しないでください。



そしてもう一つのケース。

 EAPI const void * evas_object_smart_interface_get(const Evas_Object *eo_obj, const char *name) { Evas_Smart *s; .... s = evas_object_smart_smart_get(eo_obj); if (!s) return NULL; if (s) .... }
      
      





PVS-Studio警告:V547式 's'は常に真です。 evas_object_smart.c 160



ポインターがNULLの場合、関数は終了します。 再確認は意味がありません。



その他のエラー: EFL_V547.txt



私はそれらを理解することに興味がなかったので、私は逃し、書き出さなかったV547警告があります。 それらの中には、さらにいくつかのエラーがあります。



V556(8エラー)



1つのコードで8つのエラーがすべて発行されます。 最初に、2つのリストの発表を見てみましょう。

 typedef enum _Elm_Image_Orient_Type { ELM_IMAGE_ORIENT_NONE = 0, ELM_IMAGE_ORIENT_0 = 0, ELM_IMAGE_ROTATE_90 = 1, ELM_IMAGE_ORIENT_90 = 1, ELM_IMAGE_ROTATE_180 = 2, ELM_IMAGE_ORIENT_180 = 2, ELM_IMAGE_ROTATE_270 = 3, ELM_IMAGE_ORIENT_270 = 3, ELM_IMAGE_FLIP_HORIZONTAL = 4, ELM_IMAGE_FLIP_VERTICAL = 5, ELM_IMAGE_FLIP_TRANSPOSE = 6, ELM_IMAGE_FLIP_TRANSVERSE = 7 } Elm_Image_Orient; typedef enum { EVAS_IMAGE_ORIENT_NONE = 0, EVAS_IMAGE_ORIENT_0 = 0, EVAS_IMAGE_ORIENT_90 = 1, EVAS_IMAGE_ORIENT_180 = 2, EVAS_IMAGE_ORIENT_270 = 3, EVAS_IMAGE_FLIP_HORIZONTAL = 4, EVAS_IMAGE_FLIP_VERTICAL = 5, EVAS_IMAGE_FLIP_TRANSPOSE = 6, EVAS_IMAGE_FLIP_TRANSVERSE = 7 } Evas_Image_Orient;
      
      





ご覧のとおり、これらの列挙の定数の名前は似ています。 .

 EAPI void elm_image_orient_set(Evas_Object *obj, Elm_Image_Orient orient) { Efl_Orient dir; Efl_Flip flip; EFL_UI_IMAGE_DATA_GET(obj, sd); sd->image_orient = orient; switch (orient) { case EVAS_IMAGE_ORIENT_0: .... case EVAS_IMAGE_ORIENT_90: .... case EVAS_IMAGE_FLIP_HORIZONTAL: .... case EVAS_IMAGE_FLIP_VERTICAL: .... }
      
      





PVS-Studioの警告:

, .



, , . :

, .



Comment by Carsten Haitzler. All of the above orient/rotate enum stuff is intentional. We had to cleanup duplication of enums and we ensured they had the same values so they were interchangeable — we moved from rotate to orient and kept the compatibility. It's part of our move over to the new object system and a lot of code auto-generation etc. that is still underway and beta. It's not an error but intended to do this as part of transitioning, so it's a false positive.



. , false positives. , , - , .



V558 (4 )



 accessor_iterator<T>& operator++(int) { accessor_iterator<T> tmp(*this); ++*this; return tmp; }
      
      





PVS-Studio: V558 Function returns the reference to temporary local object: tmp. eina_accessor.hh 519



, & :

 accessor_iterator<T> operator++(int)
      
      





:



V560 (32 )



 static unsigned int read_compressed_channel(....) { .... signed char headbyte; .... if (headbyte >= 0) { .... } else if (headbyte >= -127 && headbyte <= -1) // <= .... }
      
      





PVS-Studio: V560 A part of conditional expression is always true: headbyte <= — 1. evas_image_load_psd.c 221



headbyte >= 0, <= -1 .



別のケースを考えてみましょう。

 static Eeze_Disk_Type _eeze_disk_type_find(Eeze_Disk *disk) { const char *test; .... test = udev_device_get_property_value(disk->device, "ID_BUS"); if (test) { if (!strcmp(test, "ata")) return EEZE_DISK_TYPE_INTERNAL; if (!strcmp(test, "usb")) return EEZE_DISK_TYPE_USB; return EEZE_DISK_TYPE_UNKNOWN; } if ((!test) && (!filesystem)) // <= .... }
      
      





PVS-Studio: V560 A part of conditional expression is always true: (!test). eeze_disk.c 55



. test , .



: EFL_V560.txt .



V568 (3 )



 EOLIAN static Eina_Error _efl_net_server_tcp_efl_net_server_fd_socket_activate(....) { .... struct sockaddr_storage *addr; socklen_t addrlen; .... addrlen = sizeof(addr); if (getsockname(fd, (struct sockaddr *)&addr, &addrlen) != 0) .... }
      
      





PVS-Studio: V568 It's odd that 'sizeof()' operator evaluates the size of a pointer to a class, but not the size of the 'addr' class object. efl_net_server_tcp.c 192



, , . :

 addrlen = sizeof(*addr);
      
      





:



V571 (6 )



 EAPI void eeze_disk_scan(Eeze_Disk *disk) { .... if (!disk->cache.vendor) if (!disk->cache.vendor) disk->cache.vendor = udev_device_get_sysattr_value(....); .... }
      
      





PVS-Studio: V571 Recurring check. The 'if (!disk->cache.vendor)' condition was already verified in line 298. eeze_disk.c 299



.



:

ご注意 Carsten Haitzler . . , . , . , .



V575 (126 )



, . .

 static void free_buf(Eina_Evlog_Buf *b) { if (!b->buf) return; b->size = 0; b->top = 0; # ifdef HAVE_MMAP munmap(b->buf, b->size); # else free(b->buf); # endif b->buf = NULL; }
      
      





PVS-Studio: V575 The 'munmap' function processes '0' elements. Inspect the second argument. eina_evlog.c 117



b->size 0, munmap .



, :

 static void free_buf(Eina_Evlog_Buf *b) { if (!b->buf) return; b->top = 0; # ifdef HAVE_MMAP munmap(b->buf, b->size); # else free(b->buf); # endif b->buf = NULL; b->size = 0; }
      
      





.

 EAPI Eina_Bool eina_simple_xml_parse(....) { .... else if ((itr + sizeof("<!>") - 1 < itr_end) && (!memcmp(itr + 2, "", sizeof("") - 1))) .... }
      
      





PVS-Studio: V575 The 'memcmp' function processes '0' elements. Inspect the third argument. eina_simple_xml_parser.c 355



, 0 .



.

 static void _edje_key_down_cb(....) { .... char *compres = NULL, *string = (char *)ev->string; .... if (compres) { string = compres; free_string = EINA_TRUE; } else free(compres); .... }
      
      





PVS-Studio: V575 The null pointer is passed into 'free' function. 最初の引数を調べます。 edje_entry.c 2306



compress , .

 else free(compres);
      
      





.



Comment by Carsten Haitzler. Not a bug but indeed some extra if paranoia like code that isn't needed. Micro optimizations again?



. . , . , , . , , .



:

V575 . - , , V522.

 static void _fill_all_outs(char **outs, const char *val) { size_t vlen = strlen(val); for (size_t i = 0; i < (sizeof(_dexts) / sizeof(char *)); ++i) { if (outs[i]) continue; size_t dlen = strlen(_dexts[i]); char *str = malloc(vlen + dlen + 1); memcpy(str, val, vlen); memcpy(str + vlen, _dexts[i], dlen); str[vlen + dlen] = '\0'; outs[i] = str; } }
      
      





PVS-Studio: V575 The potential null pointer is passed into 'memcpy' function. 最初の引数を調べます。 main.c 112



, , .



: EFL_V575.txt .



V587 (2 )



 void _ecore_x_event_handle_focus_in(XEvent *xevent) { .... e->time = _ecore_x_event_last_time; _ecore_x_event_last_time = e->time; .... }
      
      





PVS-Studio: V587 An odd sequence of assignments of this kind: A = B; B = A;. Check lines: 1006, 1007. ecore_x_events.c 1007



Comment by Carsten Haitzler. Not bugs as such — looks like just overzealous storing of last timestamp. This is adding a timestamp to an event when no original timestamp exists so we can keep a consistent structure for events with timestamps, but it is code clutter and a micro optimization.



. , . , Carsten , . .



: V587 An odd sequence of assignments of this kind: A = B; B = A;. Check lines: 1050, 1051. ecore_x_events.c 1051



V590 (3 )



 static int command(void) { .... while (*lptr == ' ' && *lptr != '\0') lptr++; /* skip whitespace */ .... }
      
      





PVS-Studio: V590 Consider inspecting the '* lptr == ' ' && * lptr != '\0'' expression. The expression is excessive or contains a misprint. embryo_cc_sc2.c 944



. :

 while (*lptr == ' ')
      
      





:



V591 (1 )



 _self_type& operator=(_self_type const& other) { _base_type::operator=(other); }
      
      





PVS-Studio: V591 Non-void function should return a value. eina_accessor.hh 330



V595 (4 )



 static void eng_image_size_get(void *engine EINA_UNUSED, void *image, int *w, int *h) { Evas_GL_Image *im; if (!image) { *w = 0; // <= *h = 0; // <= return; } im = image; if (im->orient == EVAS_IMAGE_ORIENT_90 || im->orient == EVAS_IMAGE_ORIENT_270 || im->orient == EVAS_IMAGE_FLIP_TRANSPOSE || im->orient == EVAS_IMAGE_FLIP_TRANSVERSE) { if (w) *w = im->h; if (h) *h = im->w; } else { if (w) *w = im->w; if (h) *h = im->h; } }
      
      





PVS-Studioの警告:

if (w) if (h) , w h NULL . , .



eng_image_size_get :

 eng_image_size_get(NULL, NULL, NULL, NULL);
      
      





.



, , , :



V597 (6 )



 EAPI Eina_Binbuf * emile_binbuf_decipher(Emile_Cipher_Algorithm algo, const Eina_Binbuf *data, const char *key, unsigned int length) { .... Eina_Binbuf *result = NULL; unsigned int *over; EVP_CIPHER_CTX *ctx = NULL; unsigned char ik[MAX_KEY_LEN]; unsigned char iv[MAX_IV_LEN]; .... on_error: memset(iv, 0, sizeof (iv)); memset(ik, 0, sizeof (ik)); if (ctx) EVP_CIPHER_CTX_free(ctx); eina_binbuf_free(result); return NULL; }
      
      





PVS-Studioの警告:

, memset . . - , V597 .



Comment by Carsten Haitzler. Above 2 — totally familiar with the issue. The big problem is memset_s is not portable or easily available, thus why we don't use it yet. You have to do special checks for it to see if it exists as it does not exist everywhere. Just as a simple example add AC_CHECK_FUNCS([memset_s]) to your configure.ac and memset_s is not found you have to jump through some more hoops like define __STDC_WANT_LIB_EXT1__ 1 before including system headers… and it's still not declared. On my pretty up to date Arch system memset_s is not defined by any system headers, same on debian testing… warning: implicit declaration of function 'memset_s'; did you mean memset'? [-Wimplicit-function-declaration], and then compile failure… no matter what I do. A grep -r of all my system includes shows no memset_s declared… so I think advising people to use memset_s is only a viable advice if its widely available and usable. Be aware of this.



:



V609 (1 )



eina_value_util_type_size .

 static inline size_t eina_value_util_type_size(const Eina_Value_Type *type) { if (type == EINA_VALUE_TYPE_INT) return sizeof(int32_t); if (type == EINA_VALUE_TYPE_UCHAR) return sizeof(unsigned char); if ((type == EINA_VALUE_TYPE_STRING) || (type == EINA_VALUE_TYPE_STRINGSHARE)) return sizeof(char*); if (type == EINA_VALUE_TYPE_TIMESTAMP) return sizeof(time_t); if (type == EINA_VALUE_TYPE_ARRAY) return sizeof(Eina_Value_Array); if (type == EINA_VALUE_TYPE_DOUBLE) return sizeof(double); if (type == EINA_VALUE_TYPE_STRUCT) return sizeof(Eina_Value_Struct); return 0; }
      
      





, 0. , :

 static inline unsigned int eina_value_util_type_offset(const Eina_Value_Type *type, unsigned int base) { unsigned size, padding; size = eina_value_util_type_size(type); if (!(base % size)) return base; padding = ( (base > size) ? (base - size) : (size - base)); return base + padding; }
      
      





PVS-Studio: V609 Mod by zero. Denominator range [0..24]. eina_inline_value_util.x 60



. , eina_value_util_type_size 0. .



Comment by Carsten Haitzler. The 0 return would only happen if you have provided totally invalid input, like again strdup(NULL)… So I call this a false positive as you cant have an eina_value generic value that is not valid without bad stuff happening — validate you passes a proper value in first. eina_value is performance sensitive btw so every check here costs something. it's like adding if() checks to the add opcode.



V610 (1 )



 void fetch_linear_gradient(....) { .... if (t + inc*length < (float)(INT_MAX >> (FIXPT_BITS + 1)) && t+inc*length > (float)(INT_MIN >> (FIXPT_BITS + 1))) .... }
      
      





PVS-Studio: V610 Unspecified behavior. シフト演算子「>>」を確認してください。 The left operand '(- 0x7fffffff — 1)' is negative. ector_software_gradient.c 412



V614 (1 )



 extern struct tm *gmtime (const time_t *__timer) __attribute__ ((__nothrow__ , __leaf__)); static void _set_headers(Evas_Object *obj) { static char part[] = "ch_0.text"; int i; struct tm *t; time_t temp; ELM_CALENDAR_DATA_GET(obj, sd); elm_layout_freeze(obj); sd->filling = EINA_TRUE; t = gmtime(&temp); // <= .... }
      
      





PVS-Studio: V614 Uninitialized variable 'temp' used. Consider checking the first actual argument of the 'gmtime' function. elm_calendar.c 720



V621 (1 )



 static void _opcodes_unregister_all(Eina_Debug_Session *session) { Eina_List *l; int i; _opcode_reply_info *info = NULL; if (!session) return; session->cbs_length = 0; for (i = 0; i < session->cbs_length; i++) eina_list_free(session->cbs[i]); .... }
      
      





PVS-Studio: V621 Consider inspecting the 'for' operator. It's possible that the loop will be executed incorrectly or won't be executed at all. eina_debug.c 405



V630 (2 )



btVector3 . , .

 class btVector3 { public: .... btScalar m_floats[4]; inline btVector3() { } .... };
      
      





Simulation_Msg :

 typedef struct _Simulation_Msg Simulation_Msg; struct _Simulation_Msg { EPhysics_Body *body_0; EPhysics_Body *body_1; btVector3 pos_a; btVector3 pos_b; Eina_Bool tick:1; };
      
      





, btVector3 . , :

 _ephysics_world_tick_dispatch(EPhysics_World *world) { Simulation_Msg *msg; if (!world->ticked) return; world->ticked = EINA_FALSE; world->pending_ticks++; msg = (Simulation_Msg *) calloc(1, sizeof(Simulation_Msg)); msg->tick = EINA_TRUE; ecore_thread_feedback(world->cur_th, msg); }
      
      





PVS-Studio: V630 The 'calloc' function is used to allocate memory for an array of objects which are classes containing constructors. ephysics_world.cpp 299



, non-POD , calloc .



, . .



: V630 The 'calloc' function is used to allocate memory for an array of objects which are classes containing constructors. ephysics_world.cpp 471



Comment by Carsten Haitzler. Because the other end of the pipe is C code that is passing around a raw ptr as the result from thread A to thread B, it's a mixed c and c++ environment. In the end we'd be sending raw ptr's around no matter what...



V654 (2 )



 int evas_mem_free(int mem_required EINA_UNUSED) { return 0; } int evas_mem_degrade(int mem_required EINA_UNUSED) { return 0; } void * evas_mem_calloc(int size) { void *ptr; ptr = calloc(1, size); if (ptr) return ptr; MERR_BAD(); while ((!ptr) && (evas_mem_free(size))) ptr = calloc(1, size); if (ptr) return ptr; while ((!ptr) && (evas_mem_degrade(size))) ptr = calloc(1, size); if (ptr) return ptr; MERR_FATAL(); return NULL; }
      
      





PVS-Studioの警告:

- .



Comment by Carsten Haitzler. Old old code because caching was implemented, so it was basically a lot of NOP's waiting to be filled in. since evas speculatively cached data (megabytes of it) the idea was that if allocs fail — free up some cache and try again… if that fails then actually try nuke some non-cached data that could be reloaded/rebuilt but with more cost… and only fail after that. But because of overcommit this didn't end up practical as allocs would succeed then just fall over often enough if you did hit a really low memory situation, so I gave up. it's not a bug. it's a piece of history :).



.







WTF






 EAPI void evas_common_font_query_size(....) { .... size_t cluster = 0; size_t cur_cluster = 0; .... do { cur_cluster = cluster + 1; glyph--; if (cur_w > ret_w) { ret_w = cur_w; } } while ((glyph > first_glyph) && (cur_cluster == cluster)); .... }
      
      





PVS-Studio: V654 The condition of loop is always false. evas_font_query.c 376



:

 cur_cluster = cluster + 1;
      
      





, (cur_cluster == cluster) false .



Comment by Carsten Haitzler. Above… it seems you built without harfbuzz support… we highly don't recommend that. it's not tested. Building without basically nukes almost all of the interesting unicode/intl support for text layout. You do have to explicitly — disable it… because with harfbuzz support we have opentype enabled and a different bit of code is executed due to ifdefs… if you actually check history of the code before adding opentype support it didn't loop over clusters at all or even glyphs… so really the ifdef just ensures the loop only loops one and avoids more ifdefs later in the loop conditions making the code easier to maintain — beware the ifdefs!



V668 (21 )



, , malloc / calloc .



new - .















:

 static EPhysics_Body * _ephysics_body_rigid_body_add(....) { .... motion_state = new btDefaultMotionState(); if (!motion_state) { ERR("Couldn't create a motion state."); goto err_motion_state; } .... }
      
      





PVS-Studio: V668 There is no sense in testing the 'motion_state' pointer against null, as the memory was allocated using the 'new' operator. メモリ割り当てエラーの場合、例外が生成されます。 ephysics_body.cpp 837



, std::bad_alloc .



Comment by Carsten Haitzler. Fair enough, but be aware some compiler DON'T throw exceptions… they return NULL on new… so not totally useless code depending on the compiler. I believe VSC6 didn't throw an exception — so before exceptions were a thing this actually was correct behavior, also I depends on the allocator func if it throws and exception or not, so all in all, very minor harmless code.



. . . .



:

 EAPI EPhysics_Constraint * ephysics_constraint_linked_add(EPhysics_Body *body1, EPhysics_Body *body2) { .... constraint->bt_constraint = new btGeneric6DofConstraint( *ephysics_body_rigid_body_get(body1), *ephysics_body_rigid_body_get(body2), btTransform(), btTransform(), false); if (!constraint->bt_constraint) { ephysics_world_lock_release(constraint->world); free(constraint); return NULL; } .... }
      
      





PVS-Studio: V668 There is no sense in testing the 'constraint->bt_constraint' pointer against null, as the memory was allocated using the 'new' operator. メモリ割り当てエラーの場合、例外が生成されます。 ephysics_constraints.cpp 382



, , , free .



Comment by Carsten Haitzler. Same as previous new + NULL check.



. , Visual C++ 6.0. , new. , , . Tizen Visual C++ 6.0! . , . , . , . , memory-leak. , new , new(nothrow). . , , .



: EFL_V668.txt .



V674 (2 )



, abs :

 extern int abs (int __x) __attribute__ ((__nothrow__ , __leaf__)) __attribute__ ((__const__)) ;
      
      





, int .



, .

 #define ELM_GESTURE_MINIMUM_MOMENTUM 0.001 typedef int Evas_Coord; struct _Elm_Gesture_Momentum_Info { .... Evas_Coord mx; Evas_Coord my; .... }; static void _momentum_test(....) { .... if ((abs(st->info.mx) > ELM_GESTURE_MINIMUM_MOMENTUM) || (abs(st->info.my) > ELM_GESTURE_MINIMUM_MOMENTUM)) state_to_report = ELM_GESTURE_STATE_END; .... }
      
      





PVS-Studioの警告:

, int 0.001. - .



V686 (3 )



 static Image_Entry * _scaled_image_find(Image_Entry *im, ....) { size_t pathlen, keylen, size; char *hkey; Evas_Image_Load_Opts lo; Image_Entry *ret; if (((!im->file) || ((!im->file) && (!im->key))) || (!im->data1) || ((src_w == dst_w) && (src_h == dst_h)) || ((!im->flags.alpha) && (!smooth))) return NULL; .... }
      
      





PVS-Studio: V686 A pattern was detected: (!im->file) || ((!im->file) && ...). The expression is excessive or contains a logical error. evas_cache2.c 825



, . .



if (A || (A && B) || C)



:



if (A || C)



, - - . . .



:



V694 (2 )



 #define CPP_PREV_BUFFER(BUFFER) ((BUFFER)+1) static void initialize_builtins(cpp_reader * pfile) { .... cpp_buffer *pbuffer = CPP_BUFFER(pfile); while (CPP_PREV_BUFFER(pbuffer)) pbuffer = CPP_PREV_BUFFER(pbuffer); .... }
      
      





PVS-Studio: V694 The condition ((pbuffer) + 1) is only false if there is pointer overflow which is undefined behavior anyway. cpplib.c 2496



, .

 cpp_buffer *pbuffer = ....; while (pbuffer + 1) ....
      
      





. , . . undefined behavior, . , :

 while (true) pbuffer = CPP_PREV_BUFFER(pbuffer);
      
      





.



: V694 The condition ((ip) + 1) is only false if there is pointer overflow which is undefined behavior anyway. cpplib.c 2332



Comment by Carsten Haitzler. This old code indeed has issues. There should be checks against CPP_NULL_BUFFER(pfile) because if its a linked list this is a null heck, if its a static buffer array as a stack, it checks stack end position — interestingly in decades it's never been triggered that I know of.



V701 (69 )



 static void _efl_vg_gradient_efl_gfx_gradient_stop_set( ...., Efl_VG_Gradient_Data *pd, ....) { pd->colors = realloc(pd->colors, length * sizeof(Efl_Gfx_Gradient_Stop)); if (!pd->colors) { pd->colors_count = 0; return ; } memcpy(pd->colors, colors, length * sizeof(Efl_Gfx_Gradient_Stop)); pd->colors_count = length; _efl_vg_changed(obj); }
      
      





PVS-Studio: V701 realloc() possible leak: when realloc() fails in allocating memory, original pointer 'pd->colors' is lost. Consider assigning realloc() to a temporary pointer. evas_vg_gradient.c 14



:

 pd->colors = realloc(pd->colors, ....);
      
      





pd->colors . , . , pd->colors NULL .



. , . , , . :

 EOLIAN void _evas_canvas_key_lock_add( Eo *eo_e, Evas_Public_Data *e, const char *keyname) { if (!keyname) return; if (e->locks.lock.count >= 64) return; evas_key_lock_del(eo_e, keyname); e->locks.lock.count++; e->locks.lock.list = realloc(e->locks.lock.list, e->locks.lock.count * sizeof(char *)); e->locks.lock.list[e->locks.lock.count - 1] = strdup(keyname); eina_hash_free_buckets(e->locks.masks); }
      
      





PVS-Studio: V701 realloc() possible leak: when realloc() fails in allocating memory, original pointer 'e->locks.lock.list' is lost. Consider assigning realloc() to a temporary pointer. evas_key.c 142



: EFL_701.txt .



V728 (4 )



 static Eina_Bool _evas_textblock_node_text_adjust_offsets_to_start(....) { Evas_Object_Textblock_Node_Format *last_node, *itr; .... if (!itr || (itr && (itr->text_node != n))) .... }
      
      





PVS-Studio: V728 An excessive check can be simplified. 「||」 operator is surrounded by opposite expressions '!itr' and 'itr'. evas_object_textblock.c 9505



, . :

 if (!itr || (itr->text_node != n))
      
      





:



V769 (11 )



V522, . .

 EAPI Eina_Bool edje_edit_sound_sample_add( Evas_Object *obj, const char *name, const char *snd_src) { .... ed->file->sound_dir->samples = realloc(ed->file->sound_dir->samples, sizeof(Edje_Sound_Sample) * ed->file->sound_dir->samples_count); sound_sample = ed->file->sound_dir->samples + ed->file->sound_dir->samples_count - 1; sound_sample->name = (char *)eina_stringshare_add(name); .... }
      
      





PVS-Studio: V769 The 'ed->file->sound_dir->samples' pointer in the expression could be nullptr. In such case, resulting value of arithmetic operations on this pointer will be senseless and it should not be used. edje_edit.c 1271



. , . , , . , , . .



, , . . (NULL + N) , - .



:



V779 (19 )



V779 , , . 例:

 EAPI Eina_Bool ecore_x_xinerama_screen_geometry_get(int screen, int *x, int *y, int *w, int *h) { LOGFN(__FILE__, __LINE__, __FUNCTION__); #ifdef ECORE_XINERAMA if (_xin_info) { int i; for (i = 0; i < _xin_scr_num; i++) { if (_xin_info[i].screen_number == screen) { if (x) *x = _xin_info[i].x_org; if (y) *y = _xin_info[i].y_org; if (w) *w = _xin_info[i].width; if (h) *h = _xin_info[i].height; return EINA_TRUE; } } } #endif /* ifdef ECORE_XINERAMA */ if (x) *x = 0; if (y) *y = 0; if (w) *w = DisplayWidth(_ecore_x_disp, 0); if (h) *h = DisplayHeight(_ecore_x_disp, 0); return EINA_FALSE; screen = 0; // <= }
      
      





PVS-Studio警告:V779到達不能コードが検出されました。 エラーが存在する可能性があります。 ecore_x_xinerama.c 92



, screen . - , , , .



EINA_UNUSED .



:

 extern void _exit (int __status) __attribute__ ((__noreturn__)); static void _timeout(int val) { _exit(-1); if (val) return; }
      
      





PVS-Studio警告:V779到達不能コードが検出されました。 エラーが存在する可能性があります。 timeout.c 30



_exit . . , :

 static void _timeout(int val) { if (val) return; _exit(-1); }
      
      





Comment by Carsten Haitzler. Not a bug. it's also an unused param thing from before the macros. The timeout has the process self exit in case it takes too long (assuming the decoder lib is stuck if a timeout happens).



. . , , . . , .



: EFL_V779.txt .



V1001 (6 )



 static Elocation_Address *address = NULL; EAPI Eina_Bool elocation_address_get(Elocation_Address *address_shadow) { if (!address) return EINA_FALSE; if (address == address_shadow) return EINA_TRUE; address_shadow = address; return EINA_TRUE; }
      
      





PVS-Studio: V1001 The 'address_shadow' variable is assigned but is not used until the end of the function. elocation.c 1122



. , :

 *address_shadow = *address;
      
      





:



Carsten Haitzler



PVS-Studio Coverity. ( , ). , , (). , Coverity, . , PVS-Studio Coverity , Coverity , , . , , -, PVS-Studio Coverity, — .



おわりに



, , .



, . , EFL Coverity. , PVS-Studio . , PVS-Studio , :). , , PVS-Studio, Coverity, PVS-Studio .







PVS-Studioを使用する








PVS-Studio :

.







この記事を英語圏の聴衆と共有したい場合は、翻訳へのリンクを使用してください:Andrey Karpov。 Characteristics of PVS-Studio Analyzer by the Example of EFL Core Libraries, 10-15% of False Positives



記事を読んで質問がありますか?
多くの場合、記事には同じ質問が寄せられます。 ここで回答を収集しました: PVS-Studioバージョン2015に関する記事の読者からの質問への回答 。 リストをご覧ください。



All Articles