Obtener la dirección incorrecta de una variable durante una llamada de función

Estoy perdiendo la dirección de una variable (global) (definida en un objeto compartido) cuando se realiza una llamada a una función. Para probarlo, establecí intencionalmente el valor de la variable num_accounts en 55, cuando la función get_num_accounts () comenzó la ejecución, el puntero a esta variable se recibió incorrectamente. Mi prueba es esta sesión gdb:

accounts_init () at accounts.c:31 31 err_code=read_accounts(); (gdb) print num_accounts $1 = 0 (gdb) print &num_accounts $2 = (account_idx_t *) 0x7ffff767c640  (gdb) set var num_accounts=55 (gdb) print num_accounts $3 = 55 (gdb) s read_accounts () at accounts.c:66 66 err_code=get_num_accounts(&num_accounts); (gdb) s get_num_accounts (num_accounts_ptr=0x604780 ) at accounts.c:119 119 *num_accounts_ptr=0; (gdb) print num_accounts $4 = 55 (gdb) print *num_accounts_ptr $5 = 0 (gdb) (gdb) print num_accounts_ptr $6 = (account_idx_t *) 0x604780  (gdb) 

La dirección de la variable num_accounts es 0x7ffff767c640 , pero obtengo 0x604780 cuando se ejecuta la función, ¿por qué ocurren cosas tan extrañas?

El código fuente de la función get_num_accounts () es este:

 err_code_t get_num_accounts(account_idx_t *num_accounts_ptr) { err_code_t err_code; uint32_t file_size; div_t div_result; unsigned short number; *num_accounts_ptr=0; err_code=get_dir(); if (err_code!=ERR_NO_ERROR) return err_code; err_code=get_file(ACCOUNTS_FILENAME,sizeof(ACCOUNTS_FILENAME),&file_size); if (err_code!=ERR_NO_ERROR) return err_code; div_result=div(file_size,sizeof(tbl_account_t)); if (div_result.rem!=0) { return ERR_BAD_CONFIG_FILE_FORMAT; } number=div_result.quot; *num_accounts_ptr=number; return ERR_NO_ERROR; } 

El tipo account_idx_t se define como:

 typedef unsigned short account_idx_t; 

La variable global num_accounts se define en el archivo accounts.c al principio:

 account_idx_t num_accounts=0; 

Básicamente, lo que hace la función, es obtener el tamaño del archivo y calcular el número de registros que contiene el archivo, antes de leerlo. (es una base de datos)

Y este es el código de llamada, que funcionan las calles get_num_accounts ():

 err_code_t accounts_init(void) { err_code_t err_code; err_code=read_accounts(); if (err_code!=ERR_NO_ERROR) return err_code; return ERR_NO_ERROR; } err_code_t read_accounts(void) { err_code_t err_code; int ret; err_code=get_num_accounts(&num_accounts); if (err_code!=ERR_NO_ERROR) return err_code; if (num_accounts==0) return ERR_NO_ERROR; int fd=open(filename_buf,O_RDONLY); // filename_buf is global, it holds filename from previous call if (fd==-1) { return ERR_SYS_ERROR; } ret=read(fd,accounts,sizeof(tbl_account_t)*num_accounts); if (ret==-1) { return ERR_SYS_ERROR; } ret=close(fd); // TO_DO: validate return value of close(fd) if (ret==-1) { return ERR_SYS_ERROR; } return ERR_NO_ERROR; } 

Estoy comstackndo la biblioteca con el indicador -fPIC:

 [niko@dev1 src]$ make accounts.o gcc -g -ffunction-sections -fdata-sections -Wall -Wextra -Wunreachable-code -Wmissing-prototypes -Wmissing-declarations -Wunused -Winline -Wstrict-prototypes -Wimplicit-function-declaration -Wformat -D_GNU_SOURCE -fshort-enums -fPIC -c accounts.c 

No hay otro símbolo ‘num_accounts’ en ninguna parte del código fuente, verifiqué dos veces que:

 [niko@dev1 src]$ nm *o|grep num_accounts 0000000000000000 T get_num_accounts 0000000000000000 B num_accounts [niko@dev1 src]$ 

¿Alguna sugerencia sobre otros pasos de depuración?

Tiene dos símbolos distintos llamados num_accounts en la imagen ejecutable que gdb está mirando. gdb le dice eso directamente, ya que cada vez que le dice que imprima algo que tiene un valor tipo puntero, gdb hará una búsqueda inversa de esa dirección en la tabla de símbolos del ejecutable y, si encuentra algo, imprimirá el nombre del símbolo en <>. Así que cuando haces el comando gdb:

 (gdb) print &num_accounts $2 = (account_idx_t *) 0x7ffff767c640  

gdb te está diciendo que 0x7ffff767c640 apunta a un símbolo llamado num_accounts . Similar,

 (gdb) print num_accounts_ptr $6 = (account_idx_t *) 0x604780  

te dice 0x604780 puntos en un símbolo que también se llama num_accounts .

Ahora la pregunta es cómo obtuviste dos símbolos con el mismo nombre. La dirección grande 0x7ffff767c640 estará en una biblioteca compartida, ya que las bibliotecas compartidas se cargan en direcciones como esa. La pequeña dirección 0x604780 está en el ejecutable base.