يوم جيد لك! 
اسمي ستانيسلاف وأحب كتابة الكود. هذه مقالتي الإنجليزية الأولى عن هبر التي صنعتها لأسباب عديدة:
هذه المقالة هي نسخة إنجليزية من مقالي الأول عن الروسية.
اسمحوا لي أن أقدم الشخصيات الرئيسية في هذه القصة التي أصلحت بالفعل الخطأ الذي يمنع Git من الترشح في ReactOS - المطور الفرنسي Hermès Bélusca-Maïto (أو مجرد Hermes باسم hbelusca
) وبالطبع أنا (مع x86corez
اللقب).
تبدأ القصة بالرسائل التالية من قناة ReactOS Development IRC:
Jun 03 18:52:56 <hbelusca> Anybody want to work on some small problem? If so, can someone figure out why this problem https://jira.reactos.org/browse/CORE-12931 happens on ReactOS? :D Jun 03 18:53:13 <hbelusca> That would help having a good ROS self-hosting system with git support. Jun 03 18:53:34 <hbelusca> (the git assertion part only).
استخلاص المعلومات
نظرًا لأن النظام الأساسي المستهدف ReactOS هو Windows Server 2003 ، فقد تم اختيار الإصدار 2.10.0 من Git للتحقيق - إنه الأخير الذي يدعم Windows XP و 2003.
تم إجراء الاختبار في موجه أوامر ReactOS ، وكانت الأعراض الخارجية للمشكلة غامضة إلى حد ما. على سبيل المثال ، عند تشغيل git بدون معلمات إضافية ، فإنه يعرض رسالة المساعدة في وحدة التحكم دون أي مشاكل. ولكن بمجرد محاولة git clone
أو حتى git --version
في معظم الحالات ، تظل وحدة التحكم فارغة فقط. من حين لآخر عرض رسالة مقطوعة بتأكيد:
git.exe clone -v "https://github.com/minoca/os.git" "C:\Documents and Settings\Administrator\Bureau\minocaos" A ssertionfailed ! P rogram : C : \ P rogram F iles \ G it \ mingw 3 2 \ bin \ git . exe F ile : exec _ cmd . c , L ine 2 3 E xpression : argv 0 _ path This application has requested the Runtime to terminate in an unusual way. Please contact the application's support team for more information.
لحسن الحظ ، git هو مشروع مفتوح المصدر ، وقد ساعد كثيرًا في تحقيقنا. لم يكن من الصعب للغاية تحديد موقع الكود الفعلي حيث حدث استثناء غير معالج: https://github.com/git-for-windows/git/blob/4cde6287b84b8f4c5ccb4062617851a2f3d7fc78/exec_cmd.c#L23
char *system_path(const char *path) { /* snip */ #ifdef RUNTIME_PREFIX assert(argv0_path); // it asserts here assert(is_absolute_path(argv0_path)); /* snip */ #endif strbuf_addf(&d, "%s/%s", prefix, path); return strbuf_detach(&d, NULL); }
ويتم تعيين قيمة متغير argv0_path
بواسطة هذا الرمز:
const char *git_extract_argv0_path(const char *argv0) { const char *slash; if (!argv0 || !*argv0) return NULL; slash = find_last_dir_sep(argv0); if (slash) { argv0_path = xstrndup(argv0, slash - argv0); return slash + 1; } return argv0; }
بمجرد حصولي على كل هذه المعلومات ، قمت بإرسال بعض الرسائل إلى قناة IRC:
Jun 03 19:04:36 <x86corez> hbelusca: https://github.com/git-for-windows/git/blob/4cde6287b84b8f4c5ccb4062617851a2f3d7fc78/exec_cmd.c#L23 Jun 03 19:04:41 <x86corez> assertion is here Jun 03 19:04:57 <hbelusca> yes I know, I've seen the code yesterday. The question is why it's FALSE on ROS but TRUE on Windows. Jun 03 19:06:02 <x86corez> argv0_path = xstrndup(argv0, slash - argv0); Jun 03 19:06:22 <x86corez> xstrndup returns NULL %-) Jun 03 19:06:44 <hbelusca> ok, so what's the values of argv0 and slash on windows vs. on ROS? :P Jun 03 19:08:48 <x86corez> good question!
يشير اسم المتغير إلى أن القيمة الفعلية مشتقة من argv[0]
- عادة ما تحتوي على الاسم القابل للتنفيذ في فهرس الصفر. ولكن بعد كل شيء لم يكن واضحا جدا ...
Jun 03 20:15:21 <x86corez> hbelusca: surprise... git uses its own xstrndup implementation Jun 03 20:15:35 <x86corez> so I can't simply hook it xD Jun 03 20:15:56 <hbelusca> well, with such a name "xstrndup" it's not surprising it's its own implementation Jun 03 20:16:04 <x86corez> probably I would need an user-mode debugger... like OllyDbg Jun 03 20:16:09 <hbelusca> that's everything but standardized function. Jun 03 20:16:24 <hbelusca> x86corez: ollydbg should work on ROS. Jun 03 20:16:30 <mjansen> what are you breaking today? Jun 03 20:16:44 <x86corez> mjansen: https://jira.reactos.org/browse/CORE-12931 Jun 03 20:16:51 <hbelusca> (of course if you also are able to compile that git with symbols and all the stuff, it would be very nice)
العمل
بعد ذلك قررت تجميع بوابة مباشرة من المصدر ، لذلك سأكون قادرًا على طباعة متغيرات الاهتمام "سريعًا" مباشرة على وحدة التحكم. لقد تابعت هذا البرنامج التعليمي خطوة بخطوة ومن أجل تجميع إصدار git المتوافق ، اخترت هذا الفرع: https://github.com/git-for-windows/git/tree/v2.10.0-rc2
تم إعداد toolchain mingw32 بسلاسة وبدأت للتو في الإنشاء. ومع ذلك ، توجد دائمًا عيوب غير موثقة في هذه البرامج التعليمية خطوة بخطوة ، وقد صادفت أحدها على الفور:

من خلال التجربة والخطأ ، وكذلك استخدام تلميحات من القاعة (قناة IRC) ، تم إصلاح جميع أخطاء وقت الترجمة. إذا أراد شخص ما اتباع خطواتي ، فإليك الفرق الذي يجعل المترجم سعيدًا: https://pastebin.com/ZiA9MaKt
من أجل تجنب استدعاء وظائف متعددة أثناء التهيئة ولإعادة إنتاج الأخطاء بسهولة ، قررت أن أضع عدة مطبوعات تصحيح صحيحة في بداية الوظيفة main()
، والتي توجد في common-main.c
في حالة git:
int main(int argc, const char **argv) { /* * Always open file descriptors 0/1/2 to avoid clobbering files * in die(). It also avoids messing up when the pipes are dup'ed * onto stdin/stdout/stderr in the child processes we spawn. */ //DebugBreak(); printf("sanitize_stdfds(); 1\n"); sanitize_stdfds(); printf("git_setup_gettext(); 1\n"); git_setup_gettext(); /* * Always open file descriptors 0/1/2 to avoid clobbering files * in die(). It also avoids messing up when the pipes are dup'ed * onto stdin/stdout/stderr in the child processes we spawn. */ printf("sanitize_stdfds(); 2\n"); sanitize_stdfds(); printf("git_setup_gettext(); 2\n"); git_setup_gettext(); printf("before argv[0] = %s\n", argv[0]); argv[0] = git_extract_argv0_path(argv[0]); printf("after argv[0] = %s\n", argv[0]); restore_sigpipe_to_default(); printf("restore_sigpipe_to_default(); done\n"); return cmd_main(argc, argv); }
لقد حصلت على الإخراج التالي:
C:\>git --version sanitize_stdfds(); 1 git_setup_gettext(); 1 sanitize_stdfds(); 2 git_setup_gettext(); 2 before argv[0] = git after argv[0] = git restore_sigpipe_to_default(); done A ssertionfailed ! (cutted a part of error message which is the same as the one above)
يمكن للمرء أن يفترض أن كل شيء على ما يرام هنا ، قيمة argv[0]
صحيحة. لدي فكرة لتشغيل git داخل المصحح ، OllyDbg على سبيل المثال ، ولكن حدث خطأ ما ...
Jun 04 01:54:46 <sanchaez> now please try gdb/ollydbg in ROS Jun 04 01:58:11 <sanchaez> you have gdb in RosBE Jun 04 01:58:20 <sanchaez> just in case :p Jun 04 01:59:45 <x86corez> ollydbg says "nope" with MEMORY_MANAGEMENT bsod Jun 04 02:00:07 <x86corez> !bc 0x0000001A Jun 04 02:00:08 <hTechBot> KeBugCheck( MEMORY_MANAGEMENT ); Jun 04 02:00:13 <hbelusca> :/ Jun 04 02:00:49 <sanchaez> welp Jun 04 02:00:56 <sanchaez> you only have one option now :D
وهنا اقترح سانشيز فكرة ممتازة تلقي الضوء على أشياء كثيرة!

التأكيد لم يعد يحدث ، وحصلت بوابة طباعته بنجاح.
Jun 04 02:23:40 <x86corez> it prints! Jun 04 02:23:44 <x86corez> but only in gdb Jun 04 02:23:53 <hbelusca> oh Jun 04 02:24:00 <hbelusca> C:\git/git.exe Jun 04 02:24:13 <hbelusca> I wonder whether it's the same in windows, or not.
انتقلت القضية من مركز ميت ، وحاولت طرق مختلفة لتشغيل بوابة في موجه الأوامر ، والعثور على الطريق الصحيح!

كانت المشكلة بوضوح أن بوابة توقع المسار الكامل على سطر الأوامر. لذلك قارنت انتاجها التصحيح على ويندوز. النتائج فاجأتني قليلاً.

لسبب ما احتوى قيمة argv[0]
على المسار الكامل لثنائي git.exe.
Jun 05 23:01:44 <hbelusca> x86corez: can you try to run git also by not using cmd.exe? Jun 05 23:02:05 <hbelusca> (to exclude the possibility it's cmd that doesn't call Createprocess with a complete path) Jun 05 23:02:09 <hbelusca> while I think it should... Jun 05 23:02:30 <x86corez> not using cmd... moment Jun 05 23:02:55 <hbelusca> x86corez: alternatively, on windows, try starting git using our own cmd.exe :)
اقترح هيرميس التحقق مما إذا كان ReactOS cmd.exe مكونًا مذنبًا هنا ...

لكن لقطة الشاشة هذه أكدت أن المشكلة الفعلية في مكان آخر.
Jun 05 23:04:38 <x86corez> ROS cmd is not guilty Jun 05 23:07:57 <hbelusca> If there was a possibility to consult the received path, before looking at the contents of argvs... ? Jun 05 23:08:30 <x86corez> dump contents of actual command line? Jun 05 23:08:39 <hbelusca> yeah Jun 05 23:09:39 <hbelusca> The thing you retrieve using GetCommandLineW Jun 05 23:10:03 <hbelusca> (which is, after simplifications, basically : NtCurrentPeb()->ProcessParameters->CommandLine ) Jun 05 23:10:59 <hbelusca> Also I was thinking it could be a side-effect of having (or not having) git path into the env-vars.... Jun 05 23:12:17 <x86corez> hbelusca, command line is "git --version" Jun 05 23:12:34 <hbelusca> Always? Jun 05 23:12:39 <x86corez> Yes, even on Windows Jun 05 23:15:13 <hbelusca> ok but then it would be nice if these different results are at least the same on Windows and on ROS, so that we can 100% exclude problems outside of msvcrt.
كان الخيار الأخير لاختبار ReactOS msvcrt.dll في نظام التشغيل Windows. حاولت وضع الملف في نفس الدليل حيث يوجد git.exe ، لكنه لم يساعد. اقترح مارك إضافة ملف .local:
Jun 05 22:59:01 <mjansen> x86corez: add .local file next to msvcrt.dll ;) Jun 05 22:59:47 <mjansen> exename.exe.local Jun 05 23:00:17 <x86corez> just an empty file? Jun 05 23:00:21 <mjansen> yea Jun 05 23:00:49 <hbelusca> mjansen: do we support these .local files? Jun 05 23:00:52 <mjansen> we dont Jun 05 23:00:54 <mjansen> windows does Jun 05 23:15:48 <x86corez> moment... I'll try with .local Jun 05 23:18:43 <x86corez> mjansen: I've created git.exe.local but it still doesn't load msvcrt.dll in this directory
لكن لسبب ما لم تنجح هذه الطريقة أيضًا. ربما حقيقة أنني فعلت كل التجارب على إصدار خادم ويندوز (2008 R2).
اقترح هيرميس الفكرة الأخيرة:
Jun 05 23:19:28 <hbelusca> last solution: patch "msvcrt" name within git and perhaps other mingwe dlls ^^ Jun 05 23:20:12 <x86corez> good idea about patching!
لذلك استبدلت كل تكرارات msvcrt في git.exe بـ msvcrd
باستخدام WinHex ، msvcrd
تسمية ReactOS msvcrt.dll وفقًا لذلك ، وهنا نحن:

