Bennu Game Development

Foros en Español => Mesa de Ayuda => Mensaje iniciado por: gecko en Octubre 06, 2017, 11:00:00 pm

Título: Segmentation Fault en fpg_save()?
Publicado por: gecko en Octubre 06, 2017, 11:00:00 pm
Hola, puede ser que de la nada me de Segmentation Fault al momento de usar la función fpg_save()?

Estoy hace varias horas con esto, y no le encuentro la vuelta. Tampoco pude armar un caso aislado donde falle.

Resumo un poco lo que estoy haciendo: un programita que recorre una carpeta, y por cada carpeta crea un fpg con todos los png que haya adentro. Lo raro es que el programa explota siempre con segmentation fault, pero siempre explota en alguna carpeta distinta. Y siempre al momento de fpg_save()

Alguna pista de por donde revisar?
Título: Re:Segmentation Fault en fpg_save()?
Publicado por: SplinterGU en Octubre 07, 2017, 05:07:53 am
dificil sin un programa de test y pngs de test.
Título: Re:Segmentation Fault en fpg_save()?
Publicado por: l1nk3rn3l en Octubre 07, 2017, 03:04:50 pm
comparte el programa y los archivos graficos que ocasionan el crash.. como dice el maestro
 ;)

El directorio tiene permisos de escritura?
Título: Re:Segmentation Fault en fpg_save()?
Publicado por: gecko en Octubre 07, 2017, 04:40:42 pm
Va avanzando la cosa.

Instalé un linux nuevo, para ver que pasaba. Ahora termina de compilar los FPG "sin problemas", pero despues el juego se ve así:

