Segmentation Fault en fpg_save()?

Started by gecko, October 06, 2017, 11:00:00 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

gecko

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?
Torres Baldi Studio
http://torresbaldi.com

SplinterGU

dificil sin un programa de test y pngs de test.
Download Lastest BennuGD Release: http://www.bennugd.org/node/2

l1nk3rn3l

#2
comparte el programa y los archivos graficos que ocasionan el crash.. como dice el maestro
;)

El directorio tiene permisos de escritura?

gecko

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í:

Torres Baldi Studio
http://torresbaldi.com

l1nk3rn3l


gecko

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?
Torres Baldi Studio
http://torresbaldi.com

daltomi

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



gecko

Muchas gracias por la info, voy a ver que rompí en el camino
Torres Baldi Studio
http://torresbaldi.com

daltomi

#8
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



gecko

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.
Torres Baldi Studio
http://torresbaldi.com

gecko

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.
Torres Baldi Studio
http://torresbaldi.com

daltomi

#11
Sip, lo mismo, con bennu 32 bits.
Pero no con pixtudio.
Ambos, bennu y pixtudio estan enlazados a la misma libpng.

Bennu:

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:

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.

daltomi

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.

gecko

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í.
Torres Baldi Studio
http://torresbaldi.com

daltomi

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:

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)

       // /* 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.

            /* 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.


    /* 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.