استدعاء eval() المباشر يعطّل تشويش VM
إذا احتوت دالة على استدعاء مباشر eval(code) في أي موضع من جسمها (بما في ذلك الدوال المتداخلة)، فإن تشويش VM يتخطى تلك الدالة، ويُصدر المشوِّش تحذير VMDynamicCodeSkipped (يذكر اسم الدالة إن كان لها اسم). في وضع الجذر (الافتراضي) تُتخطّى الدالة بأكملها وجميع الدوال المتداخلة فيها؛ أما في وضع التعليقات فالدالة المتداخلة التي تعلّمها على حدة تظل تُحوَّل إلى الآلة الافتراضية ما لم تحتوِ هي نفسها على eval. ويُصدر eval المباشر ذو الوسيط غير الثابت أيضًا تحذير DynamicCodeRenameRisk. والسبب أن eval المباشر يصل إلى المتغيرات المحلية للدالة المحيطة، وهذه المتغيرات لا تكون متاحة عند ترجمة الدالة إلى بايت كود الآلة الافتراضية.
مهم للكود المغلَّف داخل IIFE. إذا احتوت IIFE على المستوى الأعلى على أي eval مباشر في أعماقها، فلن تُشوَّش IIFE بأكملها (بما فيها كل كودك) بتشويش VM.
لفكّ IIFE ثمن: فبمجرد أن تصبح دوالك على المستوى الأعلى، لا تُتخطى إلا الدالة المسببة للمشكلة، لكن الدوال الباقية تصبح على مستوى الجذر، فيحافظ تشويش VM على أسمائها. راجع إخفاء أسماء الدوال عن تحليل نماذج LLM لمعرفة كيفية إبقاء هذه الأسماء خارج الناتج.
الصيغ غير المباشرة مثل (0, eval)(code) وwindow.eval(code) لا تمنع تشويش VM. والصيغة eval?.(code) استثناء: إذ تنفّذها لغة JavaScript على أنها eval غير مباشر، لكن المشوِّش يعاملها من باب الحيطة معاملة eval المباشر ويتخطى الدالة.
يُعامَل مُنشئ Function (new Function(body) / Function(body)) بالطريقة نفسها عندما يكون وسيط الجسم ديناميكيًا. فالدالة التي تحتوي على استدعاء ديناميكي للمُنشئ new Function(...) تُتخطى أيضًا، مع تحذير VMDynamicCodeSkipped. وكما في eval المباشر الديناميكي، يضيف المشوِّش تحذير DynamicCodeRenameRisk، لأن الجسم المبني أثناء التشغيل قد يشير إلى معرِّفات أُعيدت تسميتها. أما الاستدعاءات الثابتة بالكامل مثل new Function('a', 'b', 'return a + b') فلا تُتخطى.
يُنفَّذ eval غير المباشر ومُنشئ Function في النطاق العام. فلا يمكنهما قراءة المتغيرات المحلية للمستدعي، لكنهما قد يفشلان مع ذلك إذا أشارا إلى متغيرات عامة أُعيدت تسميتها أو أُزيلت. والجسم الثابت الذي لا يستخدم إلا معاملاته الخاصة، مثل new Function('a', 'b', 'return a + b')، يتجنب هذا الاعتماد. راجع التحذيرات واختبر الحزمة النهائية؛ فتغيير صيغة eval وحده لا يجعل الكود الديناميكي العشوائي آمنًا.
منفذ الطوارئ (v6.14.0+): اضبط vmForceCompileDynamicCode: true (أو فعّل مفتاح Force Compile Dynamic Code ضمن مجموعة التجاوزات في قسم VM) لتحويل الدالة المحيطة إلى بايت كود رغم ذلك وكتم التحذير VMDynamicCodeSkipped. لكنه لا يستطيع إصلاح النطاق: فداخل الدالة المترجَمة قسرًا، لا يستطيع eval المباشر قراءة المتغيرات المحلية للدالة أو معاملاتها أو متغيرات دالة محيطة محوَّلة إلى VM، ولا الكتابة فيها، حتى عندما يكون الكود نصًا حرفيًا. استخدمه فقط عندما لا يشير الكود المقيَّم إلا إلى متغيرات عامة. ويستمر صدور التحذير DynamicCodeRenameRisk مع تفعيل هذا الخيار، لأن خطر إعادة التسمية الذي يصفه مستقل عن تخطي VM.
راجع تشويش VM مع eval وnew Function للاطلاع على المصفوفة الكاملة للحالات، وأشكال التحذيرات، والحلول البديلة.
