sisoputnfrba / foro

Foro de consultas para el trabajo práctico
151 stars 7 forks source link

Error al serializar/deserializar instrucciones de consola y kernel #2634

Closed EspositoLucas closed 2 years ago

EspositoLucas commented 2 years ago

Buenas

A medida que probabamos el envio de instrucciones desde la consola al kernel, estuvimso teneidnoeniendo problemas para cargar la lista de instrucciones a la pcb. En el soporte del sabado pasadonos sugirieron enviar lo leido del archivo al kernel, e el paquete con un solo send() de ahi deserializarlo para luego cargarlo a la pcb. Nuestra consulta es sobre como es la implementacion para deserializar lo recibido a una lista directamente porque s eno esta complicando la forma en que kernel reciba las instrucciones y que las muestre por consola . Es mas es por este problema que nos tira este error en el servidor :

[INFO] 23:06:33:502 Servidor Kernel/(15960:15960): Se conecto un cliente!
[INFO] 23:06:33:502 Servidor Kernel/(15960:15960): Me llego el mensaje :  : Envio a kernel la info del proceso
Segmentation fault (core dumped)

y en consola solo se muestra el archivo leido que creamos de ejemplo de esta manera :

[INFO] 23:06:33:500 consola/(16002:16002): INICIANDO CONSOLA
NO_OP 5
I/O 3000
WRITE 4 42
COPY 0 4
READ 0
EXIT

En base a lo que nos coemnto un ayusante, de deserializar todo lo leido e le kernel, se nos ocucrrio implenatrlo asi pero a la hota de compilar tira el error que envie anteriroemente . Asi esta el codigo :

t_list *recibir_paquete_instrucciones(int socket_cliente) // Para deserializar las instrucciones de consola
{
    int size;
    int desplazamiento = 0;
    void *buffer;
    t_list *valores = list_create();
    int tamanio;
    int indice_split = 0 ;

    buffer = recibir_buffer(&size, socket_cliente);
    char** split_buffer = string_split(buffer, "\n");

    while (desplazamiento < size && split_buffer[indice_split] != NULL)
    {
        memcpy(&tamanio, split_buffer + desplazamiento, sizeof(int));
        desplazamiento += sizeof(int);

        char** palabras = string_split(split_buffer[indice_split], " ") ;

        if(string_contains(palabras[0], "NO_OP") ) {
            int parametro_NO_OP = atoi(palabras[1]);
            for(int i=0; i< parametro_NO_OP  ; i++){
                printf("NO_OP %d ", parametro_NO_OP);

            }

        } else if (string_contains(palabras[0], "I/O")){
            int parametro_IO = atoi(palabras[1]);
            printf("I/O %d ", parametro_IO);
        }
         else if (string_contains(palabras[0], "READ")){
            int parametro_READ = atoi(palabras[1]);
            printf("READ %d ", parametro_READ);

        } else if (string_contains(palabras[0], "WRITE")) {
            int parametro1_WRITE = atoi(palabras[1]);
            int parametro2_WRITE = atoi(palabras[2]);
            printf("WRITE %d %d ", parametro1_WRITE,parametro2_WRITE);

        } else if (string_contains(palabras[0], "COPY")){
            int parametro1_COPY = atoi(palabras[1]);
            int parametro2_COPY = atoi(palabras[2]);
            printf("COPY %d %d ", parametro1_COPY,parametro2_COPY);

        } else if (string_contains(palabras[0], "EXIT")){

            printf("EXIT");
        }
        memcpy(palabras, split_buffer + desplazamiento, tamanio);
        desplazamiento += tamanio;
        list_add(valores, palabras);
        free(palabras) ;
    }

    free(split_buffer);
    return valores;
}

Repasamos la guia y la charla sobre serializacion y aun asi estamos un poco perdidos sobre como corregirlo y serializar/deserializar esta parte . Espero que nos puedan ayudar con este tema que nos anda dando vueltas y atrasando con el desarrollo . Gracias

Saludos,

Lucas

RaniAgus commented 2 years ago

¡Buenas! Lamentablemente los ayudantes no somos compiladores humanos, por lo que te hago unas preguntas para que nos ayudes a ayudarte:

  1. ¿Probaron de usar el debugger para revisar los valores que van tomando las variables línea por línea?

  2. ¿Qué parte del paquete debería devolver recibir_buffer()? ¿Es un string o un stream?

  3. Si recibir_buffer() es un stream, ¿podrían decirme cómo está serializado?, por ejemplo:

    • uint32_t dni (4 bytes)
    • uint8_t edad (1 byte)
    • uint32_t size_nombre (4 bytes)
    • char* nombre (size_nombre bytes)
  4. Si recibir_buffer() es un string, ¿podrían darme un ejemplo de lo que contiene? Se pueden ayudar con el debugger.

Saludos

EspositoLucas commented 2 years ago
  1. Justamente estabamos teniendo tambien problemas con eso porque a la hora de debuggear no pudimos encontrar el error porque el programa terminaba directamente y no permitía avanzar linea por linea

  2. En este aso el recibir_buffer() es un stream, básicamente tiene la logica del buffer que esta en el tp0

3 y 4. Eso tambien nos surgio duda porque el error al enviarse las instrucciones tiene que ver con como se serializa el buffer . El codigo esta asi ( el mismo que en el tp0) :

void *recibir_buffer(int *size, int socket_cliente)
{
    void *buffer;

    recv(socket_cliente, size, sizeof(int), MSG_WAITALL);
    buffer = malloc(*size);
    recv(socket_cliente, buffer, *size, MSG_WAITALL);

    return buffer;
}

y la manera en como pensamos deserializarlo es en el código que mostre arriba en el que nos tira el error . El codigo en el que nos basamos fue justamnete en el del tp0 t_list *recibir_paquete_instrucciones(int socket_cliente) pero no supimos como implementarlo para deserializar las instrucciones que envia consola

No se si se aclara esto pero la idea es saber como hacer que ese buffer se serialice de la forma correcta para que se muestren las instrucciones con la logica que pusimos en t_list *recibir_paquete_instrucciones(int socket_cliente), me explico ? Porque estamos trabados con esa parte aunque hayamos leido la guia y visto el video, principalmente lo que nos confunde es como hacer que se deserialice en el kernel el archivo leido() que se envia en consola donde el codigo donde se envia el archivo de instrucciones es este :

void paquete_proceso(int conexion){

    t_paquete *paquete = crear_paquete();
    char* leido = leer_archivo("instrucciones.txt");
//    char** split = string_split(leido, "\n");
//    int longitud_instrucciones = string_array_size(split);
//    int indice_split = 0 ;

        agregar_a_paquete(paquete, leido, strlen(leido)+1 );
//      free(leido);

    enviar_paquete(paquete, conexion);
    eliminar_paquete(paquete);
//    free(leido);

}

y aca la idea es hacer un solo send90 para que luego el kernel lo reciba,deserialice y parsee las instrucciones

Espero no haber mareado porque nostros tambien estamos asi y con varias dudas

LeandroCarbajales commented 2 years ago

Buenas! En primer lugar, creo que es importante que puedan debuggear, no solo para este caso, sino también para todo lo que se vaya presentando a lo largo del cuatrimestre (y en la vida) y estamos para ayudarlos si alguna parte del video de debug no se entiende o algún uso no está abarcado. En este caso, por qué el programa termina directamente? Poniendo un breakpoint al principio de la función que causa problemas no detiene la ejecución en debug?

Por otro lado, viendo el código por arriba lo primero que me hace ruido es que estén intentando deserializar un mensaje y al mismo tiempo implementando un parseo, no es que no se pueda, pero es más propenso a que maree ya que trabajan con varias estructuras al mismo tiempo, recomendaría o hacer el parseo en la Consola y ya enviar un mensaje con una estructura fija que sepan serializar/deserializar, o bien, si quieren seguir por el camino que tienen, primero deserializar el mensaje y luego hacer el parseo (en este caso entiendo que es el string_split() y los if else, que si me preguntan a mí lo cambiaría por un switch case que quedaría más prolijo).