(http://)
Título: Re:Segmentation Fault en fpg_save()?
Publicado por: l1nk3rn3l en Octubre 08, 2017, 07:04:14 pm
Ya funciona por lo visto
Título: Re:Segmentation Fault en fpg_save()?
Publicado por: gecko en Octubre 08, 2017, 10:58:08 pm
Masomenos, se ve todo horrible, doble, distorsionado. No tengo idea que puede ser.

Es BennuGD compatible con las ultimas versiones de las librerias en linux? Puede venir por algo de eso el tema? libpng? libsdl? algo de eso?
Título: Re:Segmentation Fault en fpg_save()?
Publicado por: daltomi en Octubre 09, 2017, 12:11:43 am
La versión 1.2 de tú juego funciona bien.  El problema es con la ver. 1.3.1 :(

PD: Ahora estoy utilizando Lubuntu 32bits (tengo problemas con bennu en Arch).


(http://es.zimagez.com/miniature/screenshotfrom2017-10-0821-14-01.png) (http://es.zimagez.com/zimage/screenshotfrom2017-10-0821-14-01.php)
Título: Re:Segmentation Fault en fpg_save()?
Publicado por: gecko en Octubre 09, 2017, 01:36:04 am
Muchas gracias por la info, voy a ver que rompí en el camino
Título: Re:Segmentation Fault en fpg_save()?
Publicado por: daltomi en Octubre 09, 2017, 09:00:26 pm
Pude solucionar temporalmente el problema.
Realizando un trace vi que faltaban archivos en el directorio fpg/, no encontraba por ejemplo system.fpg

Entonces hice un dirty-hack: copie todos los archivos del directorio fpg/ de la v.1.2 hacia el directorio fpg/ de la v.1.3.

Ahora inicia bien, espero que te ayude ha encontrar el problema.

Edit:
Volviendo todo atrás. Al parecer mi problema, de ventana en negro, es por que fpg/ esta vacío, y esta vacío porque debo ejecutar build.sh, el cual da error por no importa, lo que quiero indicar es que mi problema, aparentemente, es diferente al tuyo :(

Por lo menos aprendí que es un archivo fpg :D


Título: Re:Segmentation Fault en fpg_save()?
Publicado por: gecko en Octubre 09, 2017, 09:43:51 pm
Bien, muchisimas gracias por ese dato y por tu tiempo!

Eso ayuda muchisimo, ahora se confirma la sospecha que el problema es la generacion de estos FPGs.
Título: Re:Segmentation Fault en fpg_save()?
Publicado por: gecko en Octubre 10, 2017, 02:39:10 am
Ok, logré reducir el comportamiento erróneo a un programita pequeño.

Cargo un PNG, lo agrego a un FPG vacío, guardo ese FPG, y ahí ya se ve corrompido el archivo. Si cargo ese FPG que guardé, y de ahí guardo en PNG la imagen, ya la guarda rota tambíen.

Probé con BennuGD en 8, 16, y 32 bits, y lo mismo.

Alguien me podría confirmar que le pasa lo mismo? Será la versión de libpng? Hay algo que pueda hacer para ayudar a resolver esto?

Adjunto un ejemplo con el código mínimo que falla.
Título: Re:Segmentation Fault en fpg_save()?
Publicado por: daltomi en Octubre 10, 2017, 05:35:22 am
Sip, lo mismo, con bennu 32 bits.
Pero no con pixtudio.
Ambos, bennu y pixtudio estan enlazados a la misma libpng.

Bennu:
Código: [Seleccionar]
for i in /usr/local/lib/*.so ;  ldd $i | grep libpng && echo $i                                                                     
        libpng12.so.0 => /lib/i386-linux-gnu/libpng12.so.0 (0xb7517000)
/usr/local/lib/libmod_map.so

Pixtudio:
Código: [Seleccionar]
ldd  ~/.local/bin/pxtp | grep png                                                                                                   
        libpng12.so.0 => /lib/i386-linux-gnu/libpng12.so.0 (0xb75c4000)

Ni idea que puede ser.

Con pixtudio el checksum es el mismo para el input y el output, estimo que no existe corrupción.
Título: Re:Segmentation Fault en fpg_save()?
Publicado por: daltomi en Octubre 10, 2017, 11:30:37 pm
Pude comprobar que el problema esta en el archivo mod_map/file_fpg.c
Viendo las diferencias con pixstudio, y agregando los cambios a bennu, se soluciona.
Conste que no digo que es lo que esta bien o esta mal, que deba hacerse así o no, solamente indico que pude aislar el problema.
Título: Re:Segmentation Fault en fpg_save()?
Publicado por: gecko en Octubre 10, 2017, 11:57:34 pm
Splinter, el publico pide nuevo release! jajaja

daltomi muchisimas gracias por la ayuda y el tiempo! Me estaba volviendo loco esto, no tenia idea que habia hecho para que deje de andar así.
Título: Re:Segmentation Fault en fpg_save()?
Publicado por: daltomi en Octubre 11, 2017, 05:13:42 am
Bueno, ahora si voy a decir que esta bien y que esta mal :P
La función del fallo y original de bennu es esta:
Código: [Seleccionar]
int gr_save_fpg( int libid, const char * filename )

Y el problema esta aquí, en 32 y 16 (lo encontré por el parche de pixtudio)
Código: [Seleccionar]
       // /* Write the bitmap pixel data */

            for ( y = 0 ; y < gr->height ; y++ ) {
               
                switch( bpp ) {
                    case    32:
                            file_writeUint32A( fp, ( uint32_t * ) ( uint8_t * ) gr->data + gr->pitch * y, gr->width);
                            break;

                    case    16:
                            file_writeUint16A( fp, ( uint16_t * ) ( uint8_t * ) gr->data + gr->pitch * y, gr->width);
                            break;

                    case    8:
                    case    1:
                            file_write( fp, ( uint8_t * )gr->data + gr->pitch*y, gr->widthb );
                            break;
                }
            }

Básicamente, por lo que entiendo, file_write{16,32} no sabe cuando "detenerse".

Pixtudio, como parche, usa malloc(), memcpy() y free() para crear un nuevo segmento de memoria('block') de tamaño igual a gr->widthb y
luego copia gr->data alineado a ese segmento nuevo, ahora si, file_write{16,32} sabe cuando detenerse, asi se comporta igual en el case 8.
Código: [Seleccionar]
            /* Write the bitmap pixel data */

            if (bpp > 8) {
                if (!(block = malloc(gr->widthb))) {
                    file_close(fp);
                    return 0; /* No memory */
                }
            }

            for (y = 0; y < gr->height; y++) {
                if (bpp > 8) {
                    memcpy(block, (uint8_t *)gr->data + gr->pitch * y, gr->widthb);
                    if (bpp == 16) {
                        /*                        gr_convert16_ScreenTo565(( uint16_t * )block,
                         * gr->width ); */
                        file_writeUint16A(fp, (uint16_t *)block, gr->width);
                    } else
                        file_writeUint32A(fp, (uint32_t *)block, gr->width);
                } else {
                    file_write(fp, (uint8_t *)gr->data + gr->pitch * y, gr->widthb);
                }
            }

            if (bpp > 8)
                free(block);

Los problemas del parche de pixtudio:
1- malloc esta en el ámbito del for loop nmaps que itera unas ~32 veces * gr->widthb = ~232 bytes.
2- memcpy esta en el ámbito del for loop gr->height.

Mi solución es no usar malloc y usar memoria automática.
Código: [Seleccionar]

    /* Write each map */
   
    uint32_t dummy32; <--- Fuera de nmaps
    uint16_t dummy16;
   
    for ( n = 0 ; n < nmaps ; n++ ) {
    .......................................................................
    .......................................................................
   
        /* Write the bitmap pixel data */
       
        for ( y = 0 ; y < gr->height ; y++ ) {
               
                uint8_t *src = ( uint8_t * ) gr->data + gr->pitch * y;
                uint8_t *end = ( uint8_t * ) src + gr->widthb;

                switch( bpp ) {
                    case    32:
                            dummy32 = *( uint32_t * ) end;
                            *end = 0;
                            file_writeUint32A( fp, ( uint32_t * ) ( uint8_t * ) src, gr->width);
                            *end = ( uint32_t ) dummy32;
                            break;

                    case    16:
                            dummy16 = *( uint16_t * ) end;
                            *end = 0;
                            file_writeUint16A( fp, ( uint16_t * ) ( uint8_t * ) src, gr->width);
                            *end = ( uint16_t ) dummy16;
                            break;

                    case    8:
                    case    1:
                            file_write( fp, ( uint8_t * )gr->data + gr->pitch*y, gr->widthb );
                            break;
                }
            }
    .........................................................................
Básicamente, cuando file_write{32,16} recorre el bloque de memoria, se detiene en el terminador nulo 0, y para no perder el dato que ahí existía, lo guardo previamente.

Todo funciona bien con el archivo de test de gecko, con  set_mode(, , 32,) y set_mode( , , 16,).

Todo  dependerá que dicen los expertos si está aquí el bug o está en otro lado.




Título: Re:Segmentation Fault en fpg_save()?
Publicado por: SplinterGU en Octubre 13, 2017, 12:30:03 pm
Bueno, ahora si voy a decir que esta bien y que esta mal :P
La función del fallo y original de bennu es esta:
Código: [Seleccionar]
int gr_save_fpg( int libid, const char * filename )

Y el problema esta aquí, en 32 y 16 (lo encontré por el parche de pixtudio)
Código: [Seleccionar]
       // /* Write the bitmap pixel data */

            for ( y = 0 ; y < gr->height ; y++ ) {
               
                switch( bpp ) {
                    case    32:
                            file_writeUint32A( fp, ( uint32_t * ) ( uint8_t * ) gr->data + gr->pitch * y, gr->width);
                            break;

                    case    16:
                            file_writeUint16A( fp, ( uint16_t * ) ( uint8_t * ) gr->data + gr->pitch * y, gr->width);
                            break;

                    case    8:
                    case    1:
                            file_write( fp, ( uint8_t * )gr->data + gr->pitch*y, gr->widthb );
                            break;
                }
            }

Básicamente, por lo que entiendo, file_write{16,32} no sabe cuando "detenerse".

Pixtudio, como parche, usa malloc(), memcpy() y free() para crear un nuevo segmento de memoria('block') de tamaño igual a gr->widthb y
luego copia gr->data alineado a ese segmento nuevo, ahora si, file_write{16,32} sabe cuando detenerse, asi se comporta igual en el case 8.
Código: [Seleccionar]
            /* Write the bitmap pixel data */

            if (bpp > 8) {
                if (!(block = malloc(gr->widthb))) {
                    file_close(fp);
                    return 0; /* No memory */
                }
            }

            for (y = 0; y < gr->height; y++) {
                if (bpp > 8) {
                    memcpy(block, (uint8_t *)gr->data + gr->pitch * y, gr->widthb);
                    if (bpp == 16) {
                        /*                        gr_convert16_ScreenTo565(( uint16_t * )block,
                         * gr->width ); */
                        file_writeUint16A(fp, (uint16_t *)block, gr->width);
                    } else
                        file_writeUint32A(fp, (uint32_t *)block, gr->width);
                } else {
                    file_write(fp, (uint8_t *)gr->data + gr->pitch * y, gr->widthb);
                }
            }

            if (bpp > 8)
                free(block);

Los problemas del parche de pixtudio:
1- malloc esta en el ámbito del for loop nmaps que itera unas ~32 veces * gr->widthb = ~232 bytes.
2- memcpy esta en el ámbito del for loop gr->height.

Mi solución es no usar malloc y usar memoria automática.
Código: [Seleccionar]

    /* Write each map */
   
    uint32_t dummy32; <--- Fuera de nmaps
    uint16_t dummy16;
   
    for ( n = 0 ; n < nmaps ; n++ ) {
    .......................................................................
    .......................................................................
   
        /* Write the bitmap pixel data */
       
        for ( y = 0 ; y < gr->height ; y++ ) {
               
                uint8_t *src = ( uint8_t * ) gr->data + gr->pitch * y;
                uint8_t *end = ( uint8_t * ) src + gr->widthb;

                switch( bpp ) {
                    case    32:
                            dummy32 = *( uint32_t * ) end;
                            *end = 0;
                            file_writeUint32A( fp, ( uint32_t * ) ( uint8_t * ) src, gr->width);
                            *end = ( uint32_t ) dummy32;
                            break;

                    case    16:
                            dummy16 = *( uint16_t * ) end;
                            *end = 0;
                            file_writeUint16A( fp, ( uint16_t * ) ( uint8_t * ) src, gr->width);
                            *end = ( uint16_t ) dummy16;
                            break;

                    case    8:
                    case    1:
                            file_write( fp, ( uint8_t * )gr->data + gr->pitch*y, gr->widthb );
                            break;
                }
            }
    .........................................................................
Básicamente, cuando file_write{32,16} recorre el bloque de memoria, se detiene en el terminador nulo 0, y para no perder el dato que ahí existía, lo guardo previamente.

Todo funciona bien con el archivo de test de gecko, con  set_mode(, , 32,) y set_mode( , , 16,).

Todo  dependerá que dicen los expertos si está aquí el bug o está en otro lado.






como que no sabe como detenerse ?!?!?!?!

el nul char no hace que se detenga.

se detiene por "gr->width", lo que has hecho con tus cambios es seguramente ocultar otro bug, con la nueva compilacion al reasignar las areas de memoria... eso pasa bastante cuando por ejemplo, compilamos algo en debug y en release... en release crashea y en debug no.

aun no tuve tiempo de ver esto... pero el poner un *end=0, no hace que se detenga el write... si fuera asi, se detendria con pixeles con valor 0.

esto no es una string que se guarda...

el problema es otro...
Título: Re:Segmentation Fault en fpg_save()?
Publicado por: daltomi en Octubre 14, 2017, 02:14:20 pm
Ha ya, yo entendí cualquier cosa ;D

Gracias Splinter  ;)
Título: Re:Segmentation Fault en fpg_save()?
Publicado por: SplinterGU en Octubre 15, 2017, 02:21:00 am
no pasa nada, cuando tenga la solucion aviso...
Título: Re:Segmentation Fault en fpg_save()?
Publicado por: SplinterGU en Octubre 16, 2017, 08:07:59 am
bien... fixeado!

a mi no me reventaba el ejecutable, pero grababa mal el fpg... era una cuestion de casteo... me comi unos parentesis...

Código: [Seleccionar]
--- modules/mod_map/file_fpg.c  (revisión: 343)
+++ modules/mod_map/file_fpg.c  (copia de trabajo)
@@ -320,11 +320,11 @@
             for ( y = 0 ; y < gr->height ; y++ ) {
                 switch( bpp ) {
                     case    32:
-                            file_writeUint32A( fp, ( uint32_t * ) ( uint8_t * )gr->data + gr->pitch*y, gr->width );
+                            file_writeUint32A( fp, ( uint32_t * ) ( ( uint8_t * )gr->data + gr->pitch*y), gr->width );
                             break;
 
                     case    16:
-                            file_writeUint16A( fp, ( uint16_t * ) ( uint8_t * )gr->data + gr->pitch*y, gr->width );
+                            file_writeUint16A( fp, ( uint16_t * ) ( ( uint8_t * )gr->data + gr->pitch*y), gr->width );
                             break;
 
                     case    8:

ahi esta el diff

gracias por el reporte, el sample y los analisis...