Chrono Mock
اللغةالعربية

اختبار مشكلة عام 2038 على Windows

في 03:14:07 UTC يوم 19 يناير 2038 ينفد عدّاد ذو إشارة بحجم 32 بتًّا لثوانٍ منذ 1970. وساعة Windows تتابع بعد ذلك - أما البرامج وصيغ الملفات والمكتبات التي احتفظت بنسختها الخاصة ذات 32 بتًّا فلا. وإليك كيف تجدها في تطبيق واحد، من دون ضبط تاريخ الجهاز كله على 2038.

أين قد يختبئ الخطأ بعدُ

ساعة Windows عدّاد بحجم 64 بتًّا لخطوات مدتها 100 نانوثانية منذ 1601، فليس فيها 2038. ونوع time_t في مكتبة تشغيل C بحجم 64 بتًّا افتراضيًا منذ Visual Studio 2005. فما يبقى هو الشيفرة التي اختارت وقتًا بحجم 32 بتًّا أو فقدت نصفه الأعلى في الطريق:

  • إصدارات 32 بتًّا مُصرَّفة بـ _USE_32BIT_TIME_T، أو التي تستدعي _time32 و__time32_t مباشرة. وتحذّر وثائق Microsoft نفسها من أن تطبيقًا كهذا قد يفشل بعد 18 يناير 2038.
  • وقت بحجم 64 بتًّا مخزَّن في int أو long. وفي Windows كلاهما بحجم 32 بتًّا، حتى في برنامج 64 بتًّا.
  • مكتبات وصيغ ملفات وبروتوكولات شبكية وأعمدة قواعد بيانات تحفظ الثواني منذ 1970 في 32 بتًّا.
  • شيفرة تضيف سنوات. فترخيص لعشرين عامًا، أو جدول سداد لثلاثين عامًا، أو شهادة سارية حتى 2040، يعبر هذا الحد قبل وصول 2038 بزمن طويل.

عبور الحد في تطبيق واحد

الحد معرَّف بالتوقيت العالمي المنسّق، و--at يُقرأ بمنطقة الجلسة، فثبّت المنطقة على UTC حين تكتب اللحظة بنفسك. أما السيناريو الجاهز فيحمل لحظة UTC مطلقة ولا يحتاج إلى منطقة.

# السيناريو: تبدأ الجلسة عند الحد نفسه، 03:14:07 UTC
chrono run "C:\apps\test.exe" --preset year-2038 --report session.txt

# ابدأ قبله بسبع عشرة ثانية ودع التطبيق يعبره مباشرة
chrono run "C:\apps\test.exe" --at 2038-01-19T03:13:50 --zone +00:00 --report session.txt

# ابدأ أبكر وشغّل بسرعة x60 - يصل الحد بعد نحو 14 ثانية
chrono run "C:\apps\test.exe" --at 2038-01-19T03:00:00 --zone +00:00 --mode x60

# أو شغّل بتاريخ اليوم واقفز فوقه والتطبيق مفتوح
chrono run "C:\apps\test.exe" --jump-after 5:2038-01-19T03:14:05 --zone +00:00

بعد الحد بثانية يصبح العدّاد ذو الإشارة بحجم 32 بتًّا -2,147,483,648، ويُقرأ 13 ديسمبر 1901، 20:45:52 UTC. تاريخ في 1901، أو رقم سالب، أو عنصر ينتهي فجأة أو يُرتَّب أولًا، أو استثناء يُطلق من شيفرة التواريخ - هذا ما يبدو عليه الفيض من الخارج.

ضبط الساعة الحقيقية على 2038 هو الطريق الآخر إلى هنا، وهو الذي يكسر أكثر ما يكسر. ماذا يحدث حين تغيّر تاريخ النظام ←

التحقق من أنه وصل إلى البرنامج

اختبار ينجح لأن البرنامج لم يرَ 2038 قط أسوأ من عدم وجود اختبار. وتقرير نهاية كل جلسة يقول أي ساعة قرأها البرنامج وكم مرة:

Chrono Mock - session report
  target:   .\build\test.exe
  verdict:  WORKS - time substitution took effect  (processes: 1)
            every process that read time saw the session clock
  session:  fake clock reached 2038-01-19T03:14:08
            real elapsed 1.3s, fake elapsed 1.3s
  covered channels (substituted, with call counts, 10 calls in all):
            - pid 21240: GetSystemTimeAsFileTime (5 calls)
            - pid 21240: GetLocalTime (5 calls)

يؤكد سطر session أن ساعة التطبيق تجاوزت الحد. والحكم works مع أعداد الاستدعاءات يعني أن البرنامج قرأ الساعة وسُلّم تاريخ 2038؛ أما works partially فيسمّي القنوات التي قرأها بطريق آخر. ماذا تعني الأحكام ←

ما لا يثبته الاختبار الناجح

  • الذي تحرك هو ساعة البرنامج وحدها. فالتاريخ الذي يحمّله من ملف أو قاعدة بيانات هو ما خُزّن هناك، ولذا فتاريخ من 2038 داخل البيانات اختبار منفصل. وتحسب لك حاسبة التواريخ مثل هذه التواريخ: chrono calc --base 2038-01-19T03:14:07 --zone +00:00 --shift +1s
  • الخادم الذي يتحدث إليه البرنامج يبقى على التاريخ الحقيقي. وحدّ 32 بتًّا من ذلك الجانب خارج المتناول، وتحذّر الجلسة حين ترى البرنامج يفتح اتصالًا شبكيًا.

جرّبه