sisoputnfrba / foro

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

Problema al hacer memcpy de char* casteado a void* #3823

Closed pfernandezUTN closed 4 months ago

pfernandezUTN commented 4 months ago

Buenas tardes. Tenemos problemas al intentar guardar char en la memoria. El problema en general es que si yo hago el memcpy con un char anda todo bien, pero, ya que tambien espero recibir numeros, necesito usar un void. Y en este caso, funciona bien para numeros pero con los char no.

🔎 Búsqueda en foros

La posible solucion que encontramos en internet es recorrer el char* y pasarlo a ascii caracter por caracter para despues guardarlo. Esto no nos parece muy logico y creemos que deberia haber una forma de hacerlo directamente.

📝 Código relevante

void hacer_pedido_escritura(t_list* lista){
        uint32_t df = (uint32_t)list_get(lista, 1); 
        uint32_t size = (uint32_t)list_get(lista, 2);
        uint32_t pid = (uint32_t)list_get(lista, 3);
        void * elemento_a_insertar = malloc(size);
        elemento_a_insertar = list_get(lista, 4);
        uint32_t marco = floor(df / tam_pag);
        log_debug(logger, "Marco: %d", marco);
        log_info(logger,"PID: <%u> - Accion: <ESCRIBIR> - Direccion fisica: %u - Tamaño <%u>", pid, df, size);

        while (size) {
            uint32_t memoria_disponible  = ((marco + 1) * tam_pag - df);
            if (memoria_disponible > size) {
                memcpy(espacio_memoria + df, &elemento_a_insertar, size);
                size = 0;
            }
            else {  
                memcpy(espacio_memoria + df, elemento_a_insertar, memoria_disponible);
                size -= memoria_disponible;
                elemento_a_insertar += memoria_disponible;
                marco = conseguir_siguiente_marco(pid,marco);
                df = marco * tam_pag;
            }
        }
        mem_hexdump(espacio_memoria, tam_memoria);
       // mas cosas...
}

🐛 Cómo reproducir el error

Principalmente lo que probamos fue una direccion fisica de 0, un largo de 1B y el texto "A", Esto lo que nos hace es que guarda en memoria el hexa "4c", que no corresponde a la letra "A". Ademas, ese resultado nos lo devuelve siempre, sin importar el texto en cuestion.

💻 Logs

Este print es el mem_hexdump que hace al final de la funcion: imagen

iago64 commented 4 months ago

Buenas! Cómo va?

Una pregunta, en que parte del if() deberían caer? Porque tienen diferentes los memcpy() y justamente en uno pasan el elemento_a_insertar y en otro la dirección de ese elemento &elemento_a_insertar.

Saludos.-

pfernandezUTN commented 4 months ago

Si, es verdad, gracias. Eso es algo que nos olvidamos de cambiar por que lo corregimos mientras probabamos, igual no soluciona el problema ya que siempre estamos entrando al de arriba para hacer estas pruebas.

iago64 commented 4 months ago

Buenas! Cómo va?

Justamente que sea en el true del if me preocupa ya que list_get() les devuelve un puntero y uds estan pasándole la dirección del puntero.

De todas formas, probaron debugueandolo y viendo el contenido de esa variable justo en la línea anterior a hacer el memcpy()?

Saludos.-

pfernandezUTN commented 4 months ago

Todo bien, vos?

Ahi entendimos a lo que te referis... el problema es que uno de los datos ya es un puntero (char*) y el otro no (uint), entonces no se puede guardar los datos de la misma forma. Por lo tanto, seria necesario hacer que ponga el & en el memcpy si es un numero y que no si es un texto. verdad?

iago64 commented 4 months ago

Buenas!

Memoria es Memoria, después como la quieras interpretar vos es otro tema ya que char * o void * son punteros a memoria en tu caso, list_get() te devuelve un puntero (void *) y si vos le pones & adelante en memcpy(), estas diciéndole que copie la dirección de memoria de tu variable y no el contenido de tu variable.

Saludos.-

RaniAgus commented 4 months ago

¡Buenas! Me sumo para agregar un par de cosas a tener en cuenta:

1) ¿Cómo están agregando los elementos a la lista? Si usan el debugger, al recuperarlos, ¿les devuelve los mismos valores que agregaron?

2) Los punteros son simplemente números enteros que indican una posición de memoria, o sea, un índice dentro de ese gran array de bytes de memoria de un proceso. Entonces, en estas dos líneas:

void * elemento_a_insertar = malloc(size);
elemento_a_insertar = list_get(lista, 4);

Primero están iniciando la variable elemento_a_insertar con una dirección de memoria devuelta por malloc() (ejemplo: 0x1234) y luego están sobreescribiendo ese puntero, esa dirección de memoria por el contenido del quinto elemento de la lista (por ejemplo: 0x5678).

Esto significa que la memoria que se encuentra en 0x1234 no va a estar siendo apuntada por ninguna variable, lo cual es un memory leak ya que es memoria que no se utiliza ni se libera.

Para obtener ese valor de la lista simplemente pueden hacer:

void * elemento_a_insertar = list_get(lista, 4);

O, si quieren hacer una copia, deben rellenar el contenido apuntado por el primer puntero con memcpy():

void * elemento_a_insertar = malloc(size);
memcpy(elemento_a_insertar, list_get(lista, 4), size);

3) En lugar de usar una lista para almacenar los valores (que a su vez tienen distintos tipos, y deben de alguna forma recordar el orden de cada uno al recuperarlos), ¿no convendría utilizar un struct que contenga cada campo con su tipo y nombre correctos?

typedef struct {
    uint32_t df;
    uint32_t size;
    uint32_t pid;
    void *elemento_a_insertar;
} t_pedido_escritura;

Saludos

pfernandezUTN commented 4 months ago

Buenos dias a ambos, muchas gracias por las respuestas.

Respondiendo al mensaje de Damian, si, es como decis. La solucion que nosotros es que le ponemos el & solamente cuando queremos escribir un uint ya que memcpy espera un void en el dato a escribir y, por la misma razon, no se lo ponemos cuando escribimos un char. Eso esta resuelto. Muchas gracias por la ayuda.

Sobre lo de Agus:

1- La lista la obtenemos de una funcion que recibe los paquetes enviados desde otro modulo por el socket, en definitiva hace list_add de un valor uint o char*.

2- Sobre esto, gracias por la correxion. Vamos a hacer los cambios mencionados.