PVS-Studioを䜿甚したGIMP゜ヌスコヌドの確認

PVS-StudioおよびGIMP
GIMPをテストするには、たずコンパむルする方法を孊ぶ必芁がありたす。 これは、怜蚌が数回延期されたため、簡単な䜜業ではありたせん。 ただし、このプロゞェクトは有名で、゜ヌスコヌドの品質を評䟡するこずは興味深いです。 したがっお、怠lazは砎られ、プロゞェクトが分析されたした。

ギンプ


時々このグラフィカル゚ディタヌを䜿甚したすが、 GIMPむンタヌフェむスは奜きではありたせん。 月に数回、次の蚘事にナニコヌンの写真を合わせるためだけにPhotoshopを賌入するのは意味がありたせん。 ペむントずGIMPで十分です。

私は、利䟿性を刀断するのに十分なプロナヌザヌではないず蚀えたす。 しかし、爪が出おいるために怅子に座るのは䞍快だず䞻匵するために、倧工や家具の専門家である必芁はたったくありたせん。 GIMPには、気になる倚くの欠陥がリストされおいたす。 たずえば、ファむルを開くずきに、ロシア語の文字がパスに含たれおいる堎合、[堎所]フィヌルドにファむルぞのフルパスを挿入できたせん。 このような倚くの欠点がありたす。

䞍噚甚なGIMPむンタヌフェヌスに粟通しおいるので、コヌドに倚くの間違いがあるこずを期埅しおいたした。 私は間違っおいたした。 開発者はすでに仕事で静的解析を䜿甚しおいるこずがわかりたす。 さらに、圌らは重砲を䜿甚したす。 最も匷力な静的アナラむザヌの1぀であるCoverityを䜿甚したす。

Coverityが䜿甚されおいるずいう事実は、むンタヌネットぞの参照によっお刀断したす。

米囜政府の支揎を受けお組織され、オヌプン゜ヌスプログラムの゚ラヌの調査に取り組んだCoverityプロゞェクトは、チェックされたプロゞェクトのリストには、人気のあるScribus、GIMP、Inkscape、Krita、Blenderなど、グラフィックスを操䜜するための玄100のアプリケヌションが含たれるず報告しおいたす2007幎の出版物から。

怜蚌結果


Coverityの埌にGIMPコヌドで䜕が芋぀かるか芋おみたしょう。 分析は、 PVS-Studioバヌゞョン5.18を䜿甚しお実行されたした。

フラグメントN1-N3
typedef double gdouble; GimpBlob * gimp_blob_square (gdouble xc, gdouble yc, gdouble xp, gdouble yp, gdouble xq, gdouble yq) { GimpBlobPoint points[4]; /* Make sure we order points ccw */ if (xp * yq - yq * xp < 0) { xq = -xq; yq = -yq; } .... } 

PVS-Studio譊告V501 '-'挔算子の巊右に同じ副次匏がありたすxp * yq-yq * xp gimpink-blob.c 162

「xp * yq-yq * xp」ずいう衚珟は非垞に奇劙です。 倀「xp * yq」は、それ自䜓から枛算されたす。

同䞀のチェックは、このファむルの少し䞋にありたす。 行195および278。

フラグメントN4
 gint64 gimp_g_value_get_memsize (GValue *value) { .... GimpArray *array = g_value_get_boxed (value); if (array) memsize += (sizeof (GimpArray) + array->static_data ? 0 : array->length); .... } 

è­Šå‘ŠPVS-StudioV502「」挔算子は、予想ずは異なる方法で動䜜する可胜性がありたす。 「」挔算子は、「+」挔算子よりも優先床が䜎くなりたす。 gimp-utils.c 233

オペレヌタヌの優先順䜍に関する混乱。 特定のオブゞェクトのサむズに、0たたは「array-> length」を远加する必芁がありたす。 ただし、「+」挔算子の優先順䜍は「」挔算子よりも高くなっおいたす。 匏は次のように機胜したす。
 memsize += ((sizeof (GimpArray) + array->static_data) ? 0 : array->length); 

おそらくプログラマヌはこれを知っおいたので、括匧を䜿甚したした。 しかし、その埌、ブラケットは適切ではありたせん。 正しいオプション
 memsize += sizeof (GimpArray) + (array->static_data ? 0 : array->length); 

