Miri هي أداة للكشف عن السلوك غير المحدد لـ Rust. يمكنه تشغيل الثنائيات ومجموعات الاختبار لمشاريع الشحن واكتشاف التعليمات البرمجية غير الآمنة التي تفشل في الحفاظ على متطلبات السلامة الخاصة بها. على سبيل المثال:
unreachable_unchecked
، واستدعاء copy_nonoverlapping
مع نطاقات متداخلة، ...)bool
ليس 0 أو 1، على سبيل المثال، أو تمييز تعداد غير صالح) علاوة على ذلك، ستخبرك Miri أيضًا عن تسرب الذاكرة: عندما لا تزال هناك ذاكرة مخصصة في نهاية التنفيذ، ولا يمكن الوصول إلى تلك الذاكرة من static
عام، ستثير Miri خطأ.
يمكنك استخدام Miri لمحاكاة البرامج على أهداف أخرى، على سبيل المثال للتأكد من أن معالجة البيانات على مستوى البايت تعمل بشكل صحيح على الأنظمة ذات النهاية الصغيرة والكبيرة. انظر التفسير المتبادل أدناه.
لقد اكتشفت ميري بالفعل العديد من الأخطاء في العالم الحقيقي. إذا وجدت خطأً في Miri، سنكون ممتنين لإخبارنا بذلك وسنضيفه إلى القائمة!
افتراضيًا، يضمن Miri التنفيذ الحتمي الكامل ويعزل البرنامج عن النظام المضيف. يتم استبدال بعض واجهات برمجة التطبيقات التي عادةً ما تصل إلى المضيف، مثل تجميع الإنتروبيا لمولدات الأرقام العشوائية ومتغيرات البيئة والساعات، بتطبيقات حتمية "وهمية". قم بتعيين MIRIFLAGS="-Zmiri-disable-isolation"
للوصول إلى واجهات برمجة تطبيقات النظام الحقيقية بدلاً من ذلك. (على وجه الخصوص، فإن واجهات برمجة تطبيقات RNG للنظام "المزيفة" تجعل Miri غير مناسب لاستخدام التشفير ! لا تقم بإنشاء مفاتيح باستخدام Miri.)
بعد كل ما قيل، انتبه إلى أن Miri لا تكتشف كل انتهاك لمواصفات Rust في برنامجك، لأسباب ليس أقلها عدم وجود مثل هذه المواصفات. تستخدم ميري تقريبها الخاص لما هو سلوك غير محدد وما هو غير محدد في الصدأ. على حد علمنا، يتم اكتشاف جميع السلوكيات غير المحددة التي لديها القدرة على التأثير على صحة البرنامج بواسطة Miri (أخطاء modulo)، ولكن يجب عليك الرجوع إلى المرجع للحصول على التعريف الرسمي للسلوك غير المحدد. سيتم تحديث Miri بمترجم Rust للحماية من UB كما يفهمه المترجم الحالي، لكنه لا يقدم أي وعود بشأن الإصدارات المستقبلية من Rustc.
تحذيرات أخرى يجب على مستخدمي Miri معرفتها:
-Zrandomize-layout
لاكتشاف بعض هذه الحالات.)-Zmiri-seed
، لكن هذا لن يستكشف جميع عمليات التنفيذ المحتملة حتى الآن.--target x86_64-unknown-linux-gnu
للحصول على دعم أفضل.SeqCst
غير المسموح بها فعليًا بواسطة نموذج الذاكرة Rust، ولا يمكنها إنتاج جميع السلوكيات التي يمكن ملاحظتها على الأجهزة الحقيقية.علاوة على ذلك، لا تستطيع ميري في الأساس التأكد من سلامة التعليمات البرمجية الخاصة بك. السلامة هي خاصية عدم التسبب مطلقًا في حدوث سلوك غير محدد عند استدعائها من تعليمات برمجية آمنة عشوائية، حتى بالاشتراك مع رموز صوتية أخرى. في المقابل، يمكن لـ Miri فقط أن تخبرك ما إذا كانت طريقة معينة للتفاعل مع التعليمات البرمجية الخاصة بك (على سبيل المثال، مجموعة اختبار) تتسبب في أي سلوك غير محدد في عملية تنفيذ معينة (والتي قد يكون هناك الكثير منها، على سبيل المثال عند التزامن أو أشكال أخرى من عدم الحتمية متورطون). عندما تجد Miri UB، فإن الكود الخاص بك يكون بالتأكيد غير سليم، ولكن عندما لا تجد Miri UB، فقد يتعين عليك فقط اختبار المزيد من المدخلات أو المزيد من الاختيارات غير الحتمية المحتملة.
قم بتثبيت Miri على Rust ليلاً عبر rustup
:
rustup +nightly component add miri
تفترض جميع الأوامر التالية أن سلسلة الأدوات الليلية مثبتة عبر rustup override set nightly
. وبدلاً من ذلك، استخدم cargo +nightly
لكل من الأوامر التالية.
الآن يمكنك تشغيل مشروعك في ميري:
cargo miri test
.cargo miri run
.في المرة الأولى التي تقوم فيها بتشغيل Miri، سيتم إجراء بعض الإعدادات الإضافية وتثبيت بعض التبعيات. سيطلب منك التأكيد قبل تثبيت أي شيء.
يدعم cargo miri run/test
نفس الأعلام تمامًا مثل cargo run/test
. على سبيل المثال، يقوم cargo miri test filter
بإجراء الاختبارات التي تحتوي على filter
باسمها فقط.
يمكنك تمرير الأعلام إلى ميري عبر MIRIFLAGS
. على سبيل المثال، MIRIFLAGS="-Zmiri-disable-stacked-borrows" cargo miri run
يقوم بتشغيل البرنامج دون التحقق من الأسماء المستعارة للمراجع.
عند تجميع التعليمات البرمجية عبر cargo miri
، يتم تعيين علامة التكوين cfg(miri)
للتعليمات البرمجية التي سيتم تفسيرها ضمن Miri. يمكنك استخدام هذا لتجاهل حالات الاختبار التي تفشل في ظل Miri لأنها تفعل أشياء لا يدعمها Miri:
# [ test ]
# [ cfg_attr ( miri , ignore ) ]
fn does_not_work_on_miri ( ) {
tokio :: run ( futures :: future :: ok :: < _ , ( ) > ( ( ) ) ) ;
}
لا توجد طريقة لسرد جميع الأشياء اللانهائية التي لا تستطيع ميري القيام بها، لكن المترجم سيخبرك بوضوح عندما يجد شيئًا غير مدعوم:
error: unsupported operation: can't call foreign function: bind
...
= help: this is likely not a bug in the program; it indicates that the program
performed an operation that Miri does not support
لا يمكن لـ Miri تشغيل مجموعة ثنائية أو مجموعة اختبار لهدف المضيف الخاص بك فحسب، بل يمكنها أيضًا إجراء تفسير متقاطع لأهداف أجنبية عشوائية: cargo miri run --target x86_64-unknown-linux-gnu
سوف يقوم بتشغيل برنامجك كما لو كان Linux البرنامج، بغض النظر عن نظام التشغيل المضيف الخاص بك. يعد هذا مفيدًا بشكل خاص إذا كنت تستخدم Windows، حيث أن هدف Linux مدعوم بشكل أفضل بكثير من أهداف Windows.
يمكنك أيضًا استخدام هذا لاختبار الأنظمة الأساسية بخصائص مختلفة عن النظام الأساسي المضيف الخاص بك. على سبيل المثال، سوف يقوم cargo miri test --target s390x-unknown-linux-gnu
بتشغيل مجموعة الاختبار الخاصة بك على هدف ذو نهاية كبيرة، وهو أمر مفيد لاختبار التعليمات البرمجية الحساسة للنهاية.
يتم اختيار أجزاء معينة من التنفيذ بشكل عشوائي بواسطة Miri، مثل تخزين تخصيصات العنوان الأساسي الدقيقة وتشذير سلاسل التنفيذ المتزامنة. في بعض الأحيان، قد يكون من المفيد استكشاف العديد من عمليات التنفيذ المختلفة، على سبيل المثال للتأكد من أن التعليمات البرمجية الخاصة بك لا تعتمد على "المحاذاة الفائقة" العرضية للتخصيصات الجديدة واختبار تشذير سلاسل الرسائل المختلفة. يمكن القيام بذلك باستخدام علامة --many-seeds
:
cargo miri test --many-seeds # tries the seeds in 0..64
cargo miri test --many-seeds=0..16
الإعداد الافتراضي لـ 64 بذرة مختلفة هو بطيء جدًا، لذا ربما تريد تحديد نطاق أصغر.
عند تشغيل Miri على CI، استخدم المقتطف التالي لتثبيت سلسلة أدوات ليلية باستخدام مكون Miri:
rustup toolchain install nightly --component miri
rustup override set nightly
cargo miri test
فيما يلي مثال لوظيفة إجراءات GitHub:
miri :
name : " Miri "
runs-on : ubuntu-latest
steps :
- uses : actions/checkout@v4
- name : Install Miri
run : |
rustup toolchain install nightly --component miri
rustup override set nightly
cargo miri setup
- name : Test with Miri
run : cargo miri test
يساعد cargo miri setup
الصريح في الحفاظ على نظافة مخرجات خطوة الاختبار الفعلية.
لا يدعم Miri جميع الأهداف التي يدعمها Rust. لكن الخبر السار هو أنه بغض النظر عن نظام التشغيل/النظام الأساسي المضيف لديك، فمن السهل تشغيل التعليمات البرمجية لأي هدف باستخدام --target
!
يتم اختبار الأهداف التالية على CI وبالتالي يجب أن تعمل دائمًا (بالدرجة الموثقة أدناه):
s390x-unknown-linux-gnu
باعتباره "هدفنا الكبير المفضل".linux
أو macos
أو windows
، يجب أن يعمل Miri بشكل عام، لكننا لا نقدم أي وعود ولا نجري اختبارات لمثل هذه الأهداف.solaris
/ illumos
: تمت صيانته بواسطة @devnexen. يدعم std::{env, thread, sync}
ولكن ليس std::fs
.freebsd
: مطلوب مشرف . يدعم std::env
وأجزاء من std::{thread, fs}
ولكن ليس std::sync
.android
: مطلوب مشرف . الدعم غير مكتمل للغاية، ولكن "مرحبًا بالعالم" الأساسي يعمل.wasi
: مطلوب معيل . الدعم غير مكتمل للغاية، ولا حتى الإخراج القياسي يعمل، ولكن الوظيفة main
الفارغة تعمل.main
.ومع ذلك، حتى بالنسبة للأهداف التي ندعمها، فإن درجة الدعم للوصول إلى واجهات برمجة تطبيقات النظام الأساسي (مثل نظام الملفات) تختلف بين الأهداف: بشكل عام، تتمتع أهداف Linux بأفضل دعم، وعادة ما تكون أهداف macOS متساوية. يتم دعم Windows بشكل أقل جودة.
على الرغم من أنها تطبق تقنية Rust Threading، إلا أن Miri نفسها عبارة عن مترجم ذو خيط واحد. هذا يعني أنه عند تشغيل cargo miri test
، من المحتمل أن ترى زيادة كبيرة في مقدار الوقت المستغرق لتشغيل مجموعة الاختبار بأكملها بسبب التباطؤ المتأصل في المترجم الفوري وفقدان التوازي.
يمكنك استعادة التوازي لمجموعة الاختبار الخاصة بك عن طريق تشغيل cargo miri nextest run -jN
(لاحظ أنك ستحتاج إلى تثبيت cargo-nextest
). ينجح هذا نظرًا لأن cargo-nextest
تقوم بجمع قائمة بجميع الاختبارات ثم تطلق cargo miri run
منفصلة لكل اختبار. سوف تحتاج إلى تحديد -j
أو --test-threads
؛ افتراضيًا، يتم إجراء اختبار cargo miri nextest run
. لمزيد من التفاصيل، راجع وثائق Miri cargo-nextest
.
ملاحظة: يعني نموذج الاختبار الواحد لكل عملية أن cargo miri test
قادر على اكتشاف سباقات البيانات حيث يتنافس اختباران على مورد مشترك، ولكن cargo miri nextest run
لن يكتشف مثل هذه السباقات.
ملحوظة: cargo-nextest
لا يدعم Doctests، راجع next-rs/nextest#16
عند استخدام الإرشادات المذكورة أعلاه، قد تواجه عددًا من أخطاء المترجم المربكة.
RUST_BACKTRACE=1
لعرض التتبع العكسي" قد ترى هذا عند محاولة إقناع ميري بعرض أثر خلفي. افتراضيًا، لا يعرض Miri أي بيئة للبرنامج، لذا فإن تشغيل RUST_BACKTRACE=1 cargo miri test
لن يؤدي إلى ما تتوقعه.
للحصول على تتبع خلفي، تحتاج إلى تعطيل العزل باستخدام -Zmiri-disable-isolation
:
RUST_BACKTRACE=1 MIRIFLAGS= " -Zmiri-disable-isolation " cargo miri test
std
تم تجميعه بواسطة إصدار غير متوافق من Rustc" ربما تقوم بتشغيل cargo miri
بإصدار مترجم مختلف عن ذلك المستخدم لإنشاء libstd المخصص الذي يستخدمه Miri، وقد فشل Miri في اكتشاف ذلك. حاول تشغيل cargo miri clean
.
-Z
ومتغيرات البيئة تضيف Miri مجموعتها الخاصة من علامات -Z
، والتي يتم تعيينها عادةً عبر متغير البيئة MIRIFLAGS
. نقوم أولاً بتوثيق العلامات الأكثر صلة والأكثر استخدامًا:
-Zmiri-address-reuse-rate=
يغير احتمالية إضافة تخصيص غير مكدس محرر إلى التجمع لإعادة استخدام العنوان، واحتمال أن يتم أخذ تخصيص جديد غير مكدس من التجمع. لا تتم إضافة تخصيصات المكدس إلى المجموعة أو أخذها منها أبدًا. الافتراضي هو 0.5
.-Zmiri-address-reuse-cross-thread-rate=
يغير احتمال أن التخصيص الذي يحاول إعادة استخدام كتلة من الذاكرة التي تم تحريرها مسبقًا سوف يأخذ في الاعتبار أيضًا الكتل التي تم تحريرها بواسطة سلاسل رسائل أخرى . الإعداد الافتراضي هو 0.1
، مما يعني افتراضيًا أنه في 90% من الحالات التي تتم فيها محاولة إعادة استخدام العنوان، سيتم النظر فقط في العناوين من نفس الموضوع. تؤدي إعادة استخدام عنوان من سلسلة رسائل أخرى إلى حدوث مزامنة بين تلك الخيوط، مما قد يؤدي إلى إخفاء سباقات البيانات وأخطاء الذاكرة الضعيفة.-Zmiri-compare-exchange-weak-failure-rate=
يغير معدل فشل عمليات compare_exchange_weak
. القيمة الافتراضية هي 0.8
(لذلك ستفشل 4 من أصل 5 عمليات ضعيفة). يمكنك تغييرها إلى أي قيمة بين 0.0
و 1.0
، حيث 1.0
تعني أنها ستفشل دائمًا و 0.0
تعني أنها لن تفشل أبدًا. لاحظ أن تعيينه على 1.0
من المحتمل أن يتسبب في حدوث توقف، لأنه يعني أن البرامج التي تستخدم compare_exchange_weak
لا يمكنها إحراز تقدم.-Zmiri-disable-isolation
يعطل عزل المضيف. ونتيجة لذلك، يتمتع البرنامج بإمكانية الوصول إلى موارد المضيف مثل متغيرات البيئة وأنظمة الملفات والعشوائية.-Zmiri-disable-leak-backtraces
يعطل تقارير التتبعات الخلفية لتسرب الذاكرة. افتراضيًا، يتم التقاط التتبع الخلفي لكل تخصيص عند إنشائه، فقط في حالة تسربه. يؤدي هذا إلى تحمل بعض الحمل الزائد على الذاكرة لتخزين البيانات التي لا يتم استخدامها أبدًا. يتم تضمين هذه العلامة بواسطة -Zmiri-ignore-leaks
.-Zmiri-env-forward=
يقوم بإعادة توجيه متغير البيئة var
إلى البرنامج المفسر. يمكن استخدامه عدة مرات لإعادة توجيه عدة متغيرات. سيظل التنفيذ محددًا إذا ظلت قيمة المتغيرات المعاد توجيهها كما هي. ليس له أي تأثير إذا تم ضبط -Zmiri-disable-isolation
.-Zmiri-env-set==
يضبط value
متغير البيئة var
في البرنامج المفسر. ويمكن استخدامه لتمرير متغيرات البيئة دون الحاجة إلى تغيير البيئة المضيفة. يمكن استخدامه عدة مرات لتعيين عدة متغيرات. إذا تم تعيين -Zmiri-disable-isolation
أو -Zmiri-env-forward
، فستكون للقيم التي تم تعيينها باستخدام هذا الخيار الأولوية على القيم من البيئة المضيفة.-Zmiri-ignore-leaks
يعمل على تعطيل مدقق تسرب الذاكرة، ويسمح أيضًا بوجود بعض الخيوط المتبقية عند خروج الخيط الرئيسي.-Zmiri-isolation-error=
يقوم بتكوين استجابة Miri للعمليات التي تتطلب وصول المضيف أثناء تمكين العزل. إن الإجراءات المدعومة هي abort
و hide
و warn
و warn-nobacktrace
. الإعداد الافتراضي هو abort
، مما يؤدي إلى إيقاف الجهاز. تدعم بعض العمليات (وليس كلها) أيضًا التنفيذ المستمر مع إرجاع الخطأ "تم رفض الإذن" إلى البرنامج. warn
يطبع تتبعًا خلفيًا كاملاً في كل مرة يحدث فيها ذلك؛ يعد warn-nobacktrace
أقل تفصيلاً ويتم عرضه مرة واحدة على الأكثر لكل عملية. hide
يخفي التحذير بالكامل.-Zmiri-num-cpus
يوضح عدد وحدات المعالجة المركزية المتاحة التي سيتم الإبلاغ عنها بواسطة miri. بشكل افتراضي، عدد وحدات المعالجة المركزية المتاحة هو 1
. لاحظ أن هذه العلامة لا تؤثر على كيفية تعامل ميري مع المواضيع بأي شكل من الأشكال.-Zmiri-permissive-provenance
يعطل التحذير الخاص بالتحويلات من عدد صحيح إلى مؤشر و ptr::with_exposed_provenance
. سيؤدي هذا بالضرورة إلى تفويت بعض الأخطاء لأن تلك العمليات لا يمكن تنفيذها بكفاءة ودقة في المطهر، ولكنه سيفتقد فقط الأخطاء التي تتعلق بالذاكرة/المؤشرات التي تخضع لهذه العمليات.-Zmiri-preemption-rate
يقوم بتكوين احتمال أنه في نهاية الكتلة الأساسية، سيتم استباق الخيط النشط. الافتراضي هو 0.01
(أي 1%). يؤدي تعيين هذا إلى 0
إلى تعطيل الشفعة.-Zmiri-report-progress
يجعل Miri يطبع تتبع المكدس الحالي بين الحين والآخر، حتى تتمكن من معرفة ما يفعله عندما يستمر البرنامج في التشغيل. يمكنك تخصيص عدد مرات طباعة التقرير عبر -Zmiri-report-progress=
، الذي يطبع التقرير كل N من الكتل الأساسية.-Zmiri-seed=
يقوم بتكوين بذرة RNG التي يستخدمها Miri لحل عدم الحتمية. يتم استخدام RNG هذا لاختيار العناوين الأساسية للتخصيصات، ولتحديد الاستباقية وفشل compare_exchange_weak
، وللتحكم في التخزين المؤقت للمتجر من أجل محاكاة الذاكرة الضعيفة. عند تمكين العزل (الإعداد الافتراضي)، يُستخدم هذا أيضًا لمحاكاة إنتروبيا النظام. البذرة الافتراضية هي 0. يمكنك زيادة تغطية الاختبار عن طريق تشغيل Miri عدة مرات باستخدام بذور مختلفة.-Zmiri-strict-provenance
يتيح التحقق الصارم من المصدر في ميري. وهذا يعني أن إلقاء عدد صحيح على المؤشر يؤدي إلى نتيجة بمصدر "غير صالح"، أي بمصدر لا يمكن استخدامه لأي وصول إلى الذاكرة.-Zmiri-symbolic-alignment-check
يجعل فحص المحاذاة أكثر صرامة. افتراضيًا، يتم التحقق من المحاذاة عن طريق توجيه المؤشر إلى عدد صحيح، والتأكد من أن هذا عدد صحيح من مضاعفات المحاذاة. يمكن أن يؤدي هذا إلى حالات يجتاز فيها البرنامج فحص المحاذاة عن طريق الصدفة البحتة، لأن الأشياء "تصادف" أنها تمت محاذاتها بشكل كافٍ - لا يوجد UB في هذا التنفيذ ولكن قد يكون هناك UB في عمليات أخرى. ولتجنب مثل هذه الحالات، فإن فحص المحاذاة الرمزية يأخذ في الاعتبار فقط المحاذاة المطلوبة للتخصيص ذي الصلة، والإزاحة في ذلك التخصيص. يؤدي هذا إلى تجنب فقدان مثل هذه الأخطاء، ولكنه يتسبب أيضًا في حدوث بعض النتائج الإيجابية الخاطئة عندما يقوم الكود بإجراء حساب يدوي للأعداد الصحيحة لضمان المحاذاة. (تعمل طريقة align_to
الخاصة بالمكتبة القياسية بشكل جيد في كلا الوضعين؛ وفي ظل المحاذاة الرمزية، فإنها تملأ الشريحة الوسطى فقط عندما يضمن التخصيص محاذاة كافية.)العلامات المتبقية مخصصة للاستخدام المتقدم فقط، ومن المرجح أن تتغير أو تتم إزالتها. بعض هذه العناصر غير سليمة ، مما يعني أنها يمكن أن تؤدي إلى فشل Miri في اكتشاف حالات السلوك غير المحدد في البرنامج.
-Zmiri-disable-alignment-check
يعطل التحقق من محاذاة المؤشر، حتى تتمكن من التركيز على حالات الفشل الأخرى، ولكن هذا يعني أن Miri يمكن أن تفوت الأخطاء في برنامجك. استخدام هذا العلم غير سليم .-Zmiri-disable-data-race-detector
يعطل التحقق من سباقات البيانات. استخدام هذا العلم غير سليم . وهذا يعني -Zmiri-disable-weak-memory-emulation
.-Zmiri-disable-stacked-borrows
يعطل التحقق من قواعد الأسماء المستعارة التجريبية لتتبع الاقتراضات (Stacked Borrows وTree Borrows). وهذا يمكن أن يجعل Miri يعمل بشكل أسرع، ولكنه يعني أيضًا أنه لن يتم اكتشاف أي انتهاكات للاسم المستعار. إن استخدام هذه العلامة غير سليم (لكن قواعد السلامة المتأثرة تجريبية). العلامات اللاحقة لها الأسبقية: يمكن إعادة تنشيط تتبع الاقتراض بواسطة -Zmiri-tree-borrows
.-Zmiri-disable-validation
يعطل فرض ثوابت الصلاحية، والتي يتم فرضها افتراضيًا. يعد هذا مفيدًا في الغالب للتركيز على حالات الفشل الأخرى (مثل الوصول خارج الحدود) أولاً. يعني تعيين هذه العلامة أن Miri قد يفتقد الأخطاء الموجودة في برنامجك. ومع ذلك، يمكن أن يساعد هذا أيضًا في جعل Miri يعمل بشكل أسرع. استخدام هذا العلم غير سليم .-Zmiri-disable-weak-memory-emulation
يعمل على تعطيل محاكاة بعض تأثيرات الذاكرة الضعيفة لـ C++ 11.-Zmiri-native-lib=
هو علامة تجريبية لتوفير الدعم لاستدعاء الوظائف الأصلية من داخل المترجم عبر FFI. لا يزال يتم تنفيذ الوظائف التي لا يوفرها هذا الملف عبر حشوات ميري المعتادة. تحذير : إذا تم تحديد ملف .so
غير صالح/غير صحيح، فقد يتسبب ذلك في حدوث سلوك غير محدد في Miri نفسها! وبالطبع، لا تستطيع ميري إجراء أي فحوصات على الإجراءات التي تم اتخاذها بواسطة الكود الأصلي. لاحظ أن Miri لديها طريقة تعاملها الخاصة مع واصفات الملفات، لذلك إذا كنت تريد استبدال بعض الوظائف التي تعمل على واصفات الملفات، فسيتعين عليك استبدالها جميعًا ، وإلا فسيتم الخلط بين نوعي واصفات الملفات. هذا هو العمل الجاري ; حاليًا، يتم دعم وسيطات الأعداد الصحيحة وقيم الإرجاع فقط (ولا، لن تنجح عمليات تحويل المؤشر/الأعداد الصحيحة للتغلب على هذا القيد؛ وسوف تفشل بشكل فظيع). كما أنه يعمل فقط على مضيفي Unix في الوقت الحالي.-Zmiri-measureme=
يمكّن من تحديد measureme
للبرنامج المفسر. يمكن استخدام هذا للعثور على أجزاء برنامجك التي يتم تنفيذها ببطء تحت Miri. تتم كتابة ملف التعريف في ملف داخل دليل يسمى
، ويمكن معالجته باستخدام الأدوات الموجودة في المستودع https://github.com/rust-lang/measureme.-Zmiri-mute-stdout-stderr
يتجاهل بصمت جميع عمليات الكتابة إلى stdout وstderr، لكنه يبلغ البرنامج بأنه قام بكتابتها بالفعل. يعد هذا مفيدًا عندما لا تكون مهتمًا بمخرجات البرنامج الفعلية، ولكنك تريد فقط رؤية أخطاء وتحذيرات Miri.-Zmiri-recursive-validation
عبارة عن علامة تجريبية للغاية تجعل التحقق من الصلاحية متكررًا أسفل المراجع.-Zmiri-retag-fields[=]
يتحكم عندما تتكرر إعادة وضع علامات الاقتراضات المكدسة في الحقول. all
يعني أنه يتكرر دائمًا (الافتراضي، ويعادل -Zmiri-retag-fields
بدون قيمة صريحة)، none
يعني أنه لا يتكرر أبدًا، ويعني scalar
أنه يتكرر فقط للأنواع التي سنصدر فيها أيضًا تعليقات توضيحية noalias
في LLVM IR الذي تم إنشاؤه ( الأنواع التي تم تمريرها كعدديات فردية أو أزواج من الكميات). تعيين هذا على none
غير سليم .-Zmiri-provenance-gc=
يقوم بتكوين عدد مرات تشغيل أداة تجميع البيانات المهملة الخاصة بمصدر المؤشر. الإعداد الافتراضي هو البحث عن المصدر الذي لا يمكن الوصول إليه وإزالته مرة واحدة كل 10000
كتلة أساسية. يؤدي تعيين هذا إلى 0
إلى تعطيل أداة تجميع البيانات المهملة، مما يتسبب في استخدام الذاكرة المفرط لبعض البرامج و/أو وقت التشغيل الخطي الفائق.-Zmiri-track-alloc-accesses
التخصيصات والأحداث المجانية للتخصيصات المتعقبة فحسب، بل يُظهر أيضًا عمليات القراءة والكتابة.-Zmiri-track-alloc-id=,,...
يُظهر تتبعًا خلفيًا عندما يتم تخصيص التخصيصات المحددة أو تحريرها. يساعد هذا في تصحيح تسرب الذاكرة واستخدامه بعد الأخطاء المجانية. لا يؤدي تحديد هذه الوسيطة عدة مرات إلى استبدال القيم السابقة، بل يقوم بدلاً من ذلك بإلحاق قيمها بالقائمة. إدراج معرف عدة مرات ليس له أي تأثير.-Zmiri-track-pointer-tag=,,...
يُظهر تتبعًا خلفيًا عند إنشاء علامة مؤشر معينة ومتى (إذا حدث ذلك) يتم ظهورها من مكدس الاقتراض (حيث تصبح العلامة غير صالح وأي استخدام مستقبلي له سيكون خطأ). يساعدك هذا في معرفة سبب حدوث UB والمكان المناسب للبحث عنه في الكود الخاص بك. لا يؤدي تحديد هذه الوسيطة عدة مرات إلى استبدال القيم السابقة، بل يقوم بدلاً من ذلك بإلحاق قيمها بالقائمة. إدراج علامة عدة مرات ليس له أي تأثير.-Zmiri-track-weak-memory-loads
يُظهر تتبعًا خلفيًا عندما تقوم محاكاة الذاكرة الضعيفة بإرجاع قيمة قديمة من التحميل. يمكن أن يساعد هذا في تشخيص المشكلات التي تختفي ضمن -Zmiri-disable-weak-memory-emulation
.-Zmiri-tree-borrows
يستبدل الاقتراضات المكدسة بقواعد Tree Borrows. تعد Tree Borrows أكثر تجريبية من Stacked Borrows. في حين أن Tree Borrows لا تزال سليمة من حيث اكتشاف جميع انتهاكات الأسماء المستعارة التي قد تستغلها الإصدارات الحالية من المترجم، فمن المحتمل أن يكون نموذج الاسم المستعار النهائي لـ Rust أكثر صرامة من Tree Borrows. بمعنى آخر، إذا كنت تستخدم Tree Borrows، حتى لو تم قبول الكود الخاص بك اليوم، فقد يتم الإعلان عنه UB في المستقبل. هذا أقل احتمالًا بكثير مع Stacked Borrows.-Zmiri-force-page-size=
يتجاوز حجم الصفحة الافتراضي للهندسة، بمضاعفات 1k. 4
هو الافتراضي لمعظم الأهداف. يجب أن تكون هذه القيمة دائمًا قوة 2 وليست صفرًا.-Zmiri-unique-is-unique
يقوم بإجراء فحوصات إضافية للاسم المستعار لـ core::ptr::Unique
للتأكد من إمكانية اعتباره noalias
نظريًا. هذه العلامة تجريبية ولها تأثير فقط عند استخدامها مع -Zmiri-tree-borrows
. بعض أعلام Rustc -Z
الأصلية لها أيضًا صلة كبيرة بـ Miri:
-Zmir-opt-level
يتحكم في عدد تحسينات MIR التي يتم إجراؤها. تتجاوز ميري الإعداد الافتراضي ليكون 0
؛ يرجى العلم أن استخدام أي مستوى أعلى يمكن أن يجعل Miri تفوت الأخطاء في برنامجك لأنه تم تحسينها.-Zalways-encode-mir
يجعل تفريغ Rustc MIR حتى بالنسبة للوظائف الأحادية الشكل تمامًا. يعد هذا ضروريًا حتى تتمكن Miri من تنفيذ مثل هذه الوظائف، لذا تقوم Miri بتعيين هذه العلامة بشكل افتراضي.-Zmir-emit-retag
يتحكم في ما إذا كان سيتم إصدار بيانات Retag
. يقوم Miri بتمكين هذا بشكل افتراضي لأنه ضروري للاقتراضات المكدسة والاقتراضات الشجرية.علاوة على ذلك، يتعرف ميري على بعض متغيرات البيئة:
MIRIFLAGS
العلامات الإضافية التي سيتم تمريرها إلى Miri.MIRI_LIB_SRC
الدليل الذي تتوقع فيه Miri مصادر المكتبة القياسية التي ستقوم بإنشائها واستخدامها للتفسير. يجب أن يشير هذا الدليل إلى الدليل الفرعي library
بفحص مستودع rust-lang/rust
.MIRI_SYSROOT
إلى sysroot المراد استخدامه. عند استخدام cargo miri test
/ cargo miri run
، يؤدي هذا إلى تخطي الإعداد التلقائي - قم بتعيين هذا فقط إذا كنت لا تريد استخدام sysroot الذي تم إنشاؤه تلقائيًا. عند استدعاء cargo miri setup
، يشير هذا إلى المكان الذي سيتم وضع sysroot فيه.MIRI_NO_STD
من إنشاء جذر النظام الخاص بالهدف بدون libstd. وهذا يسمح باختبار وتشغيل برامج no_std. لا ينبغي عادة استخدام هذا ; ميري لديه إرشادي لاكتشاف الأهداف غير المنقولة بناءً على اسم الهدف. قد يؤدي تعيين هذا على هدف يدعم libstd إلى نتائج مربكة. extern
توفر Miri بعض الوظائف extern
التي يمكن للبرامج استيرادها للوصول إلى وظائف Miri المحددة. تم الإعلان عنها في /tests/utils/miri_extern.rs.
من المتوقع أن تعلن الثنائيات التي لا تستخدم المكتبة القياسية عن وظيفة مثل هذه حتى تعرف ميري أين من المفترض أن تبدأ التنفيذ:
# [ cfg ( miri ) ]
# [ no_mangle ]
fn miri_start ( argc : isize , argv : * const * const u8 ) -> isize {
// Call the actual start function that your project implements, based on your target's conventions.
}
إذا كنت تريد المساهمة في ميري، عظيم! يرجى مراجعة دليل المساهمة لدينا.
للمساعدة في تشغيل Miri، يمكنك فتح مشكلة هنا على GitHub أو استخدام تدفق Miri على Rust Zulip.
بدأ هذا المشروع كجزء من دورة بحثية للطلاب الجامعيين في عام 2015 بواسطة @solson في جامعة ساسكاتشوان. هناك شرائح وتقرير متاح من هذا المشروع. في عام 2016، انضم @oli-obk لإعداد Miri لاستخدامه في النهاية كمقيم ثابت في مترجم Rust نفسه (أساسًا، للأشياء const
static
)، ليحل محل المقيم القديم الذي كان يعمل مباشرة على AST. في عام 2017، أجرى @RalfJung تدريبًا داخليًا مع Mozilla وبدأ في تطوير Miri نحو أداة للكشف عن السلوك غير المحدد، وكذلك استخدام Miri كوسيلة لاستكشاف عواقب التعريفات المختلفة المحتملة للسلوك غير المحدد في Rust. تم الانتهاء أخيرًا من نقل @oli-obk لمحرك Miri إلى المترجم في أوائل عام 2018. وفي الوقت نفسه، في وقت لاحق من ذلك العام، أجرى @RalfJung تدريبًا داخليًا ثانيًا، حيث قام بتطوير Miri بشكل أكبر مع دعم التحقق من ثوابت النوع الأساسي والتحقق من استخدام المراجع وفقًا لذلك. إلى قيود التعرج الخاصة بهم.
لقد عثرت ميري بالفعل على عدد من الأخطاء في مكتبة Rust القياسية وخارجها، وقد قمنا بجمع بعض منها هنا. إذا ساعدتك Miri في العثور على خطأ UB دقيق في التعليمات البرمجية الخاصة بك، فنحن نقدر أن يضيفه العلاقات العامة إلى القائمة!
تم العثور على أخطاء محددة:
Debug for vec_deque::Iter
للوصول إلى الذاكرة غير المهيأةVec::into_iter
يقوم بقراءة ZST غير محاذيةFrom<&[T]> for Rc
لإنشاء مرجع غير محاذٍ بشكل كافٍBTreeMap
بإنشاء مرجع مشترك يشير إلى تخصيص صغير جدًاVec::append
إنشاء مرجع متدليstr
تحويل مرجع مشترك إلى مرجع قابل للتغييرrand
يؤدي القراءات غير المحاذاةposix_memalign
بطريقة غير صالحةgetrandom
يستدعي نظام getrandom
بطريقة غير صالحةVec
و BTreeMap
يتسربان من الذاكرة في ظل بعض الظروف (المذعورة).beef
تسرب الذاكرةEbrCell
ذاكرة غير مهيأة بشكل غير صحيحservo_arc
ينشئ مرجعًا مشتركًا متدليًاencoding_rs
بإجراء عمليات حسابية خارج الحدودVec::from_raw_parts
بشكل غير صحيحAtomicPtr
و Box::from_raw_in
ThinVec
crossbeam-epoch
assume_init
على MaybeUninit
الذي تمت تهيئته جزئيًاinteger-encoding
يؤدي إلى إلغاء الإشارة إلى مؤشر غير محاذٍrkyv
يقوم بإنشاء Box<[u8]>
من التخصيص المتراكبarc-swap
thread::scope
regex
يتعامل بشكل غير صحيح مع المخازن المؤقتة Vec
غير المحاذاةcompare_exchange_weak
في once_cell
vec::IntoIter
Iterator::collect
الموضعيportable-atomic-util
std::mpsc
(الكود الأصلي في العارضة المتقاطعة)تم العثور على انتهاكات للاقتراضات المكدسة والتي من المحتمل أن تكون أخطاء (لكن الاقتراضات المكدسة هي مجرد تجربة حاليًا):
VecDeque::drain
يقوم بإنشاء مراجع متداخلة قابلة للتغييرBTreeMap
المختلفةBTreeMap
بإنشاء مراجع قابلة للتغيير تتداخل مع المراجع المشتركةBTreeMap::iter_mut
ينشئ مراجع متداخلة قابلة للتغييرBTreeMap
باستخدام مؤشرات أولية خارج منطقة الذاكرة الصالحة الخاصة بهاLinkedList
إلى إنشاء مراجع متداخلة قابلة للتغييرVec::push
يبطل المراجع الموجودة في المتجهalign_to_mut
ينتهك تفرد المراجع القابلة للتغييرsized-chunks
لإنشاء مراجع مستعارة قابلة للتغييرString::push_str
يؤدي إلى إبطال المراجع الموجودة في السلسلةryu
باستخدام مؤشرات أولية خارج منطقة الذاكرة الصالحة الخاصة بهاEnv
يستخدم مؤشرًا أوليًا خارج منطقة الذاكرة الصالحة الخاصة بهVecDeque::iter_mut
يقوم بإنشاء مراجع متداخلة قابلة للتغيير<[T]>::copy_within
استخدام القرض بعد إبطاله مرخص بموجب أي من
في خيارك.
ما لم تنص صراحةً على خلاف ذلك، فإن أي مساهمة يتم تقديمها عمدًا لتضمينها في العمل بواسطتك يجب أن تكون مرخصة كما هو مذكور أعلاه، دون أي شروط أو أحكام إضافية.