Jun 05 23:23:29 <x86corez> Yes! guilty is msvcrt :) Jun 05 23:25:37 <hbelusca> ah, so as soon as git uses our msvcrt we get the problem on windows. Jun 05 23:25:38 <x86corez> hbelusca, mjansen, https://image.prntscr.com/image/FoOWnrQ4SOGMD-66DLW16Q.png Jun 05 23:25:58 <hbelusca> aha and it asserts <3 Jun 05 23:26:03 <hbelusca> (it shows the assertion now)
أصبح خطأ الآن نحن ضرب نفس التأكيد ، ولكن في ويندوز! وهذا يعني أن مصدر مشاكلنا هو في واحدة من وظائف ReactOS msvcrt.
تجدر الإشارة أيضًا إلى أن رسالة التأكيد يتم عرضها بشكل صحيح في Windows.
Jun 05 23:26:13 <x86corez> but it prints text and correctly. Jun 05 23:26:20 <hbelusca> oh Jun 05 23:26:33 <x86corez> and on ROS it doesn't print in most cases xD Jun 05 23:26:38 <hbelusca> so also it excludes another hypothesis, namely that it could have been a bug in our msvcrt/crt Jun 05 23:26:56 <hbelusca> So possibly a strange bug in our console
لذلك ، لحل المشكلة الفعلية ، كان علينا العثور على وظيفة API في msvcrt والتي تعطي المسار الكامل للتطبيق الحالي. غوغلد قليلا وافترض أن المشكلة _pgmptr
وظيفة _pgmptr
.
Jun 06 00:07:43 <x86corez> https://msdn.microsoft.com/en-us/library/tza1y5f7.aspx Jun 06 00:07:57 <x86corez> When a program is run from the command interpreter (Cmd.exe), _pgmptr is automatically initialized to the full path of the executable file. Jun 06 00:08:01 <x86corez> this ^^) Jun 06 00:08:50 <hbelusca> That's what GetModuleFileName does. Jun 06 00:09:04 <x86corez> yeah Jun 06 00:10:30 <hbelusca> Of course in ROS msvcrt we don't do this, but instead we initialize pgmptr to what argv[0] could be. Jun 06 00:11:08 <hbelusca> That's one thing. Jun 06 00:11:34 <hbelusca> The other thing is that nowhere it appears (in MS CRT from VS, or in wine) that argv is initialized using pgmptr. Jun 06 00:13:33 <x86corez> hbelusca, I've checked argv[0] in some ROS command line tools, running them in Windows Jun 06 00:13:56 <x86corez> they all interpret argv[0] as command line, not full path Jun 06 00:14:04 <x86corez> so... I think it's git specific behaviour Jun 06 00:14:16 <x86corez> or specific mingw compiler settings Jun 06 00:28:12 <hbelusca> x86corez: I'm making a patch for our msvcrt, would be nice if you could test it :) Jun 06 00:28:21 <x86corez> I'll test it
أرسل هيرميس رابطًا إلى التصحيح ، وقمت بتطبيقه يدويًا وإعادة بناء النظام ، وبعد هذه التحركات اختفت المشكلة الأصلية بطريقة سحرية!

