٢٣‏/٣‏/١٤٢٨ هـ

مشكلة الخمسة والعشرون يوماً



عجيباً أمر البرمجة. والأعجب أن تكون مهووس وتبحث عن المثالية في البرمجة.
بعد أن صممت البرنامج وقمت بفحصه وتأكدت أن كل شي يعمل كما هو مصمم عليه....يجب ألا يكون هناك أي شي للصدفة .
99.9% فكرت بكل شيء. ودرست الاحتمالات الممكن حدوثها بالبرنامج واحتطت .
وتلافيت استعمال أي مكون مالم أكون صممته إلا (واحد) ، لان لن أقوم باكتشاف العجلة من جديد،البرنامج صمم على ان يعمل اربع وعشرون ساعة في سبعة ايام ، يعني لاشي أن يوقفه.

وضعت تحت الفحص لمده 14 يوما واكتشفت خطأ ما. ليس من البرنامج ولكن بسبب احد دوال الويندوز. وتلافيت استعمال هذه الدالة.
واستعمال البرنامج بأقصى إمكانياته بتفعيل جميع الخيارات وضعت البرنامج تحت مراقبه برنامج perform اللذي يأتي مع الويندوز لمراقبة أداء الكومبيوتر وموارده. ومراقبة private bytes لبرنامج لاكتشاف أذا كان هناك أي تسرب بالذاكرة memory leak.

جميل ......كل شي يعمل كالساعة. تك تك تك .
وضعته تحت التشغيل الفعلي بعد التأكد من أن كل شيء يعمل كما هو مصمم عليه.

وفي يوم من الأيام اتصل على (احد مستخدمين البرنامج) يخبرني أن البرنامج عمل خروج فجأة. فسألته إذا عمل شي معين قبل أن يتوقف البرنامج. فقال انه لم يكن امامه وإنما اكتشف إن البرنامج لم يكن شغال.
ذهبت الى الموقع. وقمت اولاً بفحص الكومبيوتر. فلم احصل على شيء. لان كل شيء سليم ولا يوجد هناك أي شيء بالنظام نفسه. وفحصت Event Viewer ووجدت رسالة الخطأ رقم 4009 ثم فحصت اللوق ووجدت رساله الخطأ لبرنامج drwtsn وهي C0000025 ، وبدراسه رسالة الخطأ هذه عرفت ان معنها unrecoverable error يعني حتى الويندوز لا تحددها بالشكل السليم. !!
طيب.
قمت بتشغيل البرنامج ورجعت لمكتبي وقمت بتشغيل البرنامج أيضا على احد الكومبيوترات لفحص، وتركته يعمل، يوم، يومان........ثلاثة........25 يوم ، وفجأة اتصل علي المستخدم وقال لي نفس الشيء قد حدث؟ وقمت فألقيت نظره على الكومبيوتر الذي عندي في المكتب حيث وضعت كومبيوتر لفحص البرنامج وقد تفاجأ ت إذا رأيته هو أيضا قد عمل خروج .اممممم اذا ليس السبب من نظام التشغيل. لان النظامان يختلفان (win2000,winXP) ولكن المشترك بينهم هو البرنامج والمدة.!! امممم لماذا 25 يوم بالضبط تقريبا؟!!!!!!
فبحثت بالانترنت إلى أي شي قريب من هذا؟ وهل هذه المشكلة أوالظاهرة لها علاقة بال memory fragmentation . ولكن لا شي أبداً قريب من هذا.
ولكنى متاكد انها ليس من الذاكرة لأني اتخذت احتياطاتي لدرجه لا تتصورون . والمشكلة الأخرى أنها تحتاج 25 يوم لفحص، أي إذا غيرت شي بالبرنامج لفحصه أنت تحتاج إلى 25 يوم لترى النتيجة.
لقد جلست أيام احك راسي واكلم نفسي. كيف يكون الحل، وأين تكمن المشكلة . أريد بداية الخيط .وأنا متأكد إني لا استعمل أي كائن لم اصنعه، إلا واحد وهذا open source كما ذكرت سابقا.
وبدأت احسب 25 يوم ماذا يساوي بالساعات 600 ساعة.
طيب 25 يوم * 24 ساعة *60 دقيقه =36000 دقيقه .
وبالثواني 2160000 ثانيه
ألم تلاحظون شيء غريب؟
أن الأرقام سحريه؟ أي أنها كلها تنتهي بصفر(وانها ارقام معروفه؟ او قد مرت عليك من قبل)
اممممم على ماذا يدل هذا؟ وبدأ المشوار..........قليلا قليلا والتفكير يتصاعد الى القمة وعملية شحذ المخ في اقصاها. وأنا في قمة التركيز تذكرت شيء؟ رقم سحري أخر وهو 49.7 يوم لويندوز؟
نعمممممممممممم.................49.7 / 2= 24.85 وصرخت بقوه اهااااااااااااااااااا
الرقم السحري الاول:
اتعرفون ماهو 49.7 يوم لوندوز.؟ اقول لكم القصة من البداية.
هناك دالة اسمها GetTickCount

وهذه الدالة عندما تناديها ترجع لك رقم (32 بت) يمثل بالملى ثانيه وهو زمن تشغيل الويندوز (او الكومبيوتر بالأحرى) وهذا الرقم يبدأ بالصفر عند تشغيل الويندوز (او الكومبيوتر) وهو يمثل عداد داخل الكومبيوتر(RTC) ، أي أن أقصى حد ممكن تمثله بالرقم 32 بت هو 4294967295
اي 4294967295 م ث وبتحويل هذا الرقم الى أيام يصبح 49.7 يوم وبعد أن يصل العداد إلى أقصى حد له يبدأ من الصفر مره اخرى (أي يصفرReset). ولكن........ما علاقة بين هذا و25 يوم.
كما بينت ان القيمه 25 يوم تمثل نصف العدد 49.7 تقريباً.

