Solucion al crash en mame4all 0.37b5 para raspberry pi con 6 joysticks

Intentando configurar MAME en mi consola con RPI2 y retropie ( esta: http://heli.xbot.es/?p=365 ) con los joysticks /dev/input/js4 y /dev/input/js5 que son tipo PSX, veo que hay algún error en la distribución actual de mame 0.37b5.
Mame4all “casca” con “fallo de segmentación” (técnicamente es un “crash” con “segmentation fault”) cuando activo alguno de los botones de los joysticks, incluso aunque no estén configurados en el mame. Basta con tenerlos conectados y usarlos.

Gracias a que el software es de fuente abierta he podido analizar el código (es c y c++) y usando mis superpoderes de programador he conseguido encontrar el error y crear un parche que soluciona el problema.

En primer lugar es necesario descargar los sources actuales de mame4all para RPI.

Esta versión que distribuyen con retropie: https://github.com/RetroPie/mame4all-pi
Esta versión es un poco mas moderna, aunque solo tiene cambios precisamente en la gestión de joysticks de PSX, pero no solucionan mi problema:
https://sourceforge.net/p/mame4allpi/code/ci/master/tree/src/

Desde la RPI con conexión a internet hacer, como usuario pi desde su directorio personal:
git clone git://git.code.sf.net/p/mame4allpi/code mame4allpi-code

Esto creará un directorio “~/mame4allpi-code” con los fuentes actuales V0.37b5 a fecha de hoy (Octubre de 2016).
En “~/mame4allpi-code/src/rpi” se encuentran los dos ficheros que hay que modificar.
El problema se presenta porque se crea un array de 4 elementos para almacenar los datos de 4 joysticks. Un comentario en el código indica que solo se trabajará con 4 joysticks. Pero en una función posterior existe un bucle que rellena los arrays de datos de los joysticks. El buche tiene tantas interaciones como joysticks tenga el sistema (detectado mediante una llamada a la API). Entonces si esa llamada devuelve mas de 4 la función acaba escribiendo datos fuera del los arrays declarados.

En el fichero “minimal.cpp”, en la línea 140 se encuentra la función “int init_SDL(void)”
Voy a comentar los cambios necesarios y los problemas que problema el código original de “minimal.cpp”:
//SDL_Joystick* myjoy[4]; // Original: solo soporta 4 joysticks
SDL_Joystick* myjoy[6]; // Nuevo: Ahora tiene cabida para 6 joysticks

int init_SDL(void)
{
myjoy[0]=0;
myjoy[1]=0;
myjoy[2]=0;
myjoy[3]=0;
myjoy[4]=0; // Nuevo: Inicializar los nuevos elementos
myjoy[5]=0; // Nuevo: Inicializar los nuevos elementos

if (SDL_Init(SDL_INIT_JOYSTICK) < 0) {
fprintf(stderr, "Unable to init SDL: %s\n", SDL_GetError());
return(0);
}
sdlscreen = SDL_SetVideoMode(0,0, 16, SDL_SWSURFACE);

//We handle up to four joysticks
if(SDL_NumJoysticks)
{
int i;
SDL_JoystickEventState(SDL_ENABLE);

for(i=0;i<SDL_NumJoysticks;i++) { // Aqui estaba el problema, SDL_NumJoysticks() puede devolver mas de 4
myjoy[i]=SDL_JoystickOpen(i); // Pero solo habia mjoy[] para 4, si SDL_NumJoysticks() devuelve > 4 se escribe fuera del array!

Esto NO SOLUCIONA TODO EL PROBLEMA porque si el sistema tiene configurados mas de 6 joysticks estamos igual. Solo hemos actualizado el mame para que soporte 6 joysticks, pero cascará igual si hay mas.
La solución definitiva sería modifica la función “int init_SDL(void)” en minimal.cpp de forma que solo procese 6 joysticks independientemente del número de ellos que devuelva la llamada al sistema, así:
//We handle up to SIX joysticks
int NumJoysticks = SDL_NumJoysticks();

if (NumJoysticks > 6) NumJoysticks=6; // Ignoramos los demas joysticks
if(NumJoysticks)
{
int i;
SDL_JoystickEventState(SDL_ENABLE);
{
for(i=0;i<NumJoysticks;i++) { // Aqui estaba el problema,
myjoy[i]=SDL_JoystickOpen(i); // Ya no puede escribir escribe fuera del array!

A consecuencia de estos cambios también hay que modificar “input.cpp” para que pueda gestionar los nuevos joysticks:
En la línea 8:
unsigned long ExKey1=0;
unsigned long ExKey2=0;
unsigned long ExKey3=0;
unsigned long ExKey4=0;
unsigned long ExKey5=0; // Nuevo
unsigned long ExKey6=0; // Nuevo
unsigned long ExKeyKB=0;
// int num_joysticks=6; // Original: solo 4 joysticks
int num_joysticks=6; // Nuevo: ahora 6

En la función “void joyprocess(Uint8 button, SDL_bool pressed, Uint8 njoy)”
Uint32 val=0;
unsigned long *mykey=0;

if(njoy == 0) mykey = &ExKey1;
if(njoy == 1) mykey = &ExKey2;
if(njoy == 2) mykey = &ExKey3;
if(njoy == 3) mykey = &ExKey4;
if(njoy == 4) mykey = &ExKey5; // Nuevo
if(njoy == 5) mykey = &ExKey6; // Nuevo

y En la función “void gp2x_joystick_clear(void)”:

ExKey1=0;
ExKey2=0;
ExKey3=0;
ExKey4=0;
ExKey5=0; // Nuevo
ExKey6=0; // Nuevo

Lo mas rápido es descargar estos parches que ya he preparado con los cambios:
http://heli.xbot.es/wp-content/uploads/2016/10/minimal.patch_.txt
http://heli.xbot.es/wp-content/uploads/2016/10/input.patch_.txt
cd mame4allpi-code/src/rpi
wget http://heli.xbot.es/wp-content/uploads/2016/10/minimal.patch_.txt
mv minimal.patch_.txt minimal.patch
patch minimal.cpp minimal.patch
wget http://heli.xbot.es/wp-content/uploads/2016/10/input.patch_.txt
mv input.patch_.txt input.patch
patch input.cpp input.patch

Compilar y copiar el ejecutable al directorio que usa retropie:

cd ..
cd ..
make
sudo mv /opt/retropie/emulators/mame4all/mame /opt/retropie/emulators/mame4all/mame.old
sudo cp mame /opt/retropie/emulators/mame4all