Membuat Git untuk Windows berfungsi di ReactOS

Hari baik untukmu gambar


Nama saya Stanislav dan saya suka menulis kode. Ini adalah artikel bahasa Inggris saya yang pertama tentang Habr yang saya buat karena beberapa alasan:



Artikel ini adalah versi bahasa Inggris dari artikel pertama saya di Rusia.


Biarkan saya memperkenalkan tokoh-tokoh utama dalam cerita ini yang benar-benar memperbaiki bug yang mencegah Git berjalan di ReactOS - pengembang Perancis Hermès Bélusca-Maïto (atau hanya Hermes dengan nama panggilan hbelusca ) dan tentu saja saya (dengan nama panggilan x86corez ).


Kisah ini dimulai dengan pesan-pesan berikut dari saluran IRC ReactOS Development:


 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). 

Tanya jawab


Karena platform target ReactOS adalah Windows Server 2003, Git versi 2.10.0 dipilih untuk penyelidikan - ini adalah yang terakhir yang mendukung Windows XP dan 2003.


Pengujian dilakukan dalam Prompt Perintah ReactOS, gejala eksternal dari masalah agak ambigu. Misalnya, ketika Anda menjalankan git tanpa parameter tambahan, itu akan menampilkan pesan bantuan di konsol tanpa masalah. Tetapi begitu Anda mencoba git clone atau bahkan hanya git --version dalam banyak kasus konsolnya tetap kosong. Terkadang ditampilkan pesan yang rusak dengan penegasan:


 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. 

Untungnya git adalah proyek open source, dan itu banyak membantu dalam penyelidikan kami. Tidak terlalu sulit untuk menemukan blok kode aktual di mana pengecualian terjadi: 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); } 

Dan nilai variabel argv0_path diberikan oleh kode ini:


 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; } 

Setelah saya mendapatkan semua informasi ini, saya telah mengirim beberapa pesan ke saluran 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! 

Nama variabel menunjukkan bahwa nilai aktual berasal dari argv[0] - biasanya berisi nama yang dapat dieksekusi dalam indeks nol. Tapi kemudian semuanya tidak begitu jelas ...


 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) 

Aksi


Setelah itu saya memutuskan untuk mengkompilasi git langsung dari sumbernya, jadi saya akan dapat mencetak variabel yang menarik "langsung" ke konsol. Saya telah mengikuti tutorial ini selangkah demi selangkah dan untuk mengkompilasi versi git yang kompatibel, saya telah memilih cabang ini: https://github.com/git-for-windows/git/tree/v2.10.0-rc2


Menyiapkan mingw32 toolchain berjalan dengan lancar dan saya baru saja mulai membangun. Namun hampir selalu ada perangkap tidak berdokumen dalam tutorial langkah-demi-langkah seperti itu, dan saya langsung menemui salah satunya:


gambar


Melalui trial and error, serta menggunakan petunjuk dari aula (saluran IRC), semua kesalahan waktu kompilasi diperbaiki. Jika seseorang ingin mengikuti langkah saya, berikut adalah diff untuk membuat compiler senang: https://pastebin.com/ZiA9MaKt


Untuk menghindari memanggil beberapa fungsi selama inisialisasi dan mereproduksi bug dengan mudah, saya memutuskan untuk meletakkan beberapa cetakan debug tepat di awal fungsi main() , yang terletak di common-main.c dalam kasus 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); } 

Saya mendapat hasil sebagai berikut:


 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) 

Orang bisa menganggap semuanya baik-baik saja di sini, nilai argv[0] benar. Saya punya ide untuk menjalankan git di dalam debugger, OllyDbg misalnya, tetapi ada yang salah ...


 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 

Dan di sini sanchaez menyarankan ide bagus yang menjelaskan banyak hal!


gambar


Penegasan tidak lagi terjadi, dan git berhasil mencetak versinya.


 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. 

