|
[ salec @ 15.06.2004. 16:20 ] @
| Odmah da kazem, procitao sam sta sam nasao o problemima sa scanfom na ES-u, ali jednostavno nije ono na sta je upozoravano, izgleda mi kao da sscanf radi, osim kad treba da konvertuje jednu od konstanti u broj.
Code:
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include "sjet_config.h"
int main(int argc, char *argv[])
{
char *file_name = "./sjet_config.d";
FILE *config_file;
char line[MAXLINE]; /* a place for a line from config file */
char parms[2][MAXLINE];
unsigned long int address;
unsigned char data;
int result1, result2, result3;
if (argc > 1)
{
file_name = argv[1];
}
config_file = fopen(file_name, "r");
if (config_file == NULL)
{
printf("Input file %s is missing! \n", file_name);
return EXIT_FAILURE;
}
else
{
while(!feof(config_file))
{
fgets( line, MAXLINE, config_file );
printf("%s",line);
if((*line) !='\n')
{
result1 = sscanf(line, " %s %s", &(parms[0][0]), &(parms[1][0]));
printf("parms0: %s\n", parms[0] );
printf("parms1: %s\n", parms[1]);
printf("result: %d\n", result1);
result2 = sscanf(parms[0], "%i", &address);
result3 = sscanf(parms[1], "%i", &data);
printf("Address: 0x%x, Data: 0x%x \t %d \t %d \n\n",address, data, result2, result3 );
}
}
fclose( config_file );
}
return EXIT_SUCCESS;
}
Ulazni fajl sjet_config.d izgleda ovako:
Code:
0x31 0x32
0x33 0x34
0x35 0x36
0x37 0x38
0x39 0x3a
a ispis ovako:
Code:
[salec@salec src]$ ./sjet_config
0x31 0x32
parms0: 0x31
parms1: 0x32
result: 2
Address: 0x0, Data: 0x32 1 1
0x33 0x34
parms0: 0x33
parms1: 0x34
result: 2
Address: 0x0, Data: 0x34 1 1
0x35 0x36
parms0: 0x35
parms1: 0x36
result: 2
Address: 0x0, Data: 0x36 1 1
0x37 0x38
parms0: 0x37
parms1: 0x38
result: 2
Address: 0x0, Data: 0x38 1 1
0x39 0x3a
parms0: 0x39
parms1: 0x3a
result: 2
Address: 0x0, Data: 0x3a 1 1
Koliko ja ovo razumem, linija iz fajla je procitana kako valja sa fgets, sscanf je prvi put lepo rasclanio na dva stringa (i uredno javio da je nasao dva podatka), koji su tacno ucitani u parms[0] i parms[1], ali onda sledeci put iz parms[0] uredno procita podatak (vrati 1) ali ga ili ne dodeli ili ga na neku cudnu foru pretvori u 0, dok nad parms[1] sve prodje OK.
Pa, nije mi jasno otkud ta razlika u tretmanu? |
[ blaza @ 15.06.2004. 17:18 ] @
Mozda je sve ok, ali te zeza format specifikator %x, koji si koristio bez prethodnog type casting-a.
[ salec @ 15.06.2004. 17:44 ] @
Mislis u format stringu printf-a? I ja sam se ponadao da je to, pa sam pokusao sa %d umesto 0x%x, medjutim razlika je u tome sto mi ispise 0 umesto 0x0.
[ blaza @ 15.06.2004. 17:49 ] @
Ispravka:
Proveri:
sizeof(address) i sizeof(data), kao i adrese: &address i &data.
Posto nisi koristio type casting (gde je trebalo), mislim da dolazi do sledeceg:
-sscanf(parms[0]... odradi posao, ali onda
-sscanf(parms[1]... takodje odradi posao, ali pri upisu vrednosti u memorijske lokacije koje zauzima varijabla data narusi sadrzaj memorijskih lokacija koje zauzima varijabla address upisujuci 0 u 3 bajta (ako je sizeof(data) ==1).
[ salec @ 16.06.2004. 09:56 ] @
Promenio sam ¨data¨ iz char u int i sada ispisuje tacne vrednosti. Veliko ti hvala!
Stidim se sto mi je to promaklo, jer sada kad si mi otkrio resenje izgleda mi i logicno...
Uz to, i naslov teme je onda pogresan, jer problem i nema veze sa sscanf-om.
Cisto da potvrdim, vratio sam sve kako je bilo i ubacio sam jos jednu zrtvenu varijablu, dummy, izmedju address i data,
Code:
....
unsigned long int address;
unsigned int dummy; /* izvini, lutko! */
unsigned char data;
int result1, result2, result3;
....
koju postavljam na -1 (tj. sve FF) u svakom prolazu kroz petlju koja cita linije, a onda je ispisujem:
Code:
while(!feof(config_file))
{
fgets( line, MAXLINE, config_file );
printf("%s",line);
if((*line) !='\n')
{
dummy = -1;
result1 = sscanf(line, " %s %s", &(parms[0][0]), &(parms[1][0]));
printf("parms0: %s\n", parms[0] );
printf("parms1: %s\n", parms[1]);
printf("result: %d\n", result1);
result2 = sscanf(parms[0], "%i", &address);
result3 = sscanf(parms[1], "%i", &data);
printf("Address: 0x%x, Data: 0x%x \t %d \t %d \tDummy: 0x%x \n\n",address, data, result2, result3, dummy );
}
}
i dobijem ispis na pr.:
Code:
0x31 0x32
parms0: 0x31
parms1: 0x32
result: 2
Address: 0x31, Data: 0x32 1 1 Dummy: 0xff000000
odakle se jasno vidi ono sto si mi i rekao: 32-bitni int se upisuje u char, i naravno, gornjih 24 bita zavrsi ¨u komsiluku¨ (da je masina kojim slucajem obrnuti ¨indijanac¨, u data bi uvek bila 0, koja god osmobitna konstanta pisala u fajlu). Ali kad stavim
Code:
....
unsigned long int address;
unsigned int dummy; /* izvini, lutko! */
unsigned int data; /* dovoljno mesta */
int result1, result2, result3;
....
kako treba, ispis je u skladu sa planiranim, dummy nije ¨pregazena¨:
Code:
0x31 0x32
parms0: 0x31
parms1: 0x32
result: 2
Address: 0x31, Data: 0x32 1 1 Dummy: 0xffffffff
[ salec @ 16.06.2004. 10:07 ] @
Inace, kako je trebalo da u ovom primeru upotrebim type casting (tj. na kom mestu)? Kompajler mi odbija da prihvati type casting nad lvalue, tj. ako probam nesto kao:
Code: result3 = sscanf(parms[1], "%i", &( (unsigned int) data )); , a ne vidim smisao da mu stavim (unsigned int*) (&data), jer on upravo to i inace radi, sam castuje pokazivac prema onome sto mu pise u format stringu, bez obzira na tip odredisne varijable.
[ Milan Aksic @ 16.06.2004. 13:12 ] @
Interesantan "bagic", mada bi se isti mnogo brze nasao da si obratio paznju na:
Code:
[red]unsigned long int[/red] address;
[red]unsigned char[/red] data;
i na man stranicu "sscanf-a" :) Izvod iz iste:
Code:
i Matches an optionally signed integer; the next pointer must be a pointer to int. The integer is
read in base 16 if it begins with `0x' or `0X', in base 8 if it begins with `0', and in base 10
otherwise. Only characters that correspond to the base are used.
Resenje je jednostavno, kako "sscanf" koriscenjem konverzije "%i" upisuje "integer", promenljive "address" i "data" treba deklarisati kao isti. Dakle:
Code:
int address;
int data;
Sta se u stvari desava? Kod mene (kod tebe se moze razlikovati, usled poravnanja (alignment)) adrese promenljivih "address" i "data" su: 0xbffff95c i 0xbffff95b. Sto znaci da su na steku jedan pored drugog. Stek bi (za ilustrativnu svrhu) mogao npr. da izgleda ovako:
Code:
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
\________________________ address _________________________/\___ data __/
dakle u liniji:
Code: result2 = sscanf(parms[0], "%i", &address);
promenljivoj "address" se pravilno dodeli vrednost, medjutim u sledecoj liniji:
Code: result3 = sscanf(parms[1], "%i", &data);
dolazi do prelivanja bufera (buffer overflow), tj. pise se iza granica promenljive "data", odnosno preko vrednosti u promenljivoj "address" jer opet, "%i" konverzija upisuje "signed integer" a ne 1 bajt.
Npr. situacija za par vrednosti 0x31 i 0x32 na pocetku "config" fajla.
0x31 je u binarnom cetvorobajtnom zapisu:
Code: 0000 0000 0000 0000 0000 0000 0011 0001
a 0x32 u istom zapisu:
Code: 0000 0000 0000 0000 0000 0000 0011 0010
Nakon linije:
Code: result2 = sscanf(parms[0], "%i", &address);
stek izgleda ovako:
Code: /- nedefinisano -\
|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|1|1|0|0|0|1| | | | | | | | |
\________________________ address _________________________/\___ data __/
a nakon linije:
Code: result3 = sscanf(parms[1], "%i", &data);
gde dolazi do prelivanja bufera u vrednost preomenljive "address", stek izgleda ovako:
Code: <- prelivanje
|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|1|1|0|0|1|0|
\________________________ address _________________________/\___ data __/
i nestade vrednost promenljive "address" :)
[ Milan Aksic @ 16.06.2004. 13:15 ] @
Eh, tek sada nakon slanja poruke sam video da je problem resen :)
[ blaza @ 17.06.2004. 16:43 ] @
Citat: salec:Inace, kako je trebalo da u ovom primeru upotrebim type casting (tj. na kom mestu)?
Morao si ipak da upotrebis int varijablu posto je funkcija sscanf "glupa" - nju interesuje samo adresa prvog bajta od 4 u koje ce smestiti vrednost. Nemozemo je obuzdati primenom type casting-a.
Ako si hteo da rezultat smestis u unsigned char varijablu, jedini razuman nacin koji vidim je primena temp int varijable:
Code:
int temp;
result3 = sscanf(parms[1], "%i", &temp);
data = (unsigned char) temp; // data = static_cast<unsigned char>(temp);
Copyright (C) 2001-2025 by www.elitesecurity.org. All rights reserved.
|