De cualquier manera, les dejo mi análisis más en detalle con algunas cosas que me hacen ruido del código para que los ayude a ir viendo posibles puntos de errores al debuggear: Al comienzo hacen un string_split() sobre algo que podría no ser un string (el buffer, que por lo que veo contiene también el tamaño del paquete), por lo que tendría cuidado con eso. Entrando en el while, me hace ruido también que hagan memcpy directamente sobre split_buffer siendo que el mismo sería un char**. Por último, no me termina de cerrar el while, parecería estar fuera de lugar ya que entiendo que reciben un solo paquete (el tamaño con el string del archivo completo), no debería incluir solamente la parte de parseo sobre el split del texto del archivo?

Espero que les sirvan mis comentarios! Saludos! Lean

EspositoLucas commented 2 years ago

Buenas Leandro . Gracias por los comentarios . Estuve revisando la parte de deserializar el mensaje que envia consola ( en la funcion paquete_proceso(int conexion) ) y decidi seguir con la deserialización en el kernel en base a lo que comentaste .

Decidi poner en el pcb un campo char* mensaje_consola ( no se me ocurrio un mejor nombre descriptivo) que representaria la instruccion que se envia en el paquete para copiarlo en el stream del buffer y despues parsearlo . Tambien se deserializa con el tamaño del proceso del proceso que supuse que seria el tamaño del mensaje porque como mencionabas al recibir el paquete tambien se recibe el tamaño del pquete . Entonces la idea seria generar una nueva estructura pcb del proceso con esos campos del mensjae y tamaño deserializados para luego hacer el parseo con el string_split() . No se si entendi bien lo que me dijiste pero dejo el codigo de lo que pense para ver si tiene sentido .

pcb *deserializar_paquete_instrucciones(t_buffer* buffer) // Para deserializar las instrucciones de consola
 {

     pcb proceso = malloc(sizeof(pcb)) ;
     int indice_split = 0 ;
     void* stream = buffer.stream ; 

     // Deserializar los campos del buffer

    memcpy(&(proceso.tamanio_proceso), stream, sizeof(uint32_t));
    stream += sizeof(uint32_t);
    proceso.mensaje_consola = malloc(proceso.tamanio_proceso);
    memcpy(proceso.mensaje_consola, stream, proceso.mensaje_consola);

    char** split_buffer = string_split(proceso.mensaje_consola, "\n");

    while (split_buffer[indice_split] != NULL) {

    char** palabras = string_split(split_buffer[indice_split], " ") ;

         if(string_contains(palabras[0], "NO_OP") ) {
            int parametro_NO_OP = atoi(palabras[1]);
             for(int i=0; i< parametro_NO_OP  ; i++){
                printf("NO_OP %d ", parametro_NO_OP);
//                 list_add(proceso.instrucciones) ; // Para agregar a lista a medida quese vaya parseando

             }

        } else if (string_contains(palabras[0], "I/O")){
             int parametro_IO = atoi(palabras[1]);
             printf("I/O %d ", parametro_IO);
        }
         else if (string_contains(palabras[0], "READ")){
             int parametro_READ = atoi(palabras[1]);
             printf("READ %d ", parametro_READ);

        } else if (string_contains(palabras[0], "WRITE")) {
             int parametro1_WRITE = atoi(palabras[1]);
             int parametro2_WRITE = atoi(palabras[2]);
             printf("WRITE %d %d ", parametro1_WRITE,parametro2_WRITE);

        } else if (string_contains(palabras[0], "COPY")){
             int parametro1_COPY = atoi(palabras[1]);
             int parametro2_COPY = atoi(palabras[2]);
             printf("COPY %d %d ", parametro1_COPY,parametro2_COPY);

        } else if (string_contains(palabras[0], "EXIT")){

            printf("EXIT");
        }

     }

     return proceso;
 }

De paso , algo que nos surgio duda es por si cada if else hay que ir agregando a la lista de instrucciones del pcb lo que se vaya parseando o mejor dicho, como deberiamos agregar esas isntrucciones a medida que se parsean a la lista del pcb ?

Por las dudas, el pcb del proceso con los campos que creamos es este :

typedef struct {
    int id_proceso ;
    const int tamanio_proceso ;
    t_list* instrucciones ; 
    int valor_tabla_paginas ;
    int program_counter;
    float rafaga_real_anterior ;
    float estimacion_recalculada ;
    char* estado ;
    int tiempoEspera ;
    bool suspendido;
    char* mensaje_consola ; 

}pcb ;

Gracias de antemano y perdonen por si no fui claro con las dudas

Saludos

RaniAgus commented 2 years ago

¡Buenas!

Quizás el código no compile porque malloc() devuelve un puntero a una dirección de memoria del heap y están intentando guardarlo en un struct pcb en el stack:

pcb proceso = malloc(sizeof(pcb));

Prueben de cambiar el tipo de retorno a pcb* (y los proceso.atributo por proceso->atributo):

pcb* proceso = malloc(sizeof(pcb));

También veo que usan indice_split para iterar el array pero falta incrementar la variable al final del while para avanzar con el siguiente string del array.

No se olviden que también deben enviar el tamaño del proceso, que no es el tamaño del archivo de instrucciones, sino un parámetro que recibe el main() de la consola, cito el enunciado:

Para poder instanciar una consola, la misma recibirá por parámetro:

  • El tamaño que tendrá el proceso
  • Un path a un archivo de texto con pseudocódigo, con el que creará una lista de instrucciones

(Igual de todas formas aclaro que enviar el tamaño del archivo de instrucciones está bien, ya que permite reservar memoria para luego deserializar el string 👍🏻)

Por último, tengan en cuenta que string_split() devuelve strings en el heap, por lo que para liberar esa memoria una vez que ya no la necesiten pueden usar string_array_destroy().

(Si necesitan ayuda para saber qué es "heap" y "stack" también pueden consultar la guía de punteros)

¿Pudieron usar el debugger para probar el código? ¿Necesitan ayuda con eso?

Saludos

LeandroCarbajales commented 2 years ago

Buenas! Antes que nada, insisto que es crucial que se amiguen con el debug para poder ver en detalle qué valores tienen las variables a cada paso, les va a servir tanto ahora para entender mejor qué pasa en el código como en la vida profesional para cualquier cosa relacionada a la programación :)

Con respecto a agregar elementos a la lista

De paso , algo que nos surgio duda es por si cada if else hay que ir agregando a la lista de instrucciones del pcb lo que se vaya parseando o mejor dicho, como deberiamos agregar esas isntrucciones a medida que se parsean a la lista del pcb ?

Entiendo que esa sería la idea, pueden ver la definición de todas las funciones de List en el repo de las commons

Saludos! Lean

iago64 commented 2 years ago

Buenas! @EspositoLucas te quedó alguna duda? Hay algo que no se entienda de las respuestas de Lean y Agus?

Saludos.-

EspositoLucas commented 2 years ago

Buenas Profes . Disculpen que tarde en responder porque estaba tratando de resolver la duda con el grupo y aunque pudimos avanzar con el tema de la serialización/ deserializacion del pcb, todavia seguimos con algunos problemas al enviar las instrucciones de consola hacia kernel . Basándonos en sus recomendaciones, estuvimos utilizando el debug y por el lado de consola no tuvimos errores pero al ejecutar el debug en kernel, ahi se nos termina el programa y no sabemos a que se debe el error . El error se presenta en la funcion nueva que creamos pcb *recibir_paquete_instrucciones(int socket_cliente) con codigo :

 pcb *recibir_paquete_instrucciones(int socket_cliente)
{
    t_buffer* buffer ;
    int size;
    void *stream ;
    pcb* pcb ;

    stream = recibir_buffer(&size, socket_cliente);
    buffer->stream = stream ;

    pcb = deserializar_paquete_instrucciones_consola(buffer);
    free(buffer);
    return pcb ;
}

donde el programa termina arrojando este error de segmentation fault con menaje por consola :

