Obteniendo Git para Windows bajo ReactOS

Buen dia a todos! imagen


Mi nombre es Stanislav y me gusta escribir c贸digo. Este es mi primer art铆culo sobre Habr茅, por el cual varios factores me llevaron a escribir:



Perm铆tanme presentarles a los h茅roes de esta celebraci贸n (un error corregido que impidi贸 el lanzamiento de Git en ReactOS): el desarrollador franc茅s Herm猫s B茅lusca-Ma茂to (en adelante, simplemente Hermes, con el apodo hbelusca ), y en realidad yo (con el apodo x86corez ).


La historia comienza con los siguientes mensajes del canal IRC de desarrolladores de ReactOS:


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

Debriefing


Dado que actualmente ReactOS apunta a la compatibilidad con Windows Server 2003, se eligi贸 Git versi贸n 2.10.0 como el conejo experimental, el 煤ltimo que afirma ser compatible con Windows XP y 2003.


Las pruebas se realizaron en la l铆nea de comandos de ReactOS, los s铆ntomas externos del problema fueron bastante mixtos. Por ejemplo, al iniciar git sin especificar argumentos adicionales, sin ning煤n problema muestra informaci贸n de ayuda en la consola. Pero vali贸 la pena probar git clone o al menos git --version , en la mayor铆a de los casos la consola no mostr贸 nada en absoluto, u ocasionalmente mostr贸 un mensaje roto con afirmaci贸n:


 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. 

Fue muy 煤til investigar el problema de que el cliente git era de c贸digo abierto, y encontrar la l铆nea en la que ocurri贸 la excepci贸n no fue dif铆cil: https://github.com/git-for-windows/git/blob/4cde6287b84b8f4c5ccb4062617851a2f3d7fc78/exec_cm. c # L23


 char *system_path(const char *path) { /*  */ #ifdef RUNTIME_PREFIX assert(argv0_path); //    assert(is_absolute_path(argv0_path)); /*  */ #endif strbuf_addf(&d, "%s/%s", prefix, path); return strbuf_detach(&d, NULL); } 

Y el valor de la variable argv0_path establecido por esta secci贸n de c贸digo:


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

Despu茅s de aclarar estos detalles, me di de baja en el canal 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! 

El nombre de la variable, por as铆 decirlo, sugiere que el valor se obtuvo de argv[0] , generalmente en el 铆ndice cero de esta matriz contiene una cadena con el nombre del comando con el que se llam贸 al programa actual. Pero en el futuro, todo no era tan obvio ...


 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) 

Ir a la acci贸n


Despu茅s de eso, decid铆 compilar git desde la fuente para que fuera m谩s f谩cil "sobre la marcha" mostrar los valores de las variables de inter茅s directamente en la consola. Seleccion茅 este manual paso a paso , y para construir una versi贸n compatible eleg铆 esta rama: https://github.com/git-for-windows/git/tree/v2.10.0-rc2


La configuraci贸n de la cadena de herramientas mingw32 fue sencilla y comenc茅 la compilaci贸n. Pero tales manuales paso a paso a menudo tienen dificultades indocumentadas, e inmediatamente me encontr茅 con uno de ellos:


imagen


A trav茅s de prueba y error, adem谩s de utilizar indicaciones de la audiencia (canal IRC), se resolvieron todos los problemas de compilaci贸n. Si alguien quiere repetir mi camino, comparto el diff listo para una compilaci贸n exitosa: https://pastebin.com/ZiA9MaKt


Para eliminar la influencia de muchas funciones durante la inicializaci贸n, decid铆 mostrar varios mensajes de depuraci贸n justo al comienzo de la funci贸n main() , que en el caso de git se encuentra en el archivo common-main.c :


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

La conclusi贸n fue la siguiente:


 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 ! ( ,    ) 

Parece que todo est谩 bien, argv[0] deber铆a ser as铆. La idea surgi贸 para ejecutar git dentro del depurador, por ejemplo en OllyDbg, pero algo sali贸 mal ...


 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 

隆Y aqu铆 Sanchez sugiri贸 una gran idea que arroja luz sobre muchas cosas!


