ORC هي أداة للعثور على انتهاكات قاعدة التعريف الواحدة لـ C++ في سلسلة أدوات OSX.
ORC هي مسرحية على DWARF وهي مسرحية على ELF. ORC هو اختصار. بينما يرمز O إلى ODR، في نوبة من السخرية، يمثل R و C كلمات متعددة (ربما متعارضة).
هناك العديد من المقالات حول قاعدة التعريف الواحدة (ODR)، بما في ذلك معيار C++ نفسه. جوهر القاعدة هو أنه إذا تم تعريف رمز في برنامج، فلا يُسمح بتعريفه إلا مرة واحدة. تُمنح بعض الرموز استثناءً لهذه القاعدة، ويُسمح بتعريفها عدة مرات. ومع ذلك، يجب تعريف تلك الرموز بتسلسلات رمزية متطابقة .
لاحظ أن بعض إعدادات المترجم يمكن أن تؤثر أيضًا على تسلسلات الرمز المميز - على سبيل المثال، قد يؤدي تمكين RTTI أو تعطيله إلى تغيير تعريف الرمز (في هذه الحالة، جدول vtable للفئة.)
أي رمز يكسر القاعدة المذكورة أعلاه يعد انتهاكًا لـ ODR (ODRV). في بعض الحالات، قد يلتقط الرابط تعريف الرمز المكرر ويصدر تحذيرًا أو خطأ. ومع ذلك، ينص المعيار على عدم الحاجة إلى رابط للقيام بذلك. يصفها آندي جي جيدًا:
لأسباب تتعلق بالأداء، ينص معيار C++ على أنه إذا انتهكت قاعدة التعريف الواحدة فيما يتعلق بالقوالب، فإن السلوك ببساطة غير محدد. وبما أن الرابط لا يهتم، فإن انتهاكات هذه القاعدة تكون صامتة. مصدر
من الممكن وجود ODRVs غير القالبية، وقد يكون الرابط صامتًا بشأنها أيضًا.
عادةً ما يعني ODRV أن لديك رمزًا يختلف تخطيطه الثنائي اعتمادًا على وحدة الترجمة التي قامت بإنشائه. ومع ذلك، بسبب القاعدة، عندما يواجه الرابط تعريفات متعددة، يكون له الحرية في اختيار أي منها واستخدامه كتخطيط ثنائي للرمز. عندما لا يتطابق التخطيط المختار مع التخطيط الثنائي الداخلي للرمز في وحدة الترجمة، يكون السلوك غير محدد.
في كثير من الأحيان يكون مصحح الأخطاء عديم الفائدة في هذه السيناريوهات. وسيستخدم أيضًا تعريفًا واحدًا لرمز للبرنامج بأكمله، وعندما تحاول تصحيح أخطاء ODRV، قد يمنحك مصحح الأخطاء بيانات سيئة، أو يشير إلى موقع في ملف لا يبدو صحيحًا. في النهاية، سيبدو أن مصحح الأخطاء يكذب عليك، لكنه لا يقدم أي أدلة حول المشكلة الأساسية بصمت.
مثل جميع الأخطاء، يستغرق إصلاح ODRV وقتًا، فلماذا يجب عليك إصلاح انتهاك ODR في التعليمات البرمجية التي تم اختبارها (والتي من المفترض أن تعمل)؟
ORC هي أداة تقوم بما يلي:
باستثناء وجود خطأ في الأداة، لا يقوم ORC بإنشاء نتائج إيجابية خاطئة. أي شيء تبلغ عنه هو ODRV.
في الوقت الحالي، لم تكتشف ORC جميع الانتهاكات المحتملة لقاعدة التعريف الواحد. نأمل في توسيع وتحسين ما يمكن التقاطه بمرور الوقت. وحتى ذلك الحين، يعني هذا أنه على الرغم من أن ORC يعد فحصًا قيمًا، إلا أن الفحص النظيف لا يضمن خلو البرنامج من ODRVs.
يمكن لشركة ORC العثور على:
ملاحظة حول vtables: سيكتشف ORC الأساليب الافتراضية الموجودة في فتحات مختلفة. (وهو نوع سيء من البرامج الفاسدة.) في هذه المرحلة، لن يكتشف فئة تحتوي على أساليب افتراضية تمثل "مجموعة شاملة" من ODR التي تنتهك فئة مكررة.
بالإضافة إلى مصادر ORC الرئيسية، نحاول توفير مجموعة من أمثلة التطبيقات التي تحتوي على ODRVs التي يجب على الأداة التقاطها.
تم تصميم ORC في الأصل على نظام التشغيل macOS. وبينما يتركز تنفيذه الحالي هناك، فإنه لا يجب أن يقتصر على سلسلة الأدوات هذه.
تتم إدارة ORC بواسطة cmake، ويتم إنشاؤه باستخدام اصطلاحات البناء النموذجية للمشروع المُدار بواسطة CMake:
mkdir build
cd build
cmake -GXcode ..
هناك عدد قليل من نماذج التطبيقات التي تم دمج ORC فيها لأغراض الاختبار. يمكن تحديدها عبر النافذة المنبثقة للأهداف في Xcode.
يستخدم ORC Tracy كأداة التوصيف المفضلة لديه، ويتم تمكينه افتراضيًا. لتعطيل Tracy، حدد سطر أوامر cmake كما يلي:
cmake .. -GXcode -DTRACY_ENABLE=OFF
تبعية Tracy مطلوبة حتى إذا تم تعطيل التوصيف (سيتم تجميعه خارج وقت التشغيل.) لاحظ أن هذا الخيار مخزّن مؤقتًا، لذا يجب عليك إيقاف OFF
أو ON
بشكل صريح. ستؤدي إعادة تشغيل استدعاء سطر الأوامر مع فقدان الخيار إلى استخدام قيمته السابقة.
يمكن استدعاء ORC مباشرة من سطر الأوامر، أو إدراجه في سلسلة الأدوات في خطوة الرابط. الإخراج لم يتغير. إنها ببساطة مسألة راحة في سير عملك.
يكون هذا الوضع مفيدًا إذا كان لديك أمر الرابط ووسائطه، وتريد البحث عن ODRVs منفصلة عن البنية الفعلية.
ملف التكوين (انظر أدناه)
'forward_to_linker' = false
'standalone_mode' = false
أنت بحاجة إلى وسيطات سطر الأوامر ld
من XCode. قم بالإنشاء باستخدام Xcode (إذا لم تتمكن من الارتباط، فلن يتمكن ORC من مساعدتك)، وانسخ أمر الارتباط والصقه بعد استدعاء ORC. شيء مثل:
/path/to/orc /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang++ -target ... Debug/lem_mac
(إنه سطر أوامر ضخم، مختصر هنا.)
سيقوم ORC بتنفيذ وتسجيل انتهاكات ODR إلى وحدة التحكم.
إذا كانت لديك قائمة بملفات المكتبة التي يتعين على ORC معالجتها، فيمكنه القيام بذلك أيضًا.
ملف التكوين (انظر أدناه)
'forward_to_linker' = false
'standalone_mode' = true
في هذا الوضع، ما عليك سوى تمرير قائمة ملفات المكتبة إلى ORC لمعالجتها.
ملف التكوين (انظر أدناه)
'forward_to_linker' = true
'standalone_mode' = false
لاستخدام ORC ضمن مشروع إنشاء Xcode الخاص بك، قم بتجاوز المتغيرات التالية بمسار مؤهل بالكامل إلى برامج ORC النصية:
"LIBTOOL": "/absolute/path/to/orc",
"LDTOOL": "/absolute/path/to/orc",
"ALTERNATE_LINKER": "/absolute/path/to/orc",
مع وجود هذه الإعدادات في مكانها الصحيح، يجب على Xcode استخدام ORC كأداة لكل من مرحلتي libtool
و ld
من بناء المشروع. بسبب إعداد forward_to_linker
، سيقوم ORC باستدعاء أداة الارتباط المناسبة لإنتاج ملف ثنائي. بمجرد اكتمال ذلك، سيبدأ ORC في فحصه.
من بين الإعدادات الأخرى، يمكن تكوين ORC للخروج أو التحذير فقط عند اكتشاف ODRV.
سوف يقوم ORC بالتنقل في الدليل الحالي لأعلى، بحثًا عن ملف التكوين المسمى إما:
.orc-config
، أو_orc-config
إذا تم العثور عليها، فيمكن للعديد من المفاتيح التحكم في منطق ORC. الرجاء مراجعة _orc_config
في المستودع للحصول على أمثلة. سيفضل ORC .orc-config
لذا من السهل نسخ _orc_config
الأصلي وتغيير القيم محليًا في .orc-config
.
على سبيل المثال:
error: ODRV (structure:byte_size); conflict in `object`
compilation unit: a.o:
definition location: /Volumes/src/orc/extras/struct0/src/a.cpp:3
calling_convention: pass by value; 5 (0x5)
name: object
byte_size: 4 (0x4)
compilation unit: main.o:
definition location: /Volumes/src/orc/extras/struct0/src/main.cpp:3
calling_convention: pass by value; 5 (0x5)
name: object
byte_size: 1 (0x1)
تُعرف structure:byte_size
بفئة ODRV، وهي تتضمن تفاصيل دقيقة عن نوع الانتهاك الذي يمثله هذا الخطأ. يتم بعد ذلك إخراج وحدتي التجميع المتعارضتين، بالإضافة إلى معلومات DWARF التي أدت إلى الاصطدام.
struct object { ... }
In ao:
و In main.o
هما ملفا الكائنات أو الأرشيفات غير المتطابقة. من المحتمل أن يكون السبب في ODR هو عدم مطابقة إعدادات الترجمة أو #define في تجميع هذه الأرشيفات. byte_size
هي القيمة الفعلية التي تسبب خطأ.
definition location: /Volumes/src/orc/extras/struct0/src/a.cpp:3
ما هو السطر والملف الذي تم الإعلان عن الكائن فيه. إذن السطر 3 من a.cpp
في هذا المثال.
بالنسبة لنفس الإصدار من ORC، ونفس الإدخال، سيكتب ORC دائمًا نفس الإخراج. حيث تكون كلمة "نفس" متطابقة بالبايت ولن تظهر أداة الفرق أي اختلافات.
يعد تحقيق مخرجات متسقة (وربما الحفاظ عليها) أمرًا صعبًا بشكل مدهش في تطبيق متعدد الخيوط.
يرجى أن تضع في اعتبارك أن هذا لا ينطبق على إصدارات مختلفة من ORC. من المؤكد تقريبًا أن التغييرات التي يتم إجراؤها على ORC ستؤدي إلى تغييرات في المخرجات.
ليس هناك أيضًا ضمان بأن التغيير "الصغير" في ملفات الإدخال سيضمن تغييرًا "صغيرًا" في مخرجات ORC. هذا السلوك مرغوب فيه ومن المحتمل أن يكون مجالًا للتحسين في المستقبل.
orc_test
) يتم توفير تطبيق اختبار الوحدة للتأكد من أن ORC يلتقط ما يُزعم أنه يلتقطه. يقدم orc_test
"نظام بناء" مصغرًا لإنشاء ملفات كائن من مصادر معروفة لإنتاج انتهاكات معروفة لـ ODR. ثم يقوم بمعالجة ملفات الكائنات باستخدام نفس المحرك مثل أداة سطر أوامر ORC، ويقارن النتائج بقائمة تقارير ODRV المتوقعة.
كل وحدة اختبار في البطارية منفصلة وتحتوي على:
odrv_test.toml
، ملف TOML عالي المستوى يصف معلمات الاختباربشكل عام، يجب أن يؤدي اختبار واحد إلى حدوث انتهاك واحد لـ ODR، لكن هذا قد لا يكون ممكنًا في جميع الحالات.
هذه الملفات هي ملفات مصدر C++ قياسية. يجب أن تكون كميتها وحجمها صغيرًا جدًا - فقط كبير بما يكفي للتسبب في ODRV المقصود.
odrv_test.toml
يصف ملف الإعدادات لتطبيق الاختبار ما هو المصدر (المصادر) الذي يجب تجميعه، وما هي علامات الترجمة التي يجب استخدامها للاختبار، وما هي ODRVs التي يحتاج النظام إلى مراقبتها نتيجة لربط ملف (ملفات) الكائن الذي تم إنشاؤه ) معاً.
يتم تحديد مصادر الاختبار بتوجيه [[source]]
:
[[ source ]]
path = " one.cpp "
obj = " one "
flags = [
" -Dfoo=1 "
]
يصف حقل path
المسار إلى الملف المتعلق بـ odrv_test.toml
. هذا هو الحقل الوحيد المطلوب.
يحدد الحقل obj
اسم ملف الكائن (المؤقت) الذي سيتم إنشاؤه. إذا تم حذف هذا الاسم، سيتم استخدام اسم عشوائي زائف.
يحدد حقل flags
علامات الترجمة التي سيتم استخدامها خصيصًا لوحدة الترجمة هذه. باستخدام هذا الحقل، من الممكن إعادة استخدام نفس الملف المصدر مع إشارات تجميع مختلفة للحصول على ODRV.
يتم تحديد ODRVs بتوجيه [[odrv]]
:
[[ odrv ]]
category = " subprogram:vtable_elem_location "
linkage_name = " _ZNK6object3apiEv "
يصف حقل category
النوع المحدد لانتهاك ODR الذي يجب أن يتوقع تطبيق الاختبار العثور عليه.
يصف الحقل linkage_name
الرمز المحدد الذي تسبب في ODRV. إنه غير مستخدم حاليًا، ولكن سيتم فرضه مع نضوج التطبيق الاختباري.
العلامات التالية ليست قيد الاستخدام حاليًا أو ستخضع لتغييرات كبيرة مع استمرار نضج تطبيق اختبار الوحدة.
[compile_flags]
: سلسلة من علامات الترجمة التي يجب تطبيقها على كل ملف مصدر في اختبار الوحدة.
[orc_test_flags]
: سلسلة من إعدادات وقت التشغيل لتمريرها إلى تطبيق الاختبار لهذا الاختبار.
[orc_flags]
: سلسلة من إعدادات وقت التشغيل لتمريرها إلى محرك ORC لهذا الاختبار.