[INFO] 20:24:04:109 Servidor Kernel/(25407:25407): Kernel listo para recibir al modulo cliente
[INFO] 20:25:27:155 Servidor Kernel/(25407:25407): Se conecto un cliente!
[INFO] 20:25:27:156 Servidor Kernel/(25407:25407): Me llego el mensaje :  : Envio a kernel la info del proceso
[INFO] 20:25:27:156 Servidor Kernel/(25407:25407): Me llegaron las instrucciones:

Segmentation fault (core dumped)

La linea que nos marca el debug donde esta el error es en buffer->stream = stream ; pero termina ahi y no se detalla el porque del error . Esto es lo que aparece en el debug ( mando captura para que se vea mejor) :

image

Justamente como no se detalla el error del segmentation fault , nos trabamos y nos sabemos como seguir . Para dar un mejor panorama, en pcb *recibir_paquete_instrucciones(int socket_cliente) se llama a la funcion deserializar_paquete_instrucciones_consola(buffer); en el que se deserializa el menaje de consola y la logica del parseo de las instrucciones tambien esta ahi . El codigo es este por si sirve :

pcb *deserializar_paquete_instrucciones_consola(t_buffer* buffer) // Para deserializar las instrucciones de consola
 {

     pcb* proceso_pcb = malloc(sizeof(pcb)) ;
     int indice_split = 0 ;
     void* stream = buffer->stream ; 
     char* mensaje_consola ; // leido de consola que se envia en el paquete

     // Deserializar los campos del buffer

    mensaje_consola = malloc(sizeof(uint32_t));
    memcpy(mensaje_consola, stream, sizeof(uint32_t));
    stream += sizeof(uint32_t);

    char** split_buffer = string_split(mensaje_consola, "\n");
    char** palabras ;

    while (split_buffer[indice_split] != NULL) {

        if(string_contains(split_buffer[indice_split], "NO_OP") ) {
            palabras = string_split(split_buffer[indice_split], " ") ;
            int parametro_NO_OP = atoi(palabras[1]);
            for(int i=0; i< parametro_NO_OP  ; i++){
                printf("NO_OP %d ", parametro_NO_OP);
                list_add(proceso_pcb->instrucciones,palabras[0]) ; // Para agregar a lista a medida quese vaya parseando
            }
        // string_array_destroy(palabras);

        } else { // si no es no op directamente entra aca y se agrega a la lista
            printf("%s",split_buffer[indice_split]);
            list_add(proceso_pcb->instrucciones,split_buffer[indice_split]); // consultar si esto es lo mejor o volver a la anterior de if para cada uno. 
        }

        indice_split++;
    }    

    string_array_destroy(split_buffer);
    string_array_destroy(palabras);  
    free(mensaje_consola);

    return proceso_pcb;
}

No se si el error tambien tiene que ver con esta funcion o si hay algun problema en la logica de la deserialziacion . Para implementar esta funcion nos basamos en los consejos que nos dieron y al compilarlo no hubo errores y tampoco en valgrind tanto en consola como en kernel, por lo que nos genero la duda de porque de esto .

Entendemos que tiene que ver con el stream del buffer que se recibe por consola pero no sabemos si es por la deserializacion de la funcion pcb *deserializar_paquete_instrucciones_consola(t_buffer* buffer) o por un error de asignacion o algo asi . puede ser que no nos estemos dando cuenta porque no usamos bien el debug o no entendemos bien lo que nos aparece ?

Disculpen si no quedo claro . Gracias por la ayuda

Saludos

RaniAgus commented 2 years ago

¡Buenas! Falla en esa línea porque el puntero que guardan en buffer está sin inicializar:

t_buffer* buffer;

Por lo que al intentar escribir el contenido al que supuestamente apunta falla:

buffer->stream = stream; // ¿A dónde apunta "buffer"? No sabemos...

La solución es reservar memoria con malloc() antes de usarla:

t_buffer* buffer = malloc(sizeof(t_buffer));

En cuanto a Valgrind, ¿están seguros que lo están usando bien? Estoy 99% seguro de que este problema debió haber aparecido con el warning: Conditional jump or move depends on uninitialised value(s).

Saludos

EDIT: Para tener más info sobre cómo usar Valgrind pueden consultar la guía y la charla de 2019.

EspositoLucas commented 2 years ago

Gracias ! Nos habiamos olvidado de ese detalle . Igualmente, sigue tirando el mismo error pero ahora en la funcion pcb*deserializar_paquete_instrucciones_consola(t_buffer* buffer) en la parte que se agrega a lista de instrucciones del pcb cada instrucción cuando se hace el parseo en el while .

Arroja estos errores en el debug :

image image

y la funcion la tenemos asi :

pcb *deserializar_paquete_instrucciones_consola(t_buffer* buffer) // Para deserializar las instrucciones de consola
 {

     pcb* proceso_pcb = malloc(sizeof(pcb)) ;
     int indice_split = 0 ;
     void* stream = buffer->stream ; 
     char* mensaje_consola ; // leido de consola que se envia en el paquete

     // Deserializar los campos del buffer

    mensaje_consola = malloc(sizeof(uint32_t));
    memcpy(mensaje_consola, stream, sizeof(uint32_t));
    stream += sizeof(uint32_t);

    char** split_buffer = string_split(mensaje_consola, "\n");
    char** palabras ;

    while (split_buffer[indice_split] != NULL) {

        if(string_contains(split_buffer[indice_split], "NO_OP") ) {
            palabras = string_split(split_buffer[indice_split], " ") ;
            int parametro_NO_OP = atoi(palabras[1]);
            for(int i=0; i< parametro_NO_OP  ; i++){
                printf("NO_OP %d ", parametro_NO_OP);
                list_add(proceso_pcb->instrucciones,palabras[0]) ; // Para agregar a lista a medida quese vaya parseando
            }
        // string_array_destroy(palabras);

        } else { // si no es no op directamente entra aca y se agrega a la lista
            printf("%s",split_buffer[indice_split]);
            list_add(proceso_pcb->instrucciones,split_buffer[indice_split]); // consultar si esto es lo mejor o volver a la anterior de if para cada uno. 
        }

        indice_split++;
    }    

    string_array_destroy(split_buffer);
    string_array_destroy(palabras);
    list_destroy(proceso_pcb->instrucciones);
    free(mensaje_consola);
    free(proceso_pcb);

    return proceso_pcb;
}

Tendra que ver con otro error de no asignar y liberar memoria dinamica o algo asi ?

Por las dudas, probe en valgrind al compilar el kernel y al parecer no tira errores aunque igualmente me genera la duda de si es un problema de memoria dinamica o no :

==27990== Process terminating with default action of signal 2 (SIGINT)
==27990==    at 0x4143FB9: accept (accept.c:35)
==27990==    by 0x8048DEC: esperar_cliente (kernelUtils.c:43)
==27990==    by 0x8048BDF: main (kernel.c:9)
==27990== 
==27990== HEAP SUMMARY:
==27990==     in use at exit: 380 bytes in 3 blocks
==27990==   total heap usage: 32 allocs, 29 frees, 11,018 bytes allocated
==27990== 
==27990== LEAK SUMMARY:
==27990==    definitely lost: 0 bytes in 0 blocks
==27990==    indirectly lost: 0 bytes in 0 blocks
==27990==      possibly lost: 0 bytes in 0 blocks
==27990==    still reachable: 380 bytes in 3 blocks
==27990==         suppressed: 0 bytes in 0 blocks
==27990== Reachable blocks (those to which a pointer was found) are not shown.
==27990== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==27990== 
==27990== For counts of detected and suppressed errors, rerun with: -v
==27990== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
RaniAgus commented 2 years ago

Fijate que con Valgrind cortaste la ejecución antes de enviar el mensaje (ese SIGINT es la señal que se envía al hacer Ctrl + C). Asegurate de haber intentado enviar el mensaje para que el debug con Valgrind arroje resultados.

Tendra que ver con otro error de no asignar y liberar memoria dinamica o algo asi ?

Sí, al igual que para los t_config* y t_log*, para usar una t_list* es necesario primero haberla creado. Digamos que los create de las commons vendrían a ser los new que se ven en la parte de Objetos de PdeP pero en un lenguaje imperativo como C.