imagen


No hubo m谩s excepciones, y git imprimi贸 con 茅xito su n煤mero de versi贸n.


 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. 

Las cosas se despegaron, y decid铆 intentar diferente ejecutar git en la l铆nea de comando, 隆y no perd铆!


imagen


El problema era claramente que git esperaba la ruta completa en la l铆nea de comando. Luego decid铆 verificar qu茅 datos se mostrar谩n en Windows. Los resultados me sorprendieron un poco.


imagen


Por alguna raz贸n, la variable argv[0] ten铆a la ruta completa a la aplicaci贸n.


 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 sugiri贸 verificar si podr铆a haber un problema en alg煤n lugar de la l铆nea de comandos de ReactOS ...


imagen


Pero ese no fue el caso. La opci贸n de shell cmd desaparece.


 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. 

Ahora todo lo que quedaba era probar la biblioteca msvcrt.dll de ReactOS para Windows. Trat茅 de poner el archivo en el mismo directorio donde estaba git.exe, pero esto no ayud贸. Mark sugiri贸 una manera con un archivo .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 

Pero por alguna raz贸n, esta opci贸n tampoco funcion贸. Quiz谩s el hecho de que realic茅 todos los experimentos en la versi贸n del servidor de Windows Server 2008 R2 afect贸.


Hermes sugiri贸 la 煤ltima idea:


 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! 

Usando WinHex, reemplac茅 todas las apariciones de la subcadena msvcrt en el archivo msvcrd con msvcrd , y renombr茅 msvcrt.dll de ReactOS en consecuencia, y esto es lo que sucedi贸:


imagen


 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) 

隆Ahora en Windows, recibimos el mismo mensaje de error! Esto significa que la fuente del problema es la implementaci贸n de una de las funciones msvcrt de ReactOS.


Tambi茅n se puede observar que en Windows el texto de excepci贸n se muestra correctamente.


 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 

Solo quedaba averiguar qu茅 funci贸n en msvcrt proporciona la ruta completa al archivo ejecutable de la aplicaci贸n en ejecuci贸n. Buscando en Google un poco, suger铆 que el punto est谩 en la funci贸n _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 envi贸 un enlace al parche, lo apliqu茅 manualmente y reconstru铆 el sistema, 隆despu茅s de lo cual todo funcion贸 m谩gicamente como deber铆a!


imagen


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

Ep铆logo


Por lo tanto, otro error que obstaculiz贸 indirectamente el autoensamblaje de ReactOS dentro de ReactOS se solucion贸 mediante esfuerzos colectivos. Una coincidencia graciosa es el hecho de que poco antes se solucion贸 otro error en el mismo msvcrt (es decir, en la funci贸n qsort ), que no permit铆a ensamblar controladores USB en ReactOS.


Participo en el desarrollo de muchos proyectos escritos en diferentes lenguajes de programaci贸n, tanto de c贸digo cerrado como de c贸digo abierto. He estado trabajando con el proyecto ReactOS desde 2014, pero comenc茅 a ayudar activamente y escribir c贸digo solo en 2017. 隆Es especialmente interesante trabajar en esta 谩rea, porque es un sistema operativo completo! 隆Uno siente la enorme escala del resultado, en la que se invirtieron los esfuerzos, as铆 como la agradable sensaci贸n de que un error se volvi贸 menos! :)


Alguien probablemente se preguntar谩 por qu茅 ayudo a ReactOS, y no a Linux, por ejemplo. Sucedi贸 hist贸ricamente que en la mayor铆a de los casos escribo programas para Windows, y mi lenguaje de programaci贸n favorito es Delphi. Quiz谩s es por eso que la arquitectura de Windows NT, junto con la API Win32, es muy interesante para m铆, y el proyecto del sistema operativo gratuito ReactOS hace realidad un viejo sue帽o: en la pr谩ctica, le permite descubrir c贸mo funciona todo desde adentro.


Espero que les haya resultado interesante leer mi primer art铆culo aqu铆. Espero sus comentarios!


Referencias


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


All Articles