مخاطر استخدام ثوابت متعددة الشخصيات

الصورة 1

أثناء تحليل الشفرة ، يقوم PVS-Studio بتحليل تدفق البيانات وتشغيل القيم المتغيرة. القيم مأخوذة من الثوابت أو مشتقة من التعبيرات الشرطية. نحن نسميها القيم الافتراضية. في الآونة الأخيرة ، قمنا بتحسينها من أجل العمل مع الثوابت متعددة الأحرف وهذا أصبح السبب في إنشاء قاعدة تشخيصية جديدة.

مقدمة


يتم تعريف التنفيذ الحرفي متعدد الأحرف ، لذلك يمكن للمترجمين المختلفين ترميزهم بطرق مختلفة. على سبيل المثال ، حددت GCC و Clang قيمة ، بناءً على ترتيب الرموز في الحرفي ، بينما تقوم MSVC بنقلها وفقًا لنوع الرمز (عادي أو هروب).

على سبيل المثال ، سيتم ترميز حرفي 'T \ x65s \ x74' بطرق مختلفة ، اعتمادًا على المترجم. كان لابد من إضافة منطق مشابه في المحلل. نتيجةً لذلك ، قمنا بإنشاء قاعدة تشخيصية جديدة V1039 لتحديد هذه القيم الحرفية في الشفرة. هذه القيم الحرفية خطيرة في المشاريع متعددة الأنظمة التي تستخدم مترجمين متعددين للبناء.

التشخيص V1039


لنلقِ نظرة على المثال. الكود أدناه ، الذي تم تجميعه بواسطة مترجمين مختلفين ، سوف يتصرف بشكل مختلف:

#include <stdio.h> void foo(int c) { if (c == 'T\x65s\x74') // <= V1039 { printf("Compiled with GCC or Clang.\n"); } else { printf("It's another compiler (for example, MSVC).\n"); } } int main(int argc, char** argv) { foo('Test'); return 0; } 

سيقوم البرنامج ، الذي تم تجميعه بواسطة مترجمين مختلفين ، بطباعة رسائل مختلفة على الشاشة.

بالنسبة لمشروع يستخدم برنامج التحويل البرمجي المحدد ، لن يكون ملحوظًا. ولكن عند النقل ، قد تحدث مشكلات ، لذلك ينبغي للمرء استبدال هذه القيم الحرفية بثوابت رقمية بسيطة ، مثل "اختبار" يجب تغييره مع 0x54657374.

لإظهار الفرق بين المترجمين ، سنقوم بكتابة أداة صغيرة تأخذ متواليات من 3 و 4 رموز ، مثل "GHIJ" و "GHI" ، وتعرض تمثيلها في الذاكرة بعد التجميع.

رمز المنفعة:

 #include <stdio.h> typedef int char_t; void PrintBytes(const char* format, char_t lit) { printf("%20s : ", format); const unsigned char *ptr = (const unsigned char*)&lit; for (int i = sizeof(lit); i--;) { printf("%c", *ptr++); } putchar('\n'); } int main(int argc, char** argv) { printf("Hex codes are: G(%02X) H(%02X) I(%02X) J(%02X)\n",'G','H','I','J'); PrintBytes("'GHIJ'", 'GHIJ'); PrintBytes("'\\x47\\x48\\x49\\x4A'", '\x47\x48\x49\x4A'); PrintBytes("'G\\x48\\x49\\x4A'", 'G\x48\x49\x4A'); PrintBytes("'GH\\x49\\x4A'", 'GH\x49\x4A'); PrintBytes("'G\\x48I\\x4A'", 'G\x48I\x4A'); PrintBytes("'GHI\\x4A'", 'GHI\x4A'); PrintBytes("'GHI'", 'GHI'); PrintBytes("'\\x47\\x48\\x49'", '\x47\x48\x49'); PrintBytes("'GH\\x49'", 'GH\x49'); PrintBytes("'\\x47H\\x49'", '\x47H\x49'); PrintBytes("'\\x47HI'", '\x47HI'); return 0; } 

إخراج الأداة المساعدة ، التي تم تجميعها بواسطة Visual C ++:

 Hex codes are: G(47) H(48) I(49) J(4A) 'GHIJ' : JIHG '\x47\x48\x49\x4A' : GHIJ 'G\x48\x49\x4A' : HGIJ 'GH\x49\x4A' : JIHG 'G\x48I\x4A' : JIHG 'GHI\x4A' : JIHG 'GHI' : IHG '\x47\x48\x49' : GHI 'GH\x49' : IHG '\x47H\x49' : HGI '\x47HI' : IHG 

ناتج الأداة المساعدة ، التي جمعتها دول مجلس التعاون الخليجي أو كلانج:

 Hex codes are: G(47) H(48) I(49) J(4A) 'GHIJ' : JIHG '\x47\x48\x49\x4A' : JIHG 'G\x48\x49\x4A' : JIHG 'GH\x49\x4A' : JIHG 'G\x48I\x4A' : JIHG 'GHI\x4A' : JIHG 'GHI' : IHG '\x47\x48\x49' : IHG 'GH\x49' : IHG '\x47H\x49' : IHG '\x47HI' : IHG 

استنتاج


تم إضافة تشخيص V1039 في محلل PVS-Studio للإصدار 7.03 ، والذي تم إصداره مؤخرًا. يمكنك تنزيل أحدث إصدار من المحلل على صفحة التنزيل .

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


All Articles