لقد مضى ثلاثة أشهر على انتهاء 2018. بالنسبة للكثيرين ، طار بشكل غير محسوس تقريبًا ، لكن بالنسبة لنا ، مطوري PVS-Studio ، اتضح أنه مشبع جدًا. لقد عملنا بجد ، قاتلنا بلا كلل من أجل تقدم التحليل الثابت للجماهير وبحثنا عن أخطاء جديدة في مشاريع مفتوحة المصدر مكتوبة بلغات C و C ++ و C # و Java. العشرة الأكثر إثارة للاهتمام منهم جمعناها لك في هذه المقالة!
بحثنا عن أماكن مثيرة للاهتمام باستخدام محلل الكود الثابت
PVS-Studio . يمكنه اكتشاف الأخطاء ونقاط الضعف المحتملة في التعليمات البرمجية المكتوبة باللغات المذكورة أعلاه.
إذا كنت مهتمًا بالبحث عن الأخطاء بنفسك ، فيمكنك دائمًا تنزيل أداة التحليل الخاصة بنا وتجربتها. نحن نقدم
نسخة مجانية من محلل للطلاب والمبرمجين المتحمسين ،
ورخصة مجانية لمطوري المشاريع مفتوحة المصدر ، وكذلك
نسخة تجريبية للجميع. من يدري ، ربما بحلول العام المقبل يمكنك أن تصنع أفضل 10 لديك؟ :)
ملاحظة: أقترح أن يتحقق القارئ من نفسه ، وقبل النظر في تحذير المحلل ، حاول تحديد الحالات الشاذة بنفسه. كم من الأخطاء يمكن أن تجد؟
المركز العاشر
المصدر:
ومرة أخرى إلى الفضاء: كيف زار Stellarium وحيد القرنتم اكتشاف هذا الخطأ أثناء التحقق من القبة السماوية الافتراضية لـ Stellarium.
مقتطف الشفرة أعلاه ، على الرغم من صغر حجمه ، محفوف بخطأ صعب إلى حد ما:
Plane::Plane(Vec3f &v1, Vec3f &v2, Vec3f &v3) : distance(0.0f), sDistance(0.0f) { Plane(v1, v2, v3, SPolygon::CCW); }
هل وجدت؟
تحذير PVS-Studio: V603 تم إنشاء الكائن ولكن لا يتم استخدامه. إذا كنت ترغب في استدعاء المنشئ ، فيجب استخدام "هذا-> Plane :: Plane (....)". Plane.cpp 29
أراد مؤلف التعليمات البرمجية تهيئة جزء من حقول الكائن باستخدام مُنشئ آخر متداخل في الحقل الرئيسي. صحيح ، بدلاً من ذلك ، تمكن فقط من إنشاء كائن مؤقت يتم تدميره عند مغادرة منطقة الرؤية الخاصة به. وبالتالي ، ستبقى العديد من حقول الكائن غير مهيأة.
بدلاً من استدعاء مُنشئ متداخلة ، يجب عليك استخدام مُنشئ التفويض المقدمة في C ++ 11. على سبيل المثال ، يمكنك القيام بذلك:
Plane::Plane(Vec3f& v1, Vec3f& v2, Vec3f& v3) : Plane(v1, v2, v3, SPolygon::CCW) { distance = 0.0f; sDistance = 0.0f; }
ثم سيتم تهيئة جميع الحقول المطلوبة بشكل صحيح. أليس هذا رائعا؟
المركز التاسع
المصدر:
بيرل 5: كيفية إخفاء أخطاء الماكروفي المكان التاسع ، يتكبر ماكرو من كود مصدر بيرل 5.
جمع الأخطاء لكتابة المقال ، واجه زميلي سفياتوسلاف تحذيرًا أصدره المحلل بشأن استخدام ماكرو. ومن هنا:
PP(pp_match) { .... MgBYTEPOS_set(mg, TARG, truebase, RXp_OFFS(prog)[0].end); .... }
لمعرفة ما كان الأمر ، حفر Svyatoslav أعمق. لقد فتح تعريف الماكرو ، ورأى أنه يحتوي على عدة وحدات ماكرو متداخلة ، بعضها يحتوي أيضًا على وحدات ماكرو متداخلة. كان من الصعب للغاية معرفة أنه كان علي استخدام ملف مسبق المعالجة. ولكن ، للأسف ، هذا لم يساعد. بدلاً من السطر السابق من التعليمات البرمجية ، اكتشف Svyatoslav هذا:
(((targ)->sv_flags & 0x00000400) && (!((targ)->sv_flags & 0x00200000) || S_sv_only_taint_gmagic(targ)) ? (mg)->mg_len = ((prog->offs)[0].end), (mg)->mg_flags |= 0x40 : ((mg)->mg_len = (((targ)->sv_flags & 0x20000000) && !__builtin_expect(((((PL_curcop)->cop_hints + 0) & 0x00000008) ? (_Bool)1 :(_Bool)0),(0))) ? (ssize_t)Perl_utf8_length( (U8 *)(truebase), (U8 *)(truebase)+((prog->offs)[0].end)) : (ssize_t)((prog->offs)[0].end), (mg)->mg_flags &= ~0x40));
تحذير PVS-Studio: V502 ربما يعمل المشغل '؟: بطريقة مختلفة عما كان متوقعًا. لدى المشغل "؟:" أولوية أقل من المشغل "&&". pp_hot.c 3036
أعتقد أنه سيكون من الصعب العثور على مثل هذا الخطأ في عيني. بصراحة ، تأملنا في هذا الرمز لفترة طويلة وتوصلنا إلى استنتاج مفاده أنه في الواقع لا يوجد خطأ هنا. ولكن على أي حال ، هذا مثال مسلح إلى حد ما للرمز غير قابل للقراءة.
يقال إن وحدات الماكرو شريرة. بالطبع ، هناك أوقات لا يمكن الاستغناء عنها ، لكن إذا استطعت استبدال الماكرو بوظيفة ، فعليك بالتأكيد القيام بذلك.
وحدات الماكرو المتداخلة محفوفة بشكل خاص. ليس فقط لأنها صعبة الفهم ، ولكن أيضًا لأنها يمكن أن تعطي نتائج غير متوقعة. إذا ارتكب مؤلف الماكرو خطأً في مثل هذا الماكرو ، فسيكون العثور عليه أكثر صعوبة من العثور عليه في دالة.
المركز الثامن
المصدر:
الكروم: أخطاء أخرىتم أخذ المثال التالي من سلسلة من المقالات حول تحليل مشروع Chromium. غطت نفسها في مكتبة WebRTC.
std::vector<SdpVideoFormat> StereoDecoderFactory::GetSupportedFormats() const { std::vector<SdpVideoFormat> formats = ....; for (const auto& format : formats) { if (cricket::CodecNamesEq(....)) { .... formats.push_back(stereo_format); } } return formats; }
PVS-Studio Warning: V789 CWE-672 Iterators للحاوية "التنسيقات" ، المستخدمة في النطاق القائم على الحلقة ، تصبح غير صالحة عند استدعاء وظيفة "push_back". stereocodecfactory.cc 89
الخطأ هو أن يتغير حجم متجه
التنسيقات داخل الحلقة المستندة إلى النطاق. تعتمد الحلقات المستندة إلى المدى على التكرارات ، لذلك يمكن أن يؤدي تغيير حجم الحاوية داخل هذه الحلقات إلى إبطال هذه التكرارات.
سيستمر هذا الخطأ إذا قمت بإعادة كتابة الحلقة باستخدام التكرارات الصريحة. لذلك ، من أجل الوضوح ، يمكنك إحضار هذا الرمز:
for (auto format = begin(formats), __end = end(formats); format != __end; ++format) { if (cricket::CodecNamesEq(....)) { .... formats.push_back(stereo_format); } }
على سبيل المثال ، عند استخدام طريقة
push_back ، قد يتم تحرير متجه - ثم يشير التكرار إلى منطقة ذاكرة غير صالحة.
لتجنب مثل هذه الأخطاء ، يجب عليك الالتزام بالقاعدة: لا تقم أبدًا بتغيير حجم الحاوية داخل الحلقة ، وترتبط ظروفها بهذه الحاوية. ينطبق هذا على الحلقات المستندة إلى النطاق والحلقات باستخدام التكرارات. يمكنك أن تقرأ عن العمليات التي يمكن أن تؤدي إلى إبطال التكرارات في
المناقشات على StackOverflow.
المركز السابع
المصدر:
جودو: الاستخدام المنتظم لمحللات الكود الثابتالمثال الأول من صناعة ألعاب الفيديو هو مقتطف من الكود الذي اكتشفناه في محرك ألعاب Godot. قد تضطر إلى التعرق لاكتشاف الخطأ بعينيك ، لكنني متأكد من أن القراء المتطورين يمكنهم التعامل معه:
void AnimationNodeBlendSpace1D::add_blend_point( const Ref<AnimationRootNode> &p_node, float p_position, int p_at_index) { ERR_FAIL_COND(blend_points_used >= MAX_BLEND_POINTS); ERR_FAIL_COND(p_node.is_null()); ERR_FAIL_COND(p_at_index < -1 || p_at_index > blend_points_used); if (p_at_index == -1 || p_at_index == blend_points_used) { p_at_index = blend_points_used; } else { for (int i = blend_points_used - 1; i > p_at_index; i++) { blend_points[i] = blend_points[i - 1]; } } .... }
تحذير PVS-Studio: V621 CWE-835 خذ بعين الاعتبار فحص المشغل 'for'. من المحتمل أن يتم تنفيذ الحلقة بشكل غير صحيح أو لن يتم تنفيذها على الإطلاق. animation_blend_space_1d.cpp 113
النظر في حالة الدورة بمزيد من التفصيل. تتم تهيئة متغير العداد بالقيمة
blend_points_used - 1 . في الوقت نفسه ، بناءً على
الاختيارين السابقين (في
ERR_FAIL_COND وفي
حالة if ) ، يصبح من الواضح أنه في الوقت الذي يتم فيه تنفيذ الحلقة ، سيكون
blend_points_used دائمًا أكبر من
p_at_index . وبالتالي ، إما أن تكون حالة الحلقة صحيحة دائمًا ، أو لن يتم تنفيذ الحلقة مطلقًا.
إذا كانت
blend_points_used هي 1 == p_at_index ، فلن يتم تنفيذ الحلقة.
في جميع الحالات الأخرى ، سيكون الاختيار
i> p_at_index صحيحًا دائمًا ، لأن العداد
i يزيد عند كل تكرار للحلقة.
قد يبدو أن الدورة ستستمر إلى الأبد ، لكنها ليست كذلك.
أولاً ، سيكون هناك تجاوز عدد صحيح للمتغير
i ، وهو سلوك غير محدد. لذلك ، الاعتماد على هذا لا يستحق كل هذا العناء.
إذا
كنت من النوع
غير الموقّع int ، فبعد أن يصل العداد إلى الحد الأقصى للقيمة الممكنة ، يحولها مشغل
i ++ إلى
0 . يتم تعريف هذا السلوك بواسطة المعيار ويسمى "التفاف غير موقّع." ومع ذلك ، يجب أن تدرك أن استخدام مثل هذه الآلية
ليست فكرة جيدة أيضًا.
كان هذا أولاً ، لكن لا يزال هناك ثانياً! الحقيقة هي أنه لن يصل حتى إلى عدد صحيح صحيح. حيث قبل مجموعة يذهب إلى الخارج. هذا يعني أنه سيتم إجراء محاولة للوصول إلى منطقة الذاكرة خارج الكتلة المخصصة للصفيف. وهذا ، أيضًا ، سلوك غامض. مثال كلاسيكي :)
لتسهيل تجنب مثل هذه الأخطاء ، لا يمكنني تقديم سوى بضع توصيات:
- اكتب رمزًا أبسط وأكثر سهولة
- قم بمراجعة الكود بشكل أكثر شمولية واكتب المزيد من الاختبارات للرمز المكتوب حديثًا
- استخدام محللات ثابتة ؛)
المركز السادس
المصدر:
الأمازون Lumberyard: صرخة الروحمثال آخر من صناعة gamedev ، أي من الكود المصدري لمحرك Amazon Lumberyard AAA.
void TranslateVariableNameByOperandType(....) {
تحذير PVS-Studio: V523 عبارة "then" مكافئة لبيان "else". toglsloperand.c 700
يجري تطوير Amazon Lumberyard كمحرك متعدد المنصات. لذلك ، يحاول المطورون دعم أكبر عدد ممكن من المترجمين. ركض مبرمج Igor في برنامج التحويل البرمجي Qualcomm ، كما أخبرنا بالتعليقات.
ليس معروفًا ما إذا كان إيجور قادرًا على إكمال مهمته والتعامل مع الشيكات "المصحوبة بجنون العظمة" للمترجم ، لكنه ترك وراءه رمزًا غريبًا للغاية. من الغريب في ذلك أن كلا من الفروع
آنذاك وغيره من
جملة if تحتوي على كود متطابق تمامًا. على الأرجح ، حدث مثل هذا الخطأ نتيجة لنسخ نسخ لصق.
أنا لا أعرف حتى ما يمكن النصح به هنا. لذلك ، أتمنى لمطوري Amazon Lumberyard النجاح في إصلاح الأخطاء ، ونتمنى لك التوفيق للمبرمج إيغور!
المركز الخامس
المصدر:
مرة أخرى ، تبين أن محلل PVS-Studio كان أكثر انتباهاً من أي شخصحدث قصة مثيرة مع المثال التالي. كان زميلي أندريه كاربوف يعد مقالًا عن الاختبار التالي لإطار عمل كيو تي. أثناء كتابة الأخطاء الجديرة بالملاحظة ، واجه تحذير محلل ، اعتبره خطأ. فيما يلي مقتطف الشفرة والتحذير ذي الصلة:
QWindowsCursor::CursorState QWindowsCursor::cursorState() { enum { cursorShowing = 0x1, cursorSuppressed = 0x2 }; CURSORINFO cursorInfo; cursorInfo.cbSize = sizeof(CURSORINFO); if (GetCursorInfo(&cursorInfo)) { if (cursorInfo.flags & CursorShowing)
تحذير PVS-Studio: V616 CWE-480 يتم استخدام "CursorShowing" المسمى بالقيمة 0 في عملية bitwise. qwindowscursor.cpp 669
هذا هو ، أقسم PVS-Studio في مكان ، ومن الواضح أنه لم يكن هناك خطأ! لا يمكن أن يكون ثابت
CursorShowing يساوي
0 ، لأن حرفيًا سطرين فوقه يتم تهيئة إلى
1 .
نظرًا لاستخدام إصدار غير مستقر من المحلل للتحقق ، شك أندريه في صحة التحذير. لقد فحص بعناية هذا القسم من الكود عدة مرات ، وما زال لم يجد خطأ. ونتيجة لذلك ، كتب هذا الخطأ الإيجابي إلى bugtracker حتى يتمكن الزملاء الآخرون من تصحيح الموقف.
وفقط مع تحليل مفصل أصبح من الواضح أن PVS-Studio كان أكثر انتباهاً من شخص.
يتم تعيين القيمة
0x1 إلى
المؤشر الثابت المسمى ،
وتتضمن العملية الثابتة
للبت "و" الثابت المسمى
CursorShowing . هذه ثوابت مختلفة تمامًا ، لأن الأول يبدأ بحرف صغير ، والثاني بحرف كبير.
يتم ترجمة التعليمات البرمجية بنجاح ، لأن الفئة
QWindowsCursor تحتوي بالفعل على ثابت بهذا الاسم. هنا هو تعريفها:
class QWindowsCursor : public QPlatformCursor { public: enum CursorState { CursorShowing, CursorHidden, CursorSuppressed }; .... }
إذا لم تقم بتعيين ثابت التعداد المحدد بشكل صريح ، فسيتم تهيئته بشكل افتراضي. نظرًا لأن
CursorShowing هو العنصر الأول في التعداد ، فسيتم تعيينه على
0 .
من أجل منع مثل هذه الأخطاء ، يجب عدم إعطاء أسماء مشابهة للكيانات. يجب عليك اتباع هذه القاعدة بعناية خاصة إذا كانت هذه الكيانات من نفس النوع أو يمكن ضمها إلى بعضها البعض. في الواقع ، في مثل هذه الحالات ، سيكون من المستحيل تقريبًا اكتشاف خطأ عن طريق العين ، وسيتم تجميع الشفرة الخاطئة بنجاح والعيش بسعادة داخل مشروعك.
المركز الرابع
المصدر:
نطلق النار في القدم ونعالج بيانات الإدخالنحن نقترب من أفضل ثلاثة متسابقين ، والخطأ من مشروع FreeSWITCH هو التالي بدوره.
static const char *basic_gets(int *cnt) { .... int c = getchar(); if (c < 0) { if (fgets(command_buf, sizeof(command_buf) - 1, stdin) != command_buf) { break; } command_buf[strlen(command_buf)-1] = '\0'; break; } .... }
تحذير PVS-Studio: V1010 CWE-20 يتم استخدام البيانات الملوثة غير المحددة في الفهرس: 'strlen (command_buf)'.
يحذر المحلل من أن تعبير
strlen (command_buf) - 1 يستخدم بيانات لم يتم التحقق منها.
وبالفعل : إذا تبين أن
command_buf فارغة من وجهة نظر سلسلة لغة C (تحتوي على حرف واحد - '\ 0') ،
فستُرجع strlen (command_buf) 0 . في هذه الحالة ، سيتم
استدعاء command_buf [-1] ، والذي يمثل سلوكًا غير محدد. في ورطة!
لا يكمن
السبب وراء هذا الخطأ في
سبب حدوثه ، بل في
كيفية حدوثه. هذا الخطأ هو أحد الأمثلة الممتعة التي يمكنك "لمسها" بنفسك ، إعادة إنتاج. يمكنك بدء FreeSwitch ، وتنفيذ بعض الإجراءات التي ستؤدي إلى تنفيذ قسم الكود أعلاه ، وتمرير البرنامج سطر فارغ للإدخال.
نتيجة لذلك ، بنقرة من الرسغ ، يتحول برنامج العمل (لا ، ليس
السراويل القصيرة ) إلى برنامج غير عامل! يمكن العثور على تفاصيل حول كيفية إعادة إنتاج هذا الخطأ في المقال المصدر على الرابط أعلاه ، ولكن الآن سأقدم نتيجة واضحة:
تذكر أن الإدخال يمكن أن يكون أي شيء ، ويجب عليك التحقق منه دائمًا. عندها لن يقسم المحلل ، وسيكون البرنامج أكثر موثوقية.
حان الوقت الآن للتعامل مع الفائزين: ننتقل إلى النهائيات!
المركز الثالث
المصدر:
NCBI Genome Workbench: البحوث المهددة بالانقراضيتم فتح الفائزين الثلاثة برمز من مشروع NCBI Genome Workbench - مجموعة من الأدوات لدراسة وتحليل البيانات الجينية. على الرغم من أنه ليس من الضروري أن تكون سوبرمان معدل وراثيا لإيجاد خطأ هنا ، إلا أن قلة قليلة منهم تدرك هذا الاحتمال.
void tds_answer_challenge(....) { .... if (ntlm_v == 1) { .... memset(hash, 0, sizeof(hash)); memset(passwd_buf, 0, sizeof(passwd_buf)); ... } else { .... } }
تحذيرات PVS-Studio:- V597 قد يحذف المترجم استدعاء دالة "memset" ، والذي يُستخدم لمسح المخزن المؤقت "التجزئة". يجب استخدام الدالة memset_s () لمسح البيانات الخاصة. challenge.c 365
- V597 يمكن للمترجم حذف استدعاء دالة "memset" ، والذي يستخدم لمسح 'passwd_buf' المخزن المؤقت. يجب استخدام الدالة memset_s () لمسح البيانات الخاصة. challenge.c 366
تمكنت من العثور على خطأ؟ إذا كان الأمر كذلك ، فأنت - أحسنت! .. حسناً ، أو ما زلت سوبرمان معدل وراثياً.
الحقيقة هي أن المجمعين المحسنين الحديثين يمكنهم فعل الكثير لجعل البرنامج المجمّع يعمل بشكل أسرع. على وجه الخصوص ، يستطيع
المترجمون تتبع أن المخزن المؤقت الذي تم تمريره إلى
memset لا يستخدم في أي مكان آخر.
في هذه الحالة ، يمكنهم حذف مكالمة
memset "غير الضرورية" ، ولهم كل الحق في القيام بذلك. بعد ذلك ، يمكن أن يظل المخزن المؤقت الذي يخزن البيانات المهمة في الذاكرة لبهجة المهاجمين.
على هذه الخلفية ، يبدو التعليق الملموس "مع الأمن جيدًا أن يكون متحذلاً" أكثر تسلية. انطلاقًا من العدد القليل جدًا من التحذيرات التي تم إصدارها لهذا المشروع ، فقد حاول المطورون أن يكونوا حذرين وأن يكتبوا رمزًا آمنًا. ومع ذلك ، كما نرى ، فإن تخطي هذا الخلل الأمني بسيط للغاية. وفقًا للتعداد العام للضعف ، يصنف الخلل على أنه
CWE-14 : إزالة المترجم الشفري لمسح المخازن المؤقتة.
لمسح تنظيف الذاكرة ، استخدم الدالة
memset_s () . ليس فقط أكثر أمانًا من
memset () ، ولكن أيضًا لا يمكن "تجاهله" من قبل المترجم.
المركز الثاني
المصدر:
كيف تحولت PVS-Studio إلى المزيد من الاهتمام أكثر من ثلاثة مبرمجين ونصفتم إرسال الميدالية الفضية لهذا الجزء لنا من قبل أحد عملائنا. لقد كان متأكدًا من أن المحلل قد أحدث تحذيرات خاطئة.
تلقى يوجين الرسالة ، مسحها ضوئيًا لفترة وجيزة ، وأرسلها إلى سفياتوسلاف. نظر سفياتوسلاف بعناية في قسم الكود الذي أرسله العميل ، وفكر ، "هل يمكن للمحلل أن يكون مخطئًا بشكل صارخ؟" لذلك ، ذهب للتشاور مع أندريه. قام أيضًا بفحص الموقع وقرر: في الواقع ، يعطي المحلل إيجابيات كاذبة.
ماذا يمكنك أن تفعل ، تحتاج إلى إصلاحه. وفقط عندما بدأ سفياتوسلاف في تقديم أمثلة اصطناعية لإضفاء الطابع الرسمي على المهمة كصاحبة أخطاء ، أدرك ما كان يحدث.
كانت الأخطاء موجودة بالفعل في الكود ، لكن لم يستطع أحد المبرمجين اكتشافها. بصراحة ، لم ينجح مؤلف هذا المقال.
وهذا على الرغم من حقيقة أن المحلل أصدر بوضوح تحذيرات للأماكن الخطأ!
يمكنك أن تجد مثل هذا الخطأ ماكرة؟ اختبر نفسك من أجل اليقظة والانتباه.
تحذير PVS-Studio:- V560 جزء من التعبير الشرطي خطأ دائمًا: (ch> = 0x0FF21). decodew.cpp 525
- V560 جزء من التعبير الشرطي صحيح دائمًا: (ch <= 0x0FF3A). decodew.cpp 525
- V560 جزء من التعبير الشرطي خطأ دائمًا: (ch> = 0x0FF41). decodew.cpp 525
- V560 جزء من التعبير الشرطي صحيح دائمًا: (ch <= 0x0FF5A). decodew.cpp 525
إذا نجحت - فلن تحترمك!
يكمن الخطأ في حقيقة أن عامل النفي المنطقي (!) لا ينطبق على الحالة بأكملها ، ولكن فقط على تعبيره الفرعي الأول:
!((ch >= 0x0FF10) && (ch <= 0x0FF19))
إذا تم الوفاء بهذا الشرط ، فإن قيمة المتغير
ch تكمن في الفاصل الزمني [0x0FF10 ... 0x0FF19]. وبالتالي ، فإن المقارنات الأربعة الأخرى لم تعد منطقية: ستكون دائمًا صحيحة أو خاطئة.
لتجنب مثل هذه الأخطاء ، يجدر اتباع بعض القواعد. أولاً ، من المريح والواضح أن تتم محاذاة الشفرة مع جدول. ثانياً ، لا تفرط في تعبيرات الأقواس. على سبيل المثال ، يمكن إعادة كتابة هذا الرمز مثل هذا:
const bool isLetterOrDigit = (ch >= 0x0FF10 && ch <= 0x0FF19)
ثم ، أولاً ، يصبح عدد الأقواس أصغر كثيرًا ، وثانيًا ، يزيد احتمال "اصطياد" خطأ ارتكبته العيون.
والآن - الكرز: نحن ننتقل إلى المقام الأول!
المركز الاول
المصدر:
النظام في حالة صدمة: أخطاء مثيرة للاهتمام في الأكواد المصدرية لنظام الصدمة الأسطوريلذا ، فإن التصفيات النهائية لقمة اليوم لدينا هي خطأ من الصدمة الأسطورية للنظام! أصبحت هذه اللعبة ، التي تم إصدارها في عام 1994 ، السلف والملهم للألعاب الشهيرة مثل Dead Space و BioShock و Deus Ex.
لكن أولاً ، يجب أن أعترف بشيء. ما سأريكه الآن لا يحتوي على أي خطأ. بشكل عام ، ليست حتى مقتطف شفرة ، لكنني لم أستطع مقاومة عدم مشاركة هذا معك!
الحقيقة هي أنه في عملية تحليل الكود المصدري للعبة ، وجد زميلي فيكتوريا العديد من التعليقات المثيرة للاهتمام. هنا وهناك فجأة كانت هناك مزاح وسخرية من الملاحظات ، وحتى الآيات:
بالنسبة لقرائنا الناطقين بالروسية ، قمت بترجمة مجانية تقريبية:
هذه التعليقات تركها مطورو اللعبة في أوائل التسعينيات ... بالمناسبة ، كان دوغ تشيرش - المصمم الرئيسي لنظام System Shock - يكتب أيضًا الكود. من يدري ، ربما أي من هذه التعليقات كتبها شخصيا؟ آمل أن يكون حول الرجال في المناشف - وهذا ليس من شأنه :)استنتاج
في الختام ، أود أن أشكر زملائي على البحث عن أخطاء جديدة وكتابة مقالات عنها. شكرا يا شباب! بدونك ، لما كانت هذه المقالة مثيرة للاهتمام للغاية.أريد أيضًا أن أتحدث قليلاً عن إنجازاتنا ، لأننا لمدة عام كامل منخرطون في أكثر من مجرد البحث عن الأخطاء. قمنا أيضًا بتطوير المحلل وتحسينه ، ونتيجة لذلك خضع لتغيرات كبيرة.على سبيل المثال ، أضفنا دعمًا لعدة برامج ترجمة جديدة وقمنا بتوسيع قائمة قواعد التشخيص. كما قدمنا الدعم الأولي لمعايير MISRA C و MISRA C ++ . كان الابتكار الأكثر أهمية واستهلاكًا للوقت هو دعم لغة جديدة. نعم ، الآن يمكننا تحليل كود جافا ! وقمنا بتحديث الرمز:)أيضا أريد أن أشكر القراء. شكرا لقراءة مقالاتنا والكتابة لنا! ملاحظاتك ممتعة للغاية ومهمة بالنسبة لنا.في هذا الصدد ، انتهى أفضل 10 أخطاء من فئة C ++ لعام 2018. ما الأماكن التي أعجبك أكثر شيئ ولماذا؟ هل صادفت أمثلة مثيرة للاهتمام في عام 2018؟ أخبرنا عنها في التعليقات!حتى في المرة القادمة!
إذا كنت ترغب في مشاركة هذا المقال مع جمهور يتحدث الإنجليزية ، فالرجاء استخدام الرابط إلى الترجمة: George Gribkov. تم العثور على أفضل 10 أخطاء من مشاريع C ++ في عام 2018