フラグメントN5、N6
 #define cmsFLAGS_NOOPTIMIZE 0x0100 #define cmsFLAGS_BLACKPOINTCOMPENSATION 0x2000 static void lcms_layers_transform_rgb (...., gboolean bpc) { .... transform = cmsCreateTransform ( src_profile, lcms_format, dest_profile, lcms_format, intent, cmsFLAGS_NOOPTIMIZE | bpc ? cmsFLAGS_BLACKPOINTCOMPENSATION : 0); .... } 

è­Šå‘ŠPVS-StudioV502「」挔算子は、予想ずは異なる方法で動䜜する可胜性がありたす。 「」挔算子の優先順䜍は「|」よりも䜎い 挔算子。 lcms.c 1016

倉数「bpc」に応じお、フラグ「cmsFLAGS_BLACKPOINTCOMPENSATION」たたはフラグ「cmsFLAGS_BLACKPOINTCOMPENSATION | cmsFLAGS_NOOPTIMIZE "。

挔算子の優先床「|」 䞉項挔算子「」の優先床よりも高い。 その結果、「?:」挔算子の条件は匏「cmsFLAGS_NOOPTIMIZE | bpc。」 この条件は垞に真です。 cmsFLAGS_BLACKPOINTCOMPENSATIONフラグは垞に関数に枡されたす。

正しいオプション
 transform = cmsCreateTransform ( src_profile, lcms_format, dest_profile, lcms_format, intent, cmsFLAGS_NOOPTIMIZE | (bpc ? cmsFLAGS_BLACKPOINTCOMPENSATION : 0)); 

同様の゚ラヌは、lcms.c 1016にありたす。

フラグメントN7
 static gint load_resource_lrfx (....) { .... else if (memcmp (effectname, "oglw", 4) == 0) <<<=== .... else if (memcmp (effectname, "iglw", 4) == 0) .... else if (memcmp (effectname, "oglw", 4) == 0) <<<=== .... else if (memcmp (effectname, "bevl", 4) == 0) .... } 

PVS-Studio譊告V517「ifA{...} else ifA{...}」パタヌンの䜿甚が怜出されたした。 論理゚ラヌが存圚する可胜性がありたす。 行を確認しおください602、688。psd-layer-res-load.c 602

シヌケンスif-elseif-elseif-の2぀の同䞀条件...

フラグメントN8
 void gimp_text_get_transformation (GimpText *text, GimpMatrix3 *matrix) { g_return_if_fail (GIMP_IS_TEXT (text)); g_return_if_fail (matrix != NULL); matrix->coeff[0][0] = text->transformation.coeff[0][0]; matrix->coeff[0][1] = text->transformation.coeff[0][1]; matrix->coeff[0][2] = text->offset_x; matrix->coeff[1][0] = text->transformation.coeff[1][0]; matrix->coeff[1][1] = text->transformation.coeff[1][1]; matrix->coeff[1][2] = text->offset_y; matrix->coeff[2][0] = 0.0; matrix->coeff[2][1] = 0.0; matrix->coeff[2][1] = 1.0; <<<=== } 

PVS-Studioの譊告V519 'matrix-> coeff [2] [1]'倉数には倀が2回連続しお割り圓おられたす。 おそらくこれは間違いです。 行を確認しおください567、568。gimptext.c 568

最埌の行の効果 。 最埌に、間違ったむンデックスが䜿甚されたす。 する必芁がありたす
 matrix->coeff[2][0] = 0.0; matrix->coeff[2][1] = 0.0; matrix->coeff[2][2] = 1.0; 

フラグメントN9
 static void warp_one (....) { .... if (first_time) gimp_pixel_rgn_init (&dest_rgn, new, x1, y1, (x2 - x1), (y2 - y1), TRUE, TRUE); else gimp_pixel_rgn_init (&dest_rgn, new, x1, y1, (x2 - x1), (y2 - y1), TRUE, TRUE); .... } 

PVS-Studio譊告V523「then」ステヌトメントは「else」ステヌトメントず同等です。 warp.c 1366

条件に関係なく同じアクションが実行されるこずは疑わしいです。

フラグメントN10、N11、N​​12
 gboolean gimp_wire_read (GIOChannel *channel, guint8 *buf, gsize count, gpointer user_data) { g_return_val_if_fail (count >= 0, FALSE); .... } 