Kasing bergerak dari pusat mati, dan saya mencoba berbagai cara untuk menjalankan git di command prompt, dan menemukan jalan yang benar!


gambar


Masalahnya jelas bahwa git mengharapkan path lengkap pada baris perintah. Jadi saya membandingkan output debug pada Windows. Hasilnya sedikit mengejutkan saya.


gambar


Untuk beberapa alasan, nilai argv[0] berisi path lengkap ke biner 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 :) 

Hermes menyarankan untuk memeriksa apakah ReactOS cmd.exe adalah komponen yang bersalah di sini ...


gambar


Tapi tangkapan layar ini mengkonfirmasi bahwa masalah sebenarnya ada di tempat lain.


 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. 

Opsi terakhir adalah untuk menguji ReactOS msvcrt.dll di Windows. Saya mencoba untuk menempatkan file di direktori yang sama di mana git.exe berada, tetapi tidak membantu. Mark menyarankan untuk menambahkan file .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 

Tetapi untuk beberapa alasan metode ini tidak berhasil juga. Mungkin fakta bahwa saya melakukan semua percobaan pada edisi server Windows (2008 R2).


Gagasan terakhir disarankan oleh Hermes:


 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! 

Jadi saya mengganti semua kemunculan msvcrt di git.exe dengan msvcrd menggunakan WinHex, dan mengganti nama ReactOS msvcrt.dll sesuai, dan di sini kita:


gambar


 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) 

bug menjadi Sekarang kami mencapai pernyataan yang sama, tetapi di Windows! Dan itu berarti sumber masalah kita ada di salah satu fungsi ReactOS msvcrt.


Perlu juga dicatat bahwa pesan pernyataan ditampilkan dengan benar di 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 

Jadi, untuk menyelesaikan masalah yang sebenarnya, kami harus menemukan fungsi API di msvcrt yang memberikan path lengkap dari aplikasi saat ini. Saya googled sedikit dan menganggap masalahnya adalah fungsi _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 

Hermes mengirim tautan ke tambalan, saya secara manual menerapkannya dan membangun kembali sistem, dan setelah ini memindahkan masalah asli secara ajaib menghilang!


gambar


 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!!! 

Kata penutup


Yang mengatakan, bug lain yang secara tidak langsung mencegah ReactOS dari membangun itu sendiri telah diperbaiki berkat upaya kolektif. Kebetulan lucu adalah fakta bahwa tidak lama sebelum bug lain diperbaiki di perpustakaan dinamis msvcrt yang sama (yaitu, dalam fungsi qsort ) yang tidak memungkinkan untuk mengkompilasi driver USB di ReactOS.


Saya berpartisipasi dalam pengembangan banyak proyek yang ditulis dalam berbagai bahasa pemrograman, baik sumber tertutup maupun sumber terbuka. Saya berkontribusi pada proyek ReactOS sejak 2014, tetapi saya mulai secara aktif membantu dan benar-benar menulis kode hanya pada 2017. Sangat menarik untuk bekerja di bidang ini karena ini merupakan sistem operasi keseluruhan! Anda merasakan skala besar dari hasil di mana upaya diinvestasikan, serta perasaan yang menyenangkan bahwa ada satu bug lebih sedikit! :)


Seseorang mungkin bertanya-tanya mengapa saya berkontribusi pada ReactOS dan bukan Linux misalnya. Jadi secara historis dalam kebanyakan kasus saya menulis program untuk Windows dan bahasa pemrograman favorit saya adalah Delphi. Mungkin itu sebabnya arsitektur Windows NT bersama-sama dengan Win32 API sangat menarik bagi saya, dan proyek ReactOS dari alternatif Windows gratis membuat impian lama menjadi kenyataan - ini memungkinkan Anda untuk mengetahui bagaimana semuanya berjalan di bawah tenda dalam prakteknya.


Saya harap Anda menikmati artikel bahasa Inggris pertama saya di sini. Saya menantikan komentar Anda!



Source: https://habr.com/ru/post/id439580/


All Articles