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に関する蚘事の読者からの質問ぞの回答 。 リストをご芧ください。

Source: https://habr.com/ru/post/J334554/


All Articles