أذا هل انا استعمل الدالة هذه (GetTickCount) في البرنامج؟
والاجابة نعم استعملها في دالة تاخير Delay.

الرقم السحري الثاني:
هو 7FFFFFFF
نعم انه الرقم الذي يمثل longint او integer
2147483647..2147483648-
أو بالأحرى نصف الرقم (4294967295) وهو (2147483647)
الم تلاحظوا معي إن الرقم (2147483647) و (2160000)- انظر فوق كيف حصلنا عليه-قريبين من بعض.
عندما يصل العد الى أقصى حد ممكن تمثيله في integer بالموجب هو 2147483647 وهو ما يمثل 7FFFFFFF فأذا زدنا واحد يصبح الرقم 7FFFFFFF+1=80000000
80000000 هذا يمثل الرقم بالسالب =-1
لنفرض ان عندك هذا


Integer
x:=GetTickCount


إذا كانت الويندوز شغال اقل من 25 يوم هذا الرقم موجب!
وعندما تكون الويندوز شغال لمدة أكثر من 25 يوم هذا الرقم بالسالب. اكس سوف تصبح بالسالب.

عملية التنقيح والفحص:
بعد أن ذكرت سابقا من أن بداية حل المشكلة قد ظهر. ولكن حتى يكون الحل وتقديم تقرير عن المشكلة، الحدس لايكفي. ولا التفكير المنطقي يثبت شيء. لذالك وجب على أن اثبت المشكلة عن طريق المحاكاة (simulation ) أي أن اعمل المشكلة. لذالك انصب الحل الأول على أن أجعل البرنامج يتصرف كأنه قد مر على زمن التشغيل 25 يوماً.
وهنا السؤال كيف؟
الفكرة الأولى:
عملت دالة اسمها GetTickCountX وهذه الدالة تنادي الدالة الأصلية GetTickCount وتضيف على القيمة مقدار 25 يوم ناقص خمس دقائق. كما هو موضح بالصورة




ولكن لأسف لم تنجح؟ والسبب أن استدعاء دالة API ليس مثل استدعاء دالة من داخل برنامجك؟ هذا ما توصلت له. ثم قلت لنفسي سوف أستدعيها من DLL وعملت الدالة داخلDLL ولكن أيضا لم تحدث المشكلة والبرنامج استمر بالعمل طبيعي؟.
بداء الشك يدخل تفكيري.ربما اني أفكر بمشكلة ليست هي الأساس؟. ...والزمن يمر؟ والتقرير يجب أن يرفع بأقرب وقت. ولا أريد أن أضع التقرير بحل ليس أكيد. او ربما يكون خاطئ.
وقلت لنفسي يجب أن احصل على طريقة أخرى افحص بها . يجب ان انقح الويندوز!!! نعم يجب ان اتبع الدالة GetTickCount .
وهنا اعرف أن هناك منقح ويندوز من ماكروسوفت windbg وقمت بتنزيل أخر نسخه وقمت بتذكر كيف استخدمه لان النسخة القديمة command prompt وليس GUI عموما ما هي إلا سويعات والمنقح شغال.
قمت بتشغيل برنامجي تحت المنقح. ثم قمت بتنقيح Kernel32.dll والتي تحتوي على GetTickCount

u kernel32!GetTickCount

هذا الأمر unasm سوف يعرض الاسمبلي كود ومنها اعرف عنوان خروج الدالة وعندها سوف أضع نقطة التوقف
عنوان خروج الدالة هو 7c8092ba
نضع الأمر التالي نقطه توقف

"bp 7c8092ba "reax=@eax+0x7FFFFFF0;reax;g

و g في أخر الأمر هو معناها go أي اشتغل.




هذا الأمر يجعل القيمة المرجعة من الدالة في مسجل eax ما قيمته

Result= 2147483632 + current counter value

أي مجموع GetTickCount الفعلي مع القيمة المضافة.
وانتظرت قليلاً وإذا بالبرنامج يعمل خروج.
فارتسمت على محياي (حلوة هذه محياي) علامات الرضا. (أمس شاهدت فلم عنترة والظاهر انه اثرعلي)

وفحصت drwtsn لوق ووجدت نفس رقم الخطأ . هنا تأكدت من الحل ومن أسباب المشكلة.
فقمت بكتابة التقرير عن المشكلة وأسبابها. وذكرت اسباب المشكلة بالتفصيل مع ذكر ان سببها الرئيسي هو المبرمج بالأساس (أنا) flaw in programming ثم قمت بتصليح الخطأ وهو بسيط تغير قيمة integer إلى cardinal وقمت أيضا بتحسين عمل Delay بحيث لو وصل العد إلى 47.9 لا يدخل في لوب غير منتهي.
نلاحظ من حل المشكلة الأتي:
ليس أن يكون برنامج 100% شغال ولكن هناك ثغرات ربما تحدث بعد وقت معين. لذالك يجب أن تفحص برنامجك بتغير الوقت والتاريخ وكذالك بجعل البرنامج يشتغل أطول مدة ممكنة .
أيضا مهما يكون المبرمج متمكن هناك هفوات ربما يقع فيها اعتى المبرمجين (حلوة هذه أعتى أقولكم أن فلم عنترة اثر علي بجد).
كذالك لاحظت أن الويندوزتتعامل مع Kernel call بطريقة تختلف عن روتين داخل برنامج أو dll خاص.
ارجوا أن تكون هذه المقالة مفيدة.


xlogic

هناك تعليق واحد:

غير معرف يقول...

I Like Your Way To Analyze and To Explain The Problem Domain