Jun 06 00:34:26 <x86corez> hbelusca, IT WORKS! Jun 06 00:35:10 <hbelusca> LOL Jun 06 00:35:18 <hbelusca> So it seems that something uses pgmptr to rebuild an argv. Jun 06 00:35:52 <x86corez> I've even able to clone :) Jun 06 00:36:19 <hbelusca> \o/ Jun 06 00:36:21 <gigaherz> 2.10.0-rc2? not the release? Jun 06 00:36:24 <hbelusca> ok I'm gonna commit that stuff. Jun 06 00:36:43 <hbelusca> x86corez: gonna have ROS self-hosting <33 Jun 06 00:36:48 <x86corez> yeah! Jun 06 00:37:01 <x86corez> gigaherz: I've built that from sources Jun 06 00:37:37 <gigaherz> oh, for testing this bug? o_O Jun 06 00:37:50 <sanchaez> yes, you missed the fun :p Jun 06 00:39:46 <x86corez> git 2.10.0-windows.1 (release) works too! Jun 06 00:39:54 <encoded> commit!!!
خاتمة
ومع ذلك ، تم إصلاح خطأ آخر يمنع بشكل غير مباشر ReactOS من بناء نفسه بفضل الجهود الجماعية. المصادفة المضحكة هي حقيقة أنه قبل فترة طويلة من إصلاح الخلل في نفس المكتبة الديناميكية qsort
(أي في وظيفة qsort
) التي لم تسمح لتجميع برامج تشغيل USB في ReactOS.
أشارك في تطوير العديد من المشاريع المكتوبة بلغات برمجة مختلفة ، مفتوحة المصدر ومفتوحة المصدر. أنا أساهم في مشروع ReactOS منذ عام 2014 ، لكنني بدأت بالمساعدة بنشاط وكتابة الكود فعليًا فقط في عام 2017. من المثير للاهتمام بشكل خاص العمل في هذا المجال لأنه نظام تشغيل كامل! تشعر بمقياس هائل للنتيجة التي استثمرت فيها الجهود ، بالإضافة إلى شعور لطيف بوجود خطأ أقل! :)
قد يتساءل شخص ما لماذا أساهم في ReactOS وليس Linux على سبيل المثال. لذلك ، تاريخياً في معظم الحالات ، أكتب البرامج الخاصة بنظام Windows ولغتي البرمجية المفضلة هي دلفي. ربما هذا هو السبب في أن هندسة Windows NT مع Win32 API مثيرة للغاية بالنسبة لي ، ومشروع ReactOS الخاص ببديل Windows المجاني يجعل الحلم القديم حقيقة واقعة - يتيح لك معرفة كيفية عمل كل شيء تحت غطاء محرك السيارة في الممارسة.
أتمنى أن تستمتعوا بمقالتي الإنجليزية الأولى هنا. أنا أتطلع إلى تعليقاتكم!
الروابط