También recordá que desaconsejamos subir capturas de pantalla 👮🏻‍♂️. Preferimos contar con el stack trace en texto para que el buscador de issues lo reconozca.

EspositoLucas commented 2 years ago

Buenas . Si, se nos habia escapado ese detalle Gracias 👍 . Pudimos solucionar le tema del segmenation fault pero nos surgieron estos errores por consola que no lo entendemos muy bien como solucionarlo :

[INFO] 15:37:13:153 Servidor Kernel/(31244:31244): Kernel listo para recibir al modulo cliente
[INFO] 15:37:19:688 Servidor Kernel/(31244:31244): Se conecto un cliente!
[INFO] 15:37:19:688 Servidor Kernel/(31244:31244): Me llego el mensaje :  : Envio a kernel la info del proceso
[INFO] 15:37:19:689 Servidor Kernel/(31244:31244): Me llegaron las instrucciones:

*** Error in `./kernel.out': free(): invalid pointer: 0xb775a7d0 ***
======= Backtrace: =========
/lib/i386-linux-gnu/libc.so.6(+0x67377)[0xb760f377]
/lib/i386-linux-gnu/libc.so.6(+0x6d2f7)[0xb76152f7]
/lib/i386-linux-gnu/libc.so.6(+0x6dc31)[0xb7615c31]
/usr/lib/libcommons.so(string_iterate_lines+0x20)[0xb7761c4d]
/usr/lib/libcommons.so(string_array_destroy+0x24)[0xb7761d88]
./kernel.out[0x8049202]
./kernel.out[0x804902c]
./kernel.out[0x8048c4b]
/lib/i386-linux-gnu/libc.so.6(__libc_start_main+0xf7)[0xb75c0637]
./kernel.out[0x8048ab1]
======= Memory map: ========
08048000-0804a000 r-xp 00000000 00:26 4683       /home/utnso/shared/TP/tp-2022-1c-Ubunteam/kernel/bin/kernel.out
0804a000-0804b000 r--p 00001000 00:26 4683       /home/utnso/shared/TP/tp-2022-1c-Ubunteam/kernel/bin/kernel.out
0804b000-0804c000 rw-p 00002000 00:26 4683       /home/utnso/shared/TP/tp-2022-1c-Ubunteam/kernel/bin/kernel.out
08240000-08261000 rw-p 00000000 00:00 0          [heap]
b7400000-b7421000 rw-p 00000000 00:00 0 
b7421000-b7500000 ---p 00000000 00:00 0 
b7572000-b758e000 r-xp 00000000 fc:00 1700661    /lib/i386-linux-gnu/libgcc_s.so.1
b758e000-b758f000 rw-p 0001b000 fc:00 1700661    /lib/i386-linux-gnu/libgcc_s.so.1
b75a7000-b75a8000 rw-p 00000000 00:00 0 
b75a8000-b7758000 r-xp 00000000 fc:00 1705948    /lib/i386-linux-gnu/libc-2.23.so
b7758000-b775a000 r--p 001af000 fc:00 1705948    /lib/i386-linux-gnu/libc-2.23.so
b775a000-b775b000 rw-p 001b1000 fc:00 1705948    /lib/i386-linux-gnu/libc-2.23.so
b775b000-b775e000 rw-p 00000000 00:00 0 
b775e000-b7767000 r-xp 00000000 fc:00 1848627    /usr/lib/libcommons.so
b7767000-b7768000 r--p 00008000 fc:00 1848627    /usr/lib/libcommons.so
b7768000-b7769000 rw-p 00009000 fc:00 1848627    /usr/lib/libcommons.so
b7780000-b7782000 rw-p 00000000 00:00 0 
b7782000-b7785000 r--p 00000000 00:00 0          [vvar]
b7785000-b7786000 r-xp 00000000 00:00 0          [vdso]
b7786000-b77a9000 r-xp 00000000 fc:00 1705946    /lib/i386-linux-gnu/ld-2.23.so
b77a9000-b77aa000 r--p 00022000 fc:00 1705946    /lib/i386-linux-gnu/ld-2.23.so
b77aa000-b77ab000 rw-p 00023000 fc:00 1705946    /lib/i386-linux-gnu/ld-2.23.so
bfb70000-bfb91000 rwxp 00000000 00:00 0          [stack]
bfb91000-bfb92000 rw-p 00000000 00:00 0 
'Aborted (core dumped)

El cambio que realizamos en la funcion fue esto :

pcb *deserializar_paquete_instrucciones_consola(t_buffer* buffer) // Para deserializar las instrucciones de consola
 {

     pcb* proceso_pcb = malloc(sizeof(pcb)) ;
     int indice_split = 0 ;
     void* stream = buffer->stream ; 
     char* mensaje_consola ; // leido de consola que se envia en el paquete

     // Deserializar los campos del buffer

    mensaje_consola = malloc(sizeof(strlen(mensaje_consola) + 1));
    memcpy(mensaje_consola, stream, sizeof(uint32_t));
    stream += sizeof(uint32_t);

    char** split_buffer = malloc(sizeof(mensaje_consola));
    split_buffer = string_split(mensaje_consola, "\n");
    char** palabras = malloc(sizeof(split_buffer[indice_split])) ;
    proceso_pcb->instrucciones = list_create();

    while (split_buffer[indice_split] != NULL) {

        if(string_contains(split_buffer[indice_split], "NO_OP") ) {
            palabras = string_split(split_buffer[indice_split], " ") ;
            int parametro_NO_OP = atoi(palabras[1]);
            for(int i=0; i< parametro_NO_OP  ; i++){
                printf("NO_OP %d ", parametro_NO_OP);
                list_add(proceso_pcb->instrucciones,palabras[0]) ; // Para agregar a lista a medida quese vaya parseando
            }

        } else { // si no es no op directamente entra aca y se agrega a la lista
            printf("%s",split_buffer[indice_split]);
            list_add(proceso_pcb->instrucciones,split_buffer[indice_split]); // consultar si esto es lo mejor o volver a la anterior de if para cada uno. 
        }

        indice_split++;
    }    

    string_array_destroy(split_buffer);
    string_array_destroy(palabras);
    list_destroy(proceso_pcb->instrucciones);
    free(mensaje_consola);
    free(proceso_pcb);

    return proceso_pcb;
}

donde algunos de los errores que nos apareceia estaba en no hacer malloc a los char** split_buffer y palabras

Al hacer el debug, aparecen estos errores :

__GI_abort() at abort.c:89 0xb7e2a407   
Can't find a source file at "/build/glibc-mUak1Y/glibc-2.23/stdlib/abort.c" 
Locate the file or edit the source lookup path to include its location.
__libc_message() at libc_fatal.c:175 0xb7e6437c 
Can't find a source file at "/build/glibc-mUak1Y/glibc-2.23/libio/../sysdeps/posix/libc_fatal.c" 
Locate the file or edit the source lookup path to include its location.
__GI_raise() at raise.c:54 0xb7e28ea9   
Can't find a source file at "/build/glibc-mUak1Y/glibc-2.23/signal/../sysdeps/unix/sysv/linux/raise.c" 
Locate the file or edit the source lookup path to include its location.

Tiene que ver con otro problema de memoria dinamica ? Por que capaz esta en el malloc de los char* porque no supe muy bien que sizeof deberia asignarse, entiendo que seria el de u char pero no estoy seguro .

Disculpen si es facil de ver donde esta el error y no lo entiendo

RaniAgus commented 2 years ago

¡Buenas!

  1. Acá estás teniendo un memory leak, ya que estás reservando memoria con malloc() y luego estás pisando ese puntero con el que te devuelve string_split():

    char** split_buffer = malloc(sizeof(mensaje_consola));
    split_buffer = string_split(mensaje_consola, "\n");

    En este comment está explicado con más detalle lo que ocurre: https://github.com/sisoputnfrba/foro/issues/2224#issuecomment-882803512

  2. Sobre Can't find source file at, repito mi comment de https://github.com/sisoputnfrba/foro/issues/2541#issuecomment-1075632293. Sería más valioso contar con el stack trace del momento del error (ya sea mediante el debugger de Eclipse o un log de Valgrind).

  3. Ojo que están liberando memoria y luego retornando el mismo puntero, probablemente al intentar usarlo ocurra el error:

free(proceso_pcb);
return proceso_pcb;

Saludos

EspositoLucas commented 2 years ago

Con respecto a 3. directamente elimine elfree(proceso_pcb) y deje el return porque la idea es no liberar la memoria .

Estuve revisando el issue #2224 y coincido en el mismo caso . En realidad, no quiero hacer una copia sino que una vezz hecho el split ir agregando a la lista de instrucciones del pcb las instrucciones que se vayan parseando pero no es la idea rellenar el valor de una direccion del malloc en el split porque serian valores basura por lo que entiendo . Directamente saque el malloc pero sigue tirando el mismo error de segmentation fault y no se como solucionarlo . El stack trace que arroja es este :

Thread #1 [kernel.out] 1160 [core: 0] (Suspended : Signal : SIGSEGV:Segmentation fault) 
    __GI___libc_free() at malloc.c:2.951 0xb7e6e496 
    string_iterate_lines() at 0xb7fb6c4d    
    string_array_destroy() at 0xb7fb6d88    
    deserializar_paquete_instrucciones_consola() at kernelUtils.c:187 0x80491e2 
    recibir_paquete_instrucciones() at kernelUtils.c:112 0x804902c  
    main() at kernel.c:29 0x8048c4b 

y el error esta en las funcion string_array_destroy . Sera otro error de memoria dinamica ? porque si e selc aso como se podria solucionar ? porque no quiero hacer un malloc para sobre escribir el valor del split_buffer sino que directamente agregar a pcb -> instrucciones las instrucciones parseadas en el split .

Si se complica verlo, de ultima lo vemos mañana en soporte si nos conectamos . Gracias de antemano

Saludos

RaniAgus commented 2 years ago

Bien, según entiendo con las palabras están haciendo algo así:

    char** palabras;
    // ...

    while (/* ... */) {
        if (string_contains(split_buffer[indice_split], "NO_OP")) {
            palabras = string_split(split_buffer[indice_split], " ") ;
            int parametro_NO_OP = atoi(palabras[1])
            for (int i = 0; i< parametro_NO_OP; i++) {
                //...
                list_add(proceso_pcb->instrucciones, palabras[0]);
            }
        } else { 
            // ...
        }

        // ...
    }

    string_array_destroy(palabras);

Yo les recomendaría reducir el scope de palabras hacia solo dentro del if que valida si la operación es NO_OP, por varios motivos:

Para esto último duplicaría el string que agregan a la lista para no perderlo, o sea que quedaría algo así:

    while (/* ... */) {
        if (string_contains(split_buffer[indice_split], "NO_OP")) {
            // declaro "palabras" dentro del if
            char** palabras = string_split(split_buffer[indice_split], " ");
            int parametro_NO_OP = atoi(palabras[1])
            for (int i = 0; i< parametro_NO_OP; i++) {
                // hago string_duplicate() para no perder el string al liberar el array
                list_add(proceso_pcb->instrucciones, string_duplicate(palabras[0]));
            }
            // libero "palabras" al final ya que es auxiliar
            string_array_destroy(palabras);
        } else { 
            // ...
        }

        //...
    }

Consejo: traten de ser prolijos con las variables que declaran, o sea, identifiquen cuáles son temporales y se deben liberar al retornar la función y cuáles tienen datos que sí me quiero guardar para después.

También tengan en mente el concepto de "divide y vencerás", o sea, en vez de tener una función grande que pretenda resolverlo todo y resulte difícil de entender y mantener, vayan desmenuzándola en funciones más chiquitas cuya solución sea trivial.

Y por último, hay una frase que dice irónicamente "Weeks of coding can save you hours of planning". O sea, siempre a la larga termina siendo más rápido parar la pelota y planear cómo resolver cada requerimiento antes que apurarse e implementar código que luego lleva más tiempo (y esfuerzo) en corregir.

Saludos

EspositoLucas commented 2 years ago

Buenas . Disculpen que sigamos trabados con esto . @RaniAgus con esta recomendacion de reducir el scope de palabras te referis a para cada validacion de las instrucciones a medida que se haga el parseo o es solo para el NO_OP ? Es decir, te referis a algo asi :

pcb *armar_pcb(t_buffer* buffer) // Para deserializar las instrucciones de consola
 {

     pcb* proceso_pcb = malloc(sizeof(pcb)) ;
     int indice_split = 0 ;
     char* mensaje_consola ; // leido de consola que se envia en el paquete

     // Deserializar los campos del buffer

    mensaje_consola = malloc(buffer->stream_size);
    memcpy(mensaje_consola,buffer->stream ,buffer->stream_size);
    memcpy(&(proceso_pcb->tamanio_proceso),&(buffer->tamanio_proceso) ,sizeof(int));

    char** split_buffer = string_split(mensaje_consola, "\n");
    proceso_pcb->instrucciones = list_create();

    while (split_buffer[indice_split] != NULL) {

        if(string_contains(split_buffer[indice_split], "NO_OP") ) {
            char** palabras = string_split(split_buffer[indice_split], " ") ;
            int parametro_NO_OP = atoi(palabras[1]);
            for(int i=0; i< parametro_NO_OP  ; i++){
                printf("NO_OP %d ", parametro_NO_OP);
                list_add(proceso_pcb->instrucciones,string_duplicate(palabras[0])) ; 
               string_array_destroy(palabras);
            }

        } else if (string_contains(split_buffer[indice_split], "I/O")){
            char** palabras = string_split(split_buffer[indice_split], " ") ;
             int parametro_IO = atoi(palabras[1]);
             printf("I/O %d ", parametro_IO);
             list_add(proceso_pcb->instrucciones,string_duplicate(split_buffer[indice_split])) ;
             string_array_destroy(palabras);
        }
         else if (string_contains(split_buffer[indice_split], "READ")){
            char** palabras = string_split(split_buffer[indice_split], " ") ;
             int parametro_READ = atoi(palabras[1]);
            printf("READ %d ", parametro_READ);
            list_add(proceso_pcb->instrucciones,string_duplicate(split_buffer[indice_split])) ;
            string_array_destroy(palabras);

        } else if (string_contains(split_buffer[indice_split], "WRITE")) {
             char** palabras = string_split(split_buffer[indice_split], " ") ;
             int parametro1_WRITE = atoi(palabras[1]);
             int parametro2_WRITE = atoi(palabras[2]);
             printf("WRITE %d %d ", parametro1_WRITE,parametro2_WRITE);
              list_add(proceso_pcb->instrucciones,string_duplicate(split_buffer[indice_split])) ;
             string_array_destroy(palabras);

        } else if (string_contains(split_buffer[indice_split], "COPY")){
             char** palabras = string_split(split_buffer[indice_split], " ") ;
             int parametro1_COPY = atoi(palabras[1]);
             int parametro2_COPY = atoi(palabras[2]);
             printf("COPY %d %d ", parametro1_COPY,parametro2_COPY);
             list_add(proceso_pcb->instrucciones,string_duplicate(split_buffer[indice_split])) ;
            string_array_destroy(palabras);

        } else if (string_contains(split_buffer[indice_split], "EXIT")){
              char** palabras = string_split(split_buffer[indice_split], " ") ;
            printf("EXIT");
            list_add(proceso_pcb->instrucciones,string_duplicate(split_buffer[indice_split])) ;
            string_array_destroy(palabras);
        }
        indice_split++;
    }    

    string_array_destroy(split_buffer);
    list_destroy(proceso_pcb->instrucciones);
    free(mensaje_consola);

    return proceso_pcb;
}

Es verdad que se repite mucha logica y no se esta respetando lo de dividir las funciones pero estamos trabados en resolver la parte del parseo para cada instrucciones porque los errores en el debug aparecen ahi .

Otra altrnativa mas simple en bae este problema y que otros ayudantes nos sugirieron fueron de usar un switch dependiendo del tipo de isntruccion donde lo tenemos por ahora asi :

pcb *armar_pcb(t_buffer* buffer) // Para deserializar las instrucciones de consola
{

    pcb* proceso_pcb = malloc(sizeof(pcb)) ;
    int indice_split = 0 ;
    char* mensaje_consola ; // leido de consola que se envia en el paquete
    int codigo_instrucciones

    // Deserializar los campos del buffer

   mensaje_consola = malloc(buffer->stream_size);
   memcpy(mensaje_consola,buffer->stream ,buffer->stream_size);
   memcpy(proceso_pcb->tamanio_proceso,&(buffer->tamanio_proceso) ,sizeof(int));
   char** split_buffer = string_split(mensaje_consola, "\n");
   char** palabras ;
   proceso_pcb->instrucciones = list_create();

   while (split_buffer[indice_split] != NULL) {

       switch(codigo_instrucciones) {

           case:NO_OP:
               palabras = string_split(split_buffer[indice_split], " ") ;
               int parametro_NO_OP = atoi(palabras[1]);
               for(int i=0; i< parametro_NO_OP  ; i++){
                   printf("NO_OP %d ", parametro_NO_OP);
                   list_add(proceso_pcb->instrucciones,palabras[0]) ; // Para agregar a lista a medida quese vaya parseando
                   break;
           }

           case:IO:
               int parametro_IO = atoi(palabras[1]);
               printf("I/O %d ", parametro_IO);
               list_add(proceso->instrucciones,split_buffer[indice_split]) ;
               break;

           case:READ:
               int parametro_READ = atoi(palabras[1]);
               printf("READ %d ", parametro_READ);
               list_add(proceso->instrucciones,split_buffer[indice_split]) ;
               break;

           case:WRITE:
               int parametro1_WRITE = atoi(palabras[1]);
               int parametro2_WRITE = atoi(palabras[2]);
               printf("WRITE %d %d ", parametro1_WRITE,parametro2_WRITE);
               list_add(proceso->instrucciones,split_buffer[indice_split]) ;
               break;

           case:COPY:
               int parametro1_COPY = atoi(palabras[1]);
               int parametro2_COPY = atoi(palabras[2]);
               printf("COPY %d %d ", parametro1_COPY,parametro2_COPY);
               list_add(proceso->instrucciones,split_buffer[indice_split]) ;
               break;

           case:EXIT:
               printf("EXIT");
               list_add(proceso->instrucciones,split_buffer[indice_split]) ;
               break;

       }

       indice_split++;
   }

   string_array_destroy(split_buffer);
   string_array_destroy(palabras);
   list_destroy(proceso_pcb->instrucciones);
   free(mensaje_consola);

   return proceso_pcb;
}

en donde todos los case los definimos de tipo enum en codigo_instrucciones pero la logica es la misma que habiamos pensado antes con los if . Habria que hacer lo que dijiste de declarar palabras en el scope de cada instruccion y despues liberarlo o la logica es distinta ?

Basicamente la idea es dividir por listas cada instruccion con sus argumentos a medida que se parsea para agregarla al campo instrucciones del pcb . Espero que se hay aentendido la duda y donde esta el error que no sabemos solucionar

Saludos

iago64 commented 2 years ago

Buenas! Cómo va?

Vengo siguiendo el tema pero no quería interferir con las respuestas de Agus, pero estoy notando que se estan empezando a enroscar y siento que primero necesitan el problema para poder resolverlo, para ello les dejo algunos comentarios:

1.- El concepto de divide y vencerás sugiere que separes el problema grande en problemas mas chicos, nadie esta diciendo que no puedan tener lógica repetida, lo importante es que no quieran construir las pirámides de una, con lo cual ahí, sería una buena práctica que frenen un toque, vean que les llega de memoria y en base a eso planteen la estrategia en papel y una vez que están de acuerdo con la estrategia en papel, la pasen a código.

Un ejemplo de la estrategia en papel sería: Toman el contenido del archivo que leyeron y le mandaron al kernel y ahí lo separan primero por los '\n' para tener cada línea de instrucción y después lo separan por los espacios para tener la operación y sus operandos (en caso de que los tenga) y que mas o menos cuadra con lo último que tienen en el último bodoque de código. Con la salvedad de que en el código que pasaron no va a funcionar porque nunca están seteando el valor de codigo_instrucciones.

2.- El tema del scope de las variables, es muy útil que entiendan donde sirve cada variable, es decir, si una variable solo tiene sentido dentro de una función, declárenla ahí y que muera ahí, por ejemplo variables auxiliares para parsear el texto, ahora distinto es si eso que están reservando es algo que van a necesitar afuera (por ejemplo la lista de instrucciones del PCB).

3.- Con los errores generalmente podemos guiarlos en donde pueden estar, pero es importante que puedan encontrarlos por su cuenta, si no lo que va a pasar es que cuando estemos llegando a la fecha de entrega y la mayoría de grupos empiece a tener problemas con el código o con errores que no saben por donde vienen, no vamos a dar abasto en ayudar, por eso van a notar que nuestras respuestas son mas bien una "guía" de como lo pueden resolver uds y no un: Hacelo así, porque ahí pasan 2 cosas muy malas, en primer lugar Uds no aprenden a resolver problemas por su cuenta (cosa fundamental para un ingeniero) y segundo no entienden que pasa y por lo tanto si les vuelve a pasar van a volver a frenarse y posiblemente sumen una cuota de frustración porque el problema ya lo vieron pero aplican la misma receta que antes les funcionó y si no funciona es una traba mas.

4.- Un error muy común que estoy viendo no solo en este issue es que asumen que nosotros como ayudantes vemos el código y encontramos los errores y eso no puede estar mas lejos de la realidad, al igual que uds tenemos que copiar el código, compilarlo y hacer muchas veces pruebas acotadas para entender que están haciendo y ver si concuerda con lo que quieren hacer, con lo cual, fragmentos de código que no compila no nos ayuda a ayudarlos.

Perdón por el wall of text pero creo que si paramos la pelota vamos a poder llegar a buen puerto, caso contrario vamos a seguir en un while(1)

Saludos.-

EspositoLucas commented 2 years ago

@iago64 Buenas Damian . Tenes razon, nos estamos apurando a la hora de preguntar y ver con detenimiento donde esta el problema, y esto se debe al miedo a atrasarnos porque sentimos que no estamos avanzando lo esperado comparado con otros grupos y lo pautado en los checkpoints . Le estamos metiendo lo que podemos, tratando de consultar con ustedes y/o de otras fuentes pero aun asi nos cuesta plantear la forma en como encarar las distintas partes del trabajo practico . Evidentemente no esta bien porque habla mal sobre nuestra organizacion como grupo y que realmente hay temas que no sabemos aplicar porque cuesta interpretar, sumado tambien a las complicaciones del lenguaje C . Disculpen si los abrumamos con estas cuestiones que parecieran ser faciles de resolver y capaz al ser la primera experiencia con el trabajo nos resulte complicado manejarlo y distribuirlo de la mejor manera para evitar ests problemas basicos que no podemos resolver . Trataremos en lo posible corregir estos errores y hacer, cuando sea necesario, las consultas pertinentes . Gracias por el feedback

Saludos,

Lucas

iago64 commented 2 years ago

@EspositoLucas Cómo va? Por favor no se comparen con otros grupos porque cada grupo es un mundo y viven realidades diferentes y van a acumular desesperación sin sentido, mismo los checkpoints son una guía, si no los cumplen a rajatabla no hay problema, por eso hay 3 fechas de entrega y no solo una 😉

Respecto a como ordenar el laburo, esa es una hermosa pregunta que nos pueden hacer, en lugar de tirarse al vacío a codear sin orden, pueden preguntarnos como ordenar el desarrollo o por donde les puede convenir encarar las cosas. Capaz crean que son preguntas "simples", pero no hay nada de simple, de hecho el organizarse es algo fundamental y es una de las primeras cosas que siempre esperamos que nos pregunten aunque realmente pocas veces pasa. Por otro lado, el tema de C, un poco mas de lo mismo, traten de no mandarse a codear líneas y líneas, hagan algo chico, por ejemplo para un archivo que solo tenga NO_OP y EXIT, cuando les funcione, ahí se mandan a hacer mas cosas y de a poco van arrancando.

Que se descoordinen como grupo es normal, están en la universidad y están aprendiendo a trabajar en equipo, si hasta pasa en empresas grandes con áreas de planeamiento, agile coachs y demás puestos dedicados a organizar, como no les va a pasar a un grupo de estudiantes, no se preocupen, pregunten, mándennos un mail preguntándonos como pueden organizar las tareas, los ayudantes así como siempre decimos que no somos compiladores humanos, también les digo que somos humanos y que podemos ayudarlos con cosas no técnicas (que casualmente suele ser el factor número 1 de que los tps sean tan complicados).

Si necesitan charlar esto capaz de manera presencial, el sábado voy a estar por campus y como hay parcial seguramente tenga tiempo para charlar y/o empezar a diagramar algunas pruebas del TP, asique si quieren mándenme un mensaje privado por Discord y coordinamos para charlar un rato (si rinden a la mañana puede ser post parcial) y vemos como se pueden organizar para destrabarse y avanzar con el TP.

Abrazo!

EspositoLucas commented 2 years ago

Buenas ! Hoy estuvimos conversando junto al grupo con el ayudante @iago64 Damian y nos estuvo dando consejos de como avanzar sobre estos errores . Como el issue se hico bastante largo, lo voy a dar por cerrado y cualquier otra duda que surja en base a lo charlado, abrire otro consultando . Gracias y Saludos

EspositoLucas commented 2 years ago

Buenas ! Perdonen que sigamos con el tema pero nos surgió un nuevo problema . Estuvimos corrigiendo el parseo donde en base a la recomendacion de @iago64 Damian, decidimos crear una estructura instruccion que tenga un campo de tipo enum que serian el codigo_instrucciones y dos campos de tipo int que serian los paramtros de las instrucciones . Seria algo asi :

typedef struct {
    codigo_instrucciones codigo ;
    int parametro1;
    int parametro2;
}instruccion ;

Esta estructura es par cuando una vez que se haya parseado por " " con el segundo split, en este casopalabras a partir del primer split con "\n" con split_buffer , directamente ir agregando a la lista e instrucciones del pcb el codigo y los parametros, en caso de tenerlos . Entiendo que la logica de esa parte esta ok pero el problema al usar el debug esta en el primer string_split en split_buffer donde aparece el error de segmentation fault porque no reconoce el lugar asignado de split_buffer con el string_split :

No source available for "string_split() at 0xb7fb19fb" No source available for "_string_split() at 0xb7fb2140"

Y este es el codigo de la funcion donde surje todo el problema :

pcb *armar_pcb(t_buffer* buffer) // Para deserializar las instrucciones de consola

{
    pcb* proceso_pcb = malloc(sizeof(pcb)) ;
    int indice_split = 0 ;
    char* mensaje_consola = malloc(buffer->stream_size) ; // leido de consola que se envia en el paquete
    free(buffer);
    buffer = malloc(sizeof(t_buffer)) ;

     // Deserializar los campos del buffer

//    mensaje_consola = malloc(buffer->stream_size);

    memcpy(mensaje_consola,buffer->stream ,buffer->stream_size);
    memcpy(&(proceso_pcb->tamanio_proceso),&(buffer->tamanio_proceso) ,sizeof(int));
    char** split_buffer = string_split(mensaje_consola, "\n");
    proceso_pcb->instrucciones = list_create();
    while (split_buffer[indice_split] != NULL) {

        if(string_contains(split_buffer[indice_split], "NO_OP") ) {
            char** palabras = string_split(split_buffer[indice_split], " ") ;
            int parametro_NO_OP = atoi(palabras[1]);
            for(int i=0; i< parametro_NO_OP  ; i++){
                // printf("NO_OP %d ", parametro_NO_OP);
                instruccion* instruccion_No_op = malloc(sizeof(instruccion));
                instruccion_No_op->codigo = NO_OP ;
                list_add(proceso_pcb->instrucciones,instruccion_No_op) ; // Para agregar a lista a medida quese vaya parseando
                free(instruccion_No_op);
            }
        string_array_destroy(palabras);

    } else if (string_contains(split_buffer[indice_split], "I/O")){
            char** palabras = string_split(split_buffer[indice_split], " ") ;
            int parametro_IO = atoi(palabras[1]);
            // printf("I/O %d ", parametro_IO);
            instruccion* instruccion_IO = malloc(sizeof(instruccion));
            instruccion_IO->codigo = IO ;
            instruccion_IO->parametro1= parametro_IO ;
            list_add(proceso_pcb->instrucciones,instruccion_IO) ;
            string_array_destroy(palabras);
            free(instruccion_IO) ;
    }

    else if (string_contains(split_buffer[indice_split], "READ")){
            char** palabras = string_split(split_buffer[indice_split], " ") ;
            int parametro_READ = atoi(palabras[1]);
            instruccion* instruccion_READ = malloc(sizeof(instruccion));
            instruccion_READ->codigo = READ ;
            instruccion_READ->parametro1= parametro_READ ;
            // printf("READ %d ", parametro_READ);
            list_add(proceso_pcb->instrucciones,instruccion_READ) ;
            string_array_destroy(palabras);
            free(instruccion_READ);

    } else if (string_contains(split_buffer[indice_split], "WRITE")) {
            char** palabras = string_split(split_buffer[indice_split], " ") ;
            int parametro1_WRITE = atoi(palabras[1]);
            int parametro2_WRITE = atoi(palabras[2]);
            instruccion* instruccion_WRITE = malloc(sizeof(instruccion));
            instruccion_WRITE->codigo = WRITE ;
            instruccion_WRITE->parametro1= parametro1_WRITE ;
            instruccion_WRITE->parametro2= parametro2_WRITE ;
            // printf("WRITE %d %d ", parametro1_WRITE,parametro2_WRITE);
            list_add(proceso_pcb->instrucciones,instruccion_WRITE) ;
            string_array_destroy(palabras);
            free(instruccion_WRITE);

    } else if (string_contains(split_buffer[indice_split], "COPY")){
            char** palabras = string_split(split_buffer[indice_split], " ") ;
            int parametro1_COPY = atoi(palabras[1]);
            int parametro2_COPY = atoi(palabras[2]);
            instruccion* instruccion_COPY = malloc(sizeof(instruccion));
            instruccion_COPY->codigo = COPY ;
            instruccion_COPY->parametro1= parametro1_COPY ;
            instruccion_COPY->parametro2= parametro2_COPY ;
            printf("COPY %d %d ", parametro1_COPY,parametro2_COPY);
            list_add(proceso_pcb->instrucciones,instruccion_COPY) ;
            string_array_destroy(palabras);
            free(instruccion_COPY);

    } else if (string_contains(split_buffer[indice_split], "EXIT")){
            instruccion* instruccion_EXIT = malloc(sizeof(instruccion));
            instruccion_EXIT->codigo = EXIT ;
            // printf("EXIT");
            list_add(proceso_pcb->instrucciones,instruccion_EXIT) ;
            free(instruccion_EXIT);
    }
        indice_split++;
    }
    string_array_destroy(split_buffer);
    list_destroy(proceso_pcb->instrucciones);
    free(mensaje_consola);
//    free(buffer);

    return proceso_pcb;
}

Estuvimos tratando de ver si el problema tenia que ver con que no habia lugar en memoria para hacer el split a partir de lo que se recibia por el buffer->stream porque en base a lo que nos comento @RaniAgus Agustin, la idea no es hacer un malloc y luego el split al split_buffer porque se estaria teniendo un memory leak al estar reservando memoria con malloc() y luego pisar ese puntero con el que devuelve string_split() . Pero aun asi, no sabemos porque si evitamos eso se produce otro segmentation fault

Disculpen de nuevo las molestias con el asunto pero nos molesta que a pesar de haber corregido el tema del parseo, sigan apareciendo los mismo errores .

Saludos

RaniAgus commented 2 years ago

¡Buenas! ¿buffer->stream contiene solamente un string con todas las instrucciones, cierto?

Recordando que los strings tienen un caracter '\0' al final:

image

¿Desde la Consola están enviando todo el string (incluyendo el '\0') o solo están pasando el tamaño que devuelve strlen()?

Si es la segunda opción, deben también pasar el '\0' (o sea, reservar un byte más y copiar strlen() + 1).

Saludos

EspositoLucas commented 2 years ago

Claro, en consola se envia todo el string incluyendo el '\0' por eso se le pasa directamente a mensaje_consola el buffer->stream porque se supone que ya incluye ese byte . El codigo en consola es este :

void paquete_proceso(int conexion){

    t_paquete *paquete = crear_paquete();
    char* leido = leer_archivo("instrucciones.txt");

    agregar_a_paquete(paquete, leido, strlen(leido)+1 );

    enviar_paquete(paquete, conexion);
    eliminar_paquete(paquete);

}

Hay algo mal en el codigo o en la logica del envio del paquete o a la hora de hacer el memcpy en armar_pcb ?

RaniAgus commented 2 years ago

Tranqui, no hace falta que me pases todo el código 😅 Con que revisen si se estaba enviando o no el \0 está bien.

Ahí me puse a revisar mejor y vi que están liberando el buffer antes de extraer su contenido:

    free(buffer);
    buffer = malloc(sizeof(t_buffer));

Recuerden que el debugger no solo es útil para saber en qué línea rompe un programa, sino también para monitorear el estado de las variables línea por línea. Por favor estén más atentos la próxima.

También veo que están liberando atributos de proceso_pcb que probablemente no quieran liberar ya que les van a servir para más adelante. 😉

Saludos

EspositoLucas commented 2 years ago

Buenas @RaniAgus No entendi Agustin relamente el error. Entiendo el problema de haber liberado el buffer antes de asignar el malloc pero no me quedo claro lo del tema de liberar los atributos del proceso_pcb . Te referis a esta parte del codigo :

list_destroy(proceso_pcb->instrucciones);
 free(mensaje_consola);

o también cuando se agregan a la lista (en el parseo) y despues se liberan las instrucciones ? Por ejemplo aca :

 list_add(proceso_pcb->instrucciones,instruccion_No_op) ; // Para agregar a lista a medida quese vaya parseando
                free(instruccion_No_op);
            }
        string_array_destroy(palabras);

Saludos

RaniAgus commented 2 years ago

Tengan en cuenta que:

        struct link_element{
        void *data;
        struct link_element *next;
    };
    typedef struct link_element t_link_element;

(Recordemos que un puntero es un número entero no signado de 4 bytes que indica una posición de memoria sin importar lo que contenga)

Les hago un ejemplito con 2 instrucciones para que visualicen lo que contiene el pcb que armaron (un cuadradito es 1 byte). Según la implementación que pasaste antes, solo lo verde termina quedando en memoria, el resto está siendo liberado en distintas partes del código marcadas con distintos colores:

File_000

El resto se los dejo para que lo piensen ustedes.

Saludos

EspositoLucas commented 2 years ago

Buenas . @RaniAgus Hoy nos conectamos en soporte y ahondamos en este problema sobre las liberaciones innecesarias que provocaban que el buffer y la lista estén apuntando a contenido basura por ser liberado antes de haber terminado con su uso . Entonces, decidimos usar el free() solo cuando ya el puntero no se este usando mas en otro lado que sea necesario . Por lo que el codigo quedaria algo asi mas o menos :

pcb *armar_pcb(t_buffer* buffer) // Para deserializar las instrucciones de consola

{
    pcb* proceso_pcb = malloc(sizeof(pcb)) ;
    int indice_split = 0 ;
    char* mensaje_consola = malloc(buffer->stream_size) ; // leido de consola que se envia en el paquete

     // Deserializar los campos del buffer

    memcpy(mensaje_consola,buffer->stream ,buffer->stream_size);
    memcpy(&(proceso_pcb->tamanio_proceso),&(buffer->tamanio_proceso) ,sizeof(int));
    char** split_buffer = string_split(mensaje_consola, "\n");
    proceso_pcb->instrucciones = list_create();
    while (split_buffer[indice_split] != NULL) {

        if(string_contains(split_buffer[indice_split], "NO_OP") ) {
            char** palabras = string_split(split_buffer[indice_split], " ") ;
            int parametro_NO_OP;
            if(palabras[1]==NULL){parametro_NO_OP=1;}
            else{
            parametro_NO_OP= atoi(palabras[1]);}
            for(int i=0; i< parametro_NO_OP  ; i++){
                instruccion* instruccion_No_op = malloc(sizeof(instruccion));
                instruccion_No_op->codigo = NO_OP ;
                list_add(proceso_pcb->instrucciones,instruccion_No_op) ; // Para agregar a lista a medida quese vaya parseando
            }
        string_array_destroy(palabras);

    } else if (string_contains(split_buffer[indice_split], "I/O")){
            char** palabras = string_split(split_buffer[indice_split], " ") ;
            int parametro_IO = atoi(palabras[1]);
            instruccion* instruccion_IO = malloc(sizeof(instruccion));
            instruccion_IO->codigo = IO ;
            instruccion_IO->parametro1= parametro_IO ;
            list_add(proceso_pcb->instrucciones,instruccion_IO) ;
            string_array_destroy(palabras);
    }

    else if (string_contains(split_buffer[indice_split], "READ")){
            char** palabras = string_split(split_buffer[indice_split], " ") ;
            int parametro_READ = atoi(palabras[1]);
            instruccion* instruccion_READ = malloc(sizeof(instruccion));
            instruccion_READ->codigo = READ ;
            instruccion_READ->parametro1= parametro_READ ;
            list_add(proceso_pcb->instrucciones,instruccion_READ) ;
            string_array_destroy(palabras);

    } else if (string_contains(split_buffer[indice_split], "WRITE")) {
            char** palabras = string_split(split_buffer[indice_split], " ") ;
            int parametro1_WRITE = atoi(palabras[1]);
            int parametro2_WRITE = atoi(palabras[2]);
            instruccion* instruccion_WRITE = malloc(sizeof(instruccion));
            instruccion_WRITE->codigo = WRITE ;
            instruccion_WRITE->parametro1= parametro1_WRITE ;
            instruccion_WRITE->parametro2= parametro2_WRITE ;
            list_add(proceso_pcb->instrucciones,instruccion_WRITE) ;
            string_array_destroy(palabras);

    } else if (string_contains(split_buffer[indice_split], "COPY")){
            char** palabras = string_split(split_buffer[indice_split], " ") ;
            int parametro1_COPY = atoi(palabras[1]);
            int parametro2_COPY = atoi(palabras[2]);
            instruccion* instruccion_COPY = malloc(sizeof(instruccion));
            instruccion_COPY->codigo = COPY ;
            instruccion_COPY->parametro1= parametro1_COPY ;
            instruccion_COPY->parametro2= parametro2_COPY ;
            printf("COPY %d %d ", parametro1_COPY,parametro2_COPY);
            list_add(proceso_pcb->instrucciones,instruccion_COPY) ;
            string_array_destroy(palabras);

    } else if (string_contains(split_buffer[indice_split], "EXIT")){
            instruccion* instruccion_EXIT = malloc(sizeof(instruccion));
            instruccion_EXIT->codigo = EXIT ;
            list_add(proceso_pcb->instrucciones,instruccion_EXIT) ;
        indice_split++;
    }
    string_array_destroy(split_buffer);
    free(mensaje_consola);
    free(buffer);

    return proceso_pcb;
}

No se si es eso lo que se esperaba pero todavia no lo probe porque me saltaron errores en otras partes que hacen que con el debug no se llegue a la parte de la deserialización . Cuando lo corrija y pruebe esto aviso cualquier cosa que tal anduvo este cambio

Saludos

LeandroCarbajales commented 2 years ago

Cierro el issue por inactividad, cualquier cosa abren otro si tienen más dudas :)