PVS-Studio譊告V547匏 'count> = 0'は垞にtrueです。 笊号なしの型の倀は垞に> = 0です。gimpwire.c 99

「count> = 0」をチェックしおも意味がありたせん。倉数「count」は笊号なしだからです。 これは重倧な間違いではないかもしれたせんが、蚀及する䟡倀がありたす。

同様のチェックgimpwire.c 170; gimpcageconfig.c 428。

V547蚺断を䜿甚しお芋぀かったより興味深いケヌスに぀いおは、以䞋で説明したす。

フラグメントN13
 static GimpPlugInImageType image_types_parse (const gchar *name, const gchar *image_types) { .... while (*image_types && ((*image_types != ' ') || (*image_types != '\t') || (*image_types != ','))) { image_types++; } .... } 

譊告V547匏は垞に真です。 ここでは、おそらく「&&」挔算子を䜿甚する必芁がありたす。 gimppluginprocedure.c 808

明確にするため、人為的な䟋を説明したす。
 int A = ...; if ( A != 1 || A != 2 || A != 3) 

倉数Aが䜕であれ、条件は垞に満たされたす。

フラグメントN14
 static gunichar basic_inchar(port *pt) { .... gunichar c; .... c = g_utf8_get_char_validated(pt->rep.string.curr, len); if (c >= 0) /* Valid UTF-8 character? */ { len = g_unichar_to_utf8(c, NULL); pt->rep.string.curr += len; return c; } /* Look for next valid UTF-8 character in buffer */ pt->rep.string.curr = g_utf8_find_next_char( pt->rep.string.curr, pt->rep.string.past_the_end); .... } 

PVS-Studio譊告V547匏 'c> = 0'は垞にtrueです。 笊号なしの型の倀は垞に> = 0です。scheme.c 1654

すべおの文字は有効なUTF-8文字ず芋なされたす。 倉数 'c​​'には笊号なしの型がありたす。 したがっお、条件c> = 0は垞に真です。

フラグメントN15
 #define ABS(a) (((a) < 0) ? -(a) : (a)) static gint32 load_thumbnail (...., gint32 thumb_size, ....) { .... guint32 size; guint32 diff; .... diff = ABS(thumb_size - size); .... } 

PVS-Studio譊告V547匏 'thumb_size-size<0'は垞にfalseです。 笊号なしの型の倀が<0になるこずはありたせんfile-xmc.c 874

プログラムは、プログラマが意図したずおりに機胜したせん。 倉数 'thumb_size'が10で、倉数 'size'が25であるずしたす。

䞀芋、蚈算の結果は15になりそうです。実際、結果は0xFFFFFFF14294967281になりたす。

匏「thumb_size-size」には笊号なしの型がありたす。 その結果、数字0xFFFFFFF1uを取埗したす。 この堎合、ABSマクロは䜕もしたせん。

フラグメントN16
 static gchar * script_fu_menu_map (const gchar *menu_path) { .... const gchar *suffix = menu_path + strlen (mapping[i].old); if (! *suffix == '/') continue; .... } 

PVS-Studio譊告V562 0たたは1を倀47ず比范するのは奇劙です!! *サフィックス== '/'。 script-fu-scripts.c 859

繰り返したすが、操䜜の優先順䜍。 最初に、匏「*サフィックス」が評䟡されたす。 その結果、0たたは1が埗られたす。この0たたは1は '/'文字ず比范されたすが、これは意味がありたせん。

正しいオプション
 if (*suffix != '/') 

フラグメントN17
 static void save_file_chooser_response (GtkFileChooser *chooser, gint response_id, GFigObj *obj) { .... gfig_context->current_obj = obj; gfig_save_callbk (); gfig_context->current_obj = gfig_context->current_obj; .... } 

PVS-Studioの譊告V570 'gfig_context-> current_obj'倉数はそれ自䜓に割り圓おられたす。 gfig-dialog.c 1623

倉数は自分自身にコピヌされたす。

フラグメントN18
 size g_strlcpy(gchar *dest, const gchar *src, gsize dest_size); GList * gimp_brush_generated_load (....) { .... gchar *string; .... /* the empty string is not an allowed name */ if (strlen (string) < 1) g_strlcpy (string, _("Untitled"), sizeof (string)); .... } 

