
مدقق للأعمار وأنواع التنقيح الأخرى
C مُتحقِّق من
L الأعمار وأنواع أخرى من
R التحسين (Refinement)
لـ Zig
فيديو: https://www.youtube.com/watch?v=mf0WzTOe-40 دعم مالي: https://buymeacoffee.com/dnautics
ناقش على HN: https://news.ycombinator.com/item?id=42923829
ناقش على lobste.rs: https://lobste.rs/s/9sitsj/clr_checker_for_lifetimes_other
فيديو عرض مباشر: https://www.youtube.com/watch?v=ZY_Z-aGbYm8
ينشئ هذا المشروع مُحوِّلًا (transpiler) بلغة Zig لمُصرِّف Zig، يحوّل AIR (التمثيل الوسيط المجرَّد — Abstract Intermediate Representation) إلى كود مصدري بلغة Zig يُجري تحليلًا ثابتًا (static analysis) في وقت الترجمة. يكتشف المُحلِّل المُولَّد مشكلات سلامة الذاكرة مثل الاستخدام قبل الإسناد (use-before-assignment)، والاستخدام بعد التحرير (use-after-free)، وهروب مؤشرات المكدس (stack pointer escapes)، بالإضافة إلى سلوكيات غير محددة (UB) خاصة بلغة Zig مثل تأكيدات عدم الصفرية (non-nullness assertions)، وانتهاكات الاتحادات الموسومة (tagged unions)، أو إساءة استخدام fieldParentPtr.
الهدف هو جلب ضمانات سلامة الذاكرة بمستوى Rust إلى Zig عبر التحليل الثابت لـ AIR، دون تغيير اللغة نفسها.
يعتمد CLR على نسخة مشتقّة من مُصرِّف Zig (مضمَّنة كوحدة فرعية في zig/) تضيف دعم توجيه AIR إلى إضافات خارجية. عند الاستدعاء مع -ofmt=air -fair-out=<plugin.so>، يقوم المُصرِّف بتحميل المكتبة المشتركة المحددة ويمرر إليها AIR المُولَّد لمعالجته.
تهدف CLR إلى دفع البرامج نحو أنماط دورة حياة صريحة وقابلة للتحقق محليًا، وليس فقط إلى التعرف على كل برنامج Zig صالح تقنيًا. عندما يكون تمثيلان ممكنين، تفضّل CLR التمثيل الذي يجعل حالة الموارد ظاهرة في النوع وبنية تدفق التحكم.
على سبيل المثال، تجنَّب الإغلاق الشرطي لوصف ملف (file descriptor) غير اختياري:
const file = try std.fs.cwd().openFile(path, .{});
if (should_close) {
file.close(); // Bad: file is ambiguously open after this branch.
}
فضِّل تمثيل الملكية الشرطية بنوع اختياري (optional):
var file: ?std.fs.File = null;
if (should_open) {
file = try std.fs.cwd().openFile(path, .{});
}
if (file) |open_file| {
open_file.close();
}
الإغلاق الشرطي لوصف غير اختياري يترك دورة حياته غامضة بعد الفرع. السياسة المقصودة لـ CLR هي رفض هذا النمط بدلًا من حمل حالة «ربما مُغلق» دائمة.
ينطبق المبدأ نفسه على المؤشرات المُخصَّصة. لا تحرِّر عبر مؤشر مشتق:
const allocation = try allocator.alloc(u8, size);
const payload = allocation[header_size..];
allocator.free(payload); // Bad: payload is not the allocation base.
أبقِ مؤشر قاعدة التخصيص متاحًا للتحرير، واستخدم المؤشرات المشتقة للوصول فقط:
const allocation = try allocator.alloc(u8, size);
defer allocator.free(allocation);
const payload = allocation[header_size..];
use(payload);
يُرفض تحرير مؤشر حقل (field pointer)، أو شريحة فرعية (subslice)، أو مؤشر ناتج عن عمليات حسابية ما لم تعِد قاعدة داخلية موثّقة إنشاء سلسلة ملكية (provenance) لقاعدة التخصيص.
هذه السياسات صارمة افتراضيًا لأنها تُنتج كودًا بدورات حياة موارد أبسط وأسهل مراجعة. ستسمح آلية تعليقات unsafe مستقبلية لمجموعات GIDs أو عمليات محددة بالانسحاب من تحليلات فردية. سيدعم ذلك الكود الذي يقبل عن قصد فحصًا أضعف مقابل الأداء، دون إضعاف النموذج الافتراضي لبقية البرنامج.
هذه إعادة كتابة نشطة لإثبات المفهوم الأصلي المبني على Elixir بلغة Zig. يُحمَّل تنفيذ Zig كإضافة (plugin) للمُصرِّف ويحلّل AIR مباشرة.
المُنجَز حاليًا:
std.mem.Allocator:
create/destroy - تخصيص عنصر واحدalloc/free - تخصيص الشرائح (بما في ذلك alignedAlloc و allocSentinel وغيرها)realloc/remap - إعادة تخصيص الشرائح مع تتبّع تحرير الشريحة القديمةdupe/dupeZ - تكرار الشرائحinit/deinit/allocator - دورة حياة arena كاملةstd.process.args و std.mem.asBytes و std.HashMap وواجهات المُخصِّصات والملفاتstd.HashMap بهوية تخزين معيارية (canonical) للبيانات الوصفية/المفاتيح/القيم عبر put و get و getPtr وتكرار القيمposix.open/close/dup/dup2/socket/accept/epoll_create/pipeمُخطَّط له (انظر LIMITATIONS.md للتفاصيل):
sudo apt install batsيجب بناء مُصرِّف Zig المضمَّن (vendored) وإضافة libclr بمستويات تحسين متطابقة. ستؤدي مستويات التحسين غير المتطابقة إلى أعطال تجزئة (segfaults).
# Build the custom Zig compiler with ReleaseFast (first time only, or after submodule changes)
cd zig && zig build --zig-lib-dir lib -Doptimize=ReleaseFast && cd ..
# Build the CLR plugin with matching optimization
zig build -Doptimize=ReleaseFast
للتطوير/التصحيح، استخدم ReleaseSafe أو Debug لكليهما:
# ReleaseSafe (with safety checks, slightly slower)
cd zig && zig build --zig-lib-dir lib -Doptimize=ReleaseSafe && cd ..
zig build -Doptimize=ReleaseSafe
# Debug (full debug info, slowest)
cd zig && zig build --zig-lib-dir lib && cd ..
zig build
# Compile a Zig file using the AIR backend
zig/zig-out/bin/zig build-exe -fair-out=zig-out/lib/libclr.so -ofmt=air -femit-bin=output.air.zig your_file.zig
# Run the generated analyzer
zig run --dep clr -Mroot=output.air.zig -Mclr=lib/lib.zig
يُرسَل المخرَج إلى stderr.
# Unit tests (codegen/DLL)
zig build test
# Unit tests (runtime library)
zig test lib/lib.zig
# A focused integration test file
bats test/integration/fd.bats