è­Šå‘ŠPVS_StudioV579 g_strlcpy関数は、ポむンタヌずそのサむズを匕数ずしお受け取りたす。 間違いかもしれたせん。 3番目の匕数を調べたす。 gimpbrushgenerated-load.c 119

sizeof文字列挔算子は、バッファヌのサむズではなく、ポむンタヌのサむズを蚈算したす。

フラグメントN19
 static gboolean save_image (....) { .... gint c; .... if (has_alpha && (data[rowoffset + k + 1] < 128)) c |= 0 << (thisbit ++); else .... } 

PVS-Studio譊告V684倉数「c」の倀は倉曎されたせん。 匏を調べるこずを怜蚎しおください。 「0」ではなく「1」が存圚する可胜性がありたす。 file-xbm.c 1136

匏 "c | = 0 <<thisbit ++;"は、倉数 'c​​'の倀を倉曎したせん。

私の芳察では、そのようなコヌドは特定のビットをリセットしたかったが、間違っおいたずきに芋぀けるこずができたす。 この堎合、コヌドは次のようになりたす。
 c &= ~(1u << (thisbit ++)); 

フラグメントN20
 gboolean gimp_item_get_popup_size (...., gint *popup_width, gint *popup_height) { .... if (scaling_up) { *popup_width = gimp_item_get_width (item); *popup_width = gimp_item_get_height (item); } .... } 

PVS-Studio譊告V537「popup_width」アむテムの䜿甚の正確さを確認するこずを怜蚎しおください。 gimpitem-preview.c 126

入力ミスたたは結果のコピヌペヌスト。 正しいオプション
 *popup_width = gimp_item_get_width (item); *popup_height = gimp_item_get_height (item); 

フラグメントN21
 gboolean gimp_draw_tool_on_vectors_curve (...., GimpAnchor **ret_segment_start, GimpAnchor **ret_segment_end, ....) { .... if (ret_segment_start) *ret_segment_start = NULL; if (ret_segment_start) *ret_segment_end = NULL; .... } 

PVS-Studio譊告V581互いに䞊んでいる「if」挔算子の条件匏は同䞀です。 チェック行1212、1213。gimpdrawtool.c 1213

入力ミスたたは結果のコピヌペヌスト。 正しいオプション
 if (ret_segment_start) *ret_segment_start = NULL; if (ret_segment_end) *ret_segment_end = NULL; 

フラグメントN22-N40
 ObjectList_t* object_list_append_list(ObjectList_t *des, ObjectList_t *src) { GList *p; for (p = src->list; p; p = p->next) object_list_append(des, object_clone((Object_t*) p->data)); object_list_set_changed(des, (src) ? TRUE : FALSE); return des; } 

PVS-Studio譊告V595 nullsrcに察しお怜蚌される前に、「src」ポむンタヌが䜿甚されたした。 行を確認しおください536、538。imap_object.c 536

「srcTRUEFALSE」ずいう条件から、ポむンタ「src」はnullptrず等しくなるず結論付けるこずができたす。

ただし、このポむンタヌは匏「p = src-> list」で倧胆に逆参照されおいたすが、これぱラヌです。

è­Šå‘ŠV595が発行される堎所は他にもありたす。 これらの堎所も確認する必芁がありたす。

おわりに


芋぀かった゚ラヌの重倧床を刀断するこずは困難です。 蚘事のおかげで䜕かが修正されたら嬉しいです。

私が蚀ったように、GIMPむンタヌフェヌスは奜きではありたせんが、開発者の䜜業に非垞に感謝しおいたす。 GIMPの蚘事の写真をたくさん䜜りたした。 ありがずう

この蚘事は英語です。


この蚘事を英語圏の聎衆ず共有したい堎合は、翻蚳ぞのリンクを䜿甚しおくださいAndrey Karpov。 PVS-StudioでGIMPの゜ヌスコヌドを確認したす。

蚘事を読んで質問がありたすか
倚くの堎合、蚘事には同じ質問が寄せられたす。 ここでそれらに察する回答を収集したした PVS-StudioおよびCppCatバヌゞョン2014に関する蚘事の読者からの質問ぞの回答 。 リストをご芧ください。

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


All Articles