[C++] MAC adress in SQL query

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Ter info: In ben een web developer (PHP/Python) en zit op dit moment op een project waar ik ontwikkel voor ARM based hardware in C++. Van het succes van dit project hangt mijn toekomstige baan af. Ik heb geen basis kennis van C++.

Ik heb een string hw_address. Deze kan ik afdrukken als volgt:

code:
1
printf("%02X%02X%02X%02X%02X", hw_address[0], hw_address[1],hw_address[2],hw_address[3],hw_address[4],hw_address[5]);


Nu wil ik een SQL string maken waarin bovenstaande wordt opgenomen:

code:
1
2
string sql;
sql = "SELECT unit_id FROM tbl_lockers WHERE unit_serial='hw_address[0]hw_address[1]hw_address[2]hw_address[3]hw_address[4]hw_address[5]'"

Werkt dit zo of moet ik hw_adress eerst manipuleren/converteren etc..?

Ik ben een absolute beginner in C++, ik zou deze vraag niet posten als mijn baan er niet van af hing (ben alleenstaande vader en kan me niet veroorloven weer in de ww terecht te komen..).

Acties:
  • 0 Henk 'm!

  • RobIII
  • Registratie: December 2001
  • Niet online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

(overleden)
Je kunt toch gewoon sprintf gebruiken om hw_address in de string te mikken? Iets a-la:

C++:
1
sprintf(sql, "select foo, bar from mytable where foobar = '%02x%02x....'", hw_addr[0], hw_addr[1], ....);


Met de kanttekening dat C++ al effe geleden is voor me :Y)

[ Voor 66% gewijzigd door RobIII op 30-03-2011 11:29 ]

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Je eigen tweaker.me redirect

Over mij


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
RobIII schreef op woensdag 30 maart 2011 @ 11:23:
Je kunt toch gewoon sprintf gebruiken om hw_address in de string te mikken? Iets a-la:

C++:
1
sprintf(sql, "select foo, bar from mytable where foobar = '%02x%02x....'", hw_addr[0], hw....);
Zoals ik al schreef, ik ben een absolute c++ noob ;)
Maar dit werkt inderdaad, hartelijk dank, ik kan een eind verder nu.

Acties:
  • 0 Henk 'm!

  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 10-09 14:31
Nee, dat werkt niet goed. sprintf schrijft naar een char[] (en is daarom gevoelig voor bufferoverflows), niet naar een string.

De gebruikelijke methode om naar een string te schrijven is via een std::stringstream. Gezien de fromatting is het hier waarschijnlijk handiger om snprintf te gebruiken, en het type van sql aan te passen.

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


Acties:
  • 0 Henk 'm!

  • RobIII
  • Registratie: December 2001
  • Niet online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

(overleden)
MSalters schreef op woensdag 30 maart 2011 @ 16:05:
(en is daarom gevoelig voor bufferoverflows)
That thought crossed my mind too, maar een mac-adres heeft AFAIK altijd een vaste lengte itt bijv. een IP en daarom leek 't me wel "safe enough" :P Het char[] <> string verhaal heb je gelijk in.

[ Voor 17% gewijzigd door RobIII op 30-03-2011 16:38 ]

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Je eigen tweaker.me redirect

Over mij


Acties:
  • 0 Henk 'm!

  • 0fbe
  • Registratie: Januari 2004
  • Laatst online: 15:39
MSalters schreef op woensdag 30 maart 2011 @ 16:05:
Nee, dat werkt niet goed. sprintf schrijft naar een char[] (en is daarom gevoelig voor bufferoverflows), niet naar een string.

De gebruikelijke methode om naar een string te schrijven is via een std::stringstream. Gezien de fromatting is het hier waarschijnlijk handiger om snprintf te gebruiken, en het type van sql aan te passen.
Ik zou niet weten waarom sprintf in dit geval gevoelig is voor een buffer overflow, je format een vast aantal chars van vaste lengte naar een char[]. sprintf met precision is zelfs per definitie buffer overflow safe.

[ Voor 5% gewijzigd door 0fbe op 30-03-2011 18:54 ]


Acties:
  • 0 Henk 'm!

  • farlane
  • Registratie: Maart 2000
  • Laatst online: 11-09 12:01
simplendi schreef op woensdag 30 maart 2011 @ 18:49:
sprintf met precision is zelfs per definitie buffer overflow safe.
Behalve dan dat de precision het minimum aantal geprinte posities is en dus niet buffer overflow safe is.

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


Acties:
  • 0 Henk 'm!

  • 0fbe
  • Registratie: Januari 2004
  • Laatst online: 15:39
farlane schreef op woensdag 30 maart 2011 @ 20:06:
[...]

Behalve dan dat de precision het minimum aantal geprinte posities is en dus niet buffer overflow safe is.
Nee hoor, het is alleen het minimum voor integer specifiers (die per definitie al een maximale lengte hebben). Voor strings is het het maximum.

Acties:
  • 0 Henk 'm!

  • farlane
  • Registratie: Maart 2000
  • Laatst online: 11-09 12:01
simplendi schreef op woensdag 30 maart 2011 @ 20:39:
Nee hoor, het is alleen het minimum voor integer specifiers (die per definitie al een maximale lengte hebben). Voor strings is het het maximum.
Het werkt dus alleen voor %s ( dat hier overigens niet gebruikt wordt ) en niet altijd correct terminate en werkt nooit voor %f/%lf.

Lijkt me snprinf toch iets handiger.

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


Acties:
  • 0 Henk 'm!

  • Soultaker
  • Registratie: September 2000
  • Laatst online: 14:15
RobIII schreef op woensdag 30 maart 2011 @ 11:23:
Je kunt toch gewoon sprintf gebruiken om hw_address in de string te mikken? Iets a-la:

C++:
1
sprintf(sql, "select foo, bar from mytable where foobar = '%02x%02x....'", hw_addr[0], hw_addr[1], ....);
Prima suggestie, maar er is één gotcha: characters kunnen signed zijn, in welk geval sommige bytes verkeerd geprint worden. Zo is het wel veilig:
C:
1
sprintf(sql, "...%02x%02x...", hw_addr[0]&255, hw_addr[1]&255, ...);

Acties:
  • 0 Henk 'm!

  • 0fbe
  • Registratie: Januari 2004
  • Laatst online: 15:39
farlane schreef op woensdag 30 maart 2011 @ 21:45:
[...]

Het werkt dus alleen voor %s ( dat hier overigens niet gebruikt wordt ) en niet altijd correct terminate en werkt nooit voor %f/%lf.

Lijkt me snprinf toch iets handiger.
Nee hoor.

%x en %X hebben voor char's en int's gewoon een maximale lengte (char: 2, int: 8 (32-bits systeem))
Hetzelfde geldt ook voor float's alleen daar is die maximale lengte significant langer...
Soultaker schreef op woensdag 30 maart 2011 @ 22:09:
[...]

Prima suggestie, maar er is één gotcha: characters kunnen signed zijn, in welk geval sommige bytes verkeerd geprint worden. Zo is het wel veilig:
C:
1
sprintf(sql, "...%02x%02x...", hw_addr[0]&255, hw_addr[1]&255, ...);
Characters kunnen inderdaad signed zijn, maar wat verandert dat aan de hexadecimale representatie?

[ Voor 32% gewijzigd door 0fbe op 30-03-2011 22:39 ]


Acties:
  • 0 Henk 'm!

  • Soultaker
  • Registratie: September 2000
  • Laatst online: 14:15
simplendi schreef op woensdag 30 maart 2011 @ 22:13:
Characters kunnen inderdaad signed zijn, maar wat verandert dat aan de hexadecimale representatie?
(int)-1 == (int)0xffffffff (op een machine met 32-bit two's complement ints; i.e. 99% van de computers in de wereld :P) wordt geprint als "ffffffff" in plaats van "ff". Denk er aan dat je ints passt aan printf, geen characters, en de 2 in "%02x" is zoals gezegd alleen de minimumgrootte.

[ Voor 14% gewijzigd door Soultaker op 30-03-2011 23:22 ]


Acties:
  • 0 Henk 'm!

  • RobIII
  • Registratie: December 2001
  • Niet online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

(overleden)
Soultaker schreef op woensdag 30 maart 2011 @ 23:16:
Denk er aan dat je ints passt aan printf, geen characters
Even voor mijn duidelijkheid dan :P Ik neem aan dat hw_address[0] een byte/char is? Of mis ik iets? Dan pass je toch geen ints? De X specifier verwacht dan wel een int, maar ik pass er toch niet meer in dan een "halve int" om 't zo maar effe te zeggen (dus: de eerste 8 bits zijn 0)?

Mén, ik zit al veel te lang in de managed taaltjes en scripting meuk :P

Edit: ah, heb al een logische verklaring gevonden. En :F me

[ Voor 48% gewijzigd door RobIII op 30-03-2011 23:53 ]

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Je eigen tweaker.me redirect

Over mij


Acties:
  • 0 Henk 'm!

  • Soultaker
  • Registratie: September 2000
  • Laatst online: 14:15
Variable argumenten kleiner dan int worden altijd gepromoveerd naar int; daarmee is een int aan de kant van de caller niet meer te onderscheiden van een short of char. Verder kun je binnen de functie het type van het argument überhaupt niet achterhalen, vandaar dat je in de format string bijvoorbeeld "%lx" moet opgeven als je een long int wil printen.

edit:
Urg, op StackOverflow is dit het accepted answer:
You're probably getting a benign form of undefined behaviour because the %x modifier expects an unsigned int parameter and a char will usually be promoted to an int when passed to a varargs function.
Dat is geen undefined behaviour want int en unsigned int hebben gegarandeerd dezelfde grootte, alignment en representatie in het geheugen.

Dus dit is overbodig:
C:
1
printf(" 0x%x ", (unsigned)pixel_data[0] & 0xffU );

Casten naar unsigned voegt niets toe, want zoals gezegd ziet printf() het verschil toch niet (en %x print z'n resultaat altijd unsigned).

[ Voor 62% gewijzigd door Soultaker op 31-03-2011 00:30 ]


Acties:
  • 0 Henk 'm!

  • farlane
  • Registratie: Maart 2000
  • Laatst online: 11-09 12:01
simplendi schreef op woensdag 30 maart 2011 @ 22:13:
Nee hoor.
%x en %X hebben voor char's en int's gewoon een maximale lengte (char: 2, int: 8 (32-bits systeem))
Hetzelfde geldt ook voor float's alleen daar is die maximale lengte significant langer...
Het punt was dat het niet voor de hand liggend is hoe lang de uiteindelijke string gaat worden, ook al weet je dit van tevoren. Met een simpele %d gaat het wel maar niet als er specifiers door elkaar worden gebruikt en weet ik veel wat. Hebben we het nog helemaal niet gehad over de verschillen tussen de verschillende platformen.

Ik snap eerlijk niet gezegd ook niet welk punt je probeert te maken hiermee, de geschiedenis leert dat sprintf buffer overflows maar al te vaak voorkomen. Dat is niet omdat het met sprintf zo makkelijk is om ze te voorkomen,

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


Acties:
  • 0 Henk 'm!

  • Soultaker
  • Registratie: September 2000
  • Laatst online: 14:15
Toch ben ik 't met simplendi eens in dezen: je weet dat waarden tussen 0..255 met %02x als format precies twee karakters groot zijn, dus kun je precies inschatten hoe groot de buffer moet zijn. Als je er over nagedacht hebt is sprintf() in dit geval dus gewoon veilig.

Het kan niet echt kwaad om voor de zekerheid snprintf() te gebruiken, als je dat liever doet, maar feitelijk schiet je daar niets mee op. Als de buffer daadwerkelijk te klein is, introduceer je bovendien weer andere mogelijke fouten, omdat je SQL query dan doodleuk truncated is. Als je het écht goed wil doen moet je dus ook het resultaat van snprintf() checken en iets zinnigs doen als die te groot is.

En daar komt nog bij dat snprintf() géén standaardfunctie is in C++ (en dus misschien helemaal niet beschikbaar is) en sprintf() wél.

Acties:
  • 0 Henk 'm!

  • EddoH
  • Registratie: Maart 2009
  • Niet online

EddoH

Backpfeifengesicht

Ik mis het even geloof ik. Het resultaat van hw_addr[0]&255 levert toch een char op, waarna hetzelfde probleem optreedt?
Waarom moet er niet
C:
1
((unsigned int)hw_addr[0])&255
gedaan worden?

Acties:
  • 0 Henk 'm!

  • Soultaker
  • Registratie: September 2000
  • Laatst online: 14:15
Er zijn twee redenen waarom dat niet hoeft. Rekenkundige operaties werken meestal op twee argumenten van hetzelfde type, dus voor zo'n operatie uitgevoerd wordt, gebeuren er twee dingen:
  1. Elk argument dat kleiner is dan een int, wordt eerst naar een (unsigned) int geconverteerd.
  2. Voor binaire operaties die op gelijke typen argumenten werken (zoals + en & en de meeste anderen) worden de argumenten van een gelijk type gemaakt door kleinere typen naar grotere te promoveren (int naar long, bijvoorbeeld, of float naar double). De precieze regels zijn enigzins tricky.
Vanwege regel 1 wordt het karakter in de expressie dus al gepromoveerd naar int, maar zelfs als dat niet het geval zou zijn, dan zou dat door regel 2 alsnog gebeuren, omdat 255 een integer literal van type int is.

Acties:
  • 0 Henk 'm!

  • 0fbe
  • Registratie: Januari 2004
  • Laatst online: 15:39
Ik zat inderdaad fout wat betreft de type-casting naar int in de sprintf. Maar stel je doet dit:
C:
1
2
unsigned char test = 0xFF;
printf("%02x", test);

Dan kan het toch onmogelijk voorkomen dat test opeens signed is?

Acties:
  • 0 Henk 'm!

  • Soultaker
  • Registratie: September 2000
  • Laatst online: 14:15
test zal doorgaans wel een signed integer zijn, maar je bedoelt waarschijnlijk dat test niet negatief is, en dat klopt. Mijn kanttekening gaat alleen op voor signed (of ongekwalificeerde) characters.

[ Voor 4% gewijzigd door Soultaker op 31-03-2011 18:07 ]


Acties:
  • 0 Henk 'm!

  • EddoH
  • Registratie: Maart 2009
  • Niet online

EddoH

Backpfeifengesicht

Soultaker schreef op donderdag 31 maart 2011 @ 17:33:
Er zijn twee redenen waarom dat niet hoeft. Rekenkundige operaties werken meestal op twee argumenten van hetzelfde type, dus voor zo'n operatie uitgevoerd wordt, gebeuren er twee dingen:
  1. Elk argument dat kleiner is dan een int, wordt eerst naar een (unsigned) int geconverteerd.
  2. Voor binaire operaties die op gelijke typen argumenten werken (zoals + en & en de meeste anderen) worden de argumenten van een gelijk type gemaakt door kleinere typen naar grotere te promoveren (int naar long, bijvoorbeeld, of float naar double). De precieze regels zijn enigzins tricky.
Vanwege regel 1 wordt het karakter in de expressie dus al gepromoveerd naar int, maar zelfs als dat niet het geval zou zijn, dan zou dat door regel 2 alsnog gebeuren, omdat 255 een integer literal van type int is.
Ah, daar zit de crux. Ik zag over het hoofd dat de argumeneten naar int gepromote worden bij de &255 operatie. Ik ging ervan uit dat de conversie naar int pas erna zou plaatsvinden.

Acties:
  • 0 Henk 'm!

  • farlane
  • Registratie: Maart 2000
  • Laatst online: 11-09 12:01
Soultaker schreef op donderdag 31 maart 2011 @ 00:53:
Toch ben ik 't met simplendi eens in dezen: je weet dat waarden tussen 0..255 met %02x als format precies twee karakters groot zijn, dus kun je precies inschatten hoe groot de buffer moet zijn. Als je er over nagedacht hebt is sprintf() in dit geval dus gewoon veilig.
In dit geval is het overzichtelijk genoeg, maar als je ( zoals ik dan ) jezelf hebt aangewend om snprintf te gebruiken waar mogelijk is het onzin om elke keer de afweging te gaan maken tussen de twee, terwijl de voordelen van snprintf duidelijk genoeg zijn.
Als de buffer daadwerkelijk te klein is, introduceer je bovendien weer andere mogelijke fouten, omdat je SQL query dan doodleuk truncated is. Als je het écht goed wil doen moet je dus ook het resultaat van snprintf() checken en iets zinnigs doen als die te groot is.
Op zijn minst mag je dus kiezen tussen:
A - Een bufferoverflow en de query werkt niet ;w
B - De query werkt niet -O-
En daar komt nog bij dat snprintf() géén standaardfunctie is in C++ (en dus misschien helemaal niet beschikbaar is) en sprintf() wél.
In C++-2011 wel toch?

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


Acties:
  • 0 Henk 'm!

  • Soultaker
  • Registratie: September 2000
  • Laatst online: 14:15
Ik geloof het wel ja; het is een C99 standaardfunctie en C++0x zou de meeste daarvan ook importeren om de compatibiliteit tussen C en C++ verder te vergroten. Maar onder andere MSVC++ ondersteunt geen C99 (12 jaar na dato :X) en heeft die functie ook niet, dus helemaal theoretisch is de discussie niet, en voor C++0x een beetje gangbaar is zijn we nog wel even verder.

[ Voor 17% gewijzigd door Soultaker op 31-03-2011 22:04 ]


Acties:
  • 0 Henk 'm!

  • johnkeates
  • Registratie: Februari 2008
  • Laatst online: 04-07 16:30
Gewoon geen MSVC++ gebruiken dus, dan zit je altijd goed :)

Acties:
  • 0 Henk 'm!

  • farlane
  • Registratie: Maart 2000
  • Laatst online: 11-09 12:01
Soultaker schreef op donderdag 31 maart 2011 @ 22:03:
Ik geloof het wel ja; het is een C99 standaardfunctie en C++0x zou de meeste daarvan ook importeren om de compatibiliteit tussen C en C++ verder te vergroten. Maar onder andere MSVC++ ondersteunt geen C99 (12 jaar na dato :X) en heeft die functie ook niet, dus helemaal theoretisch is de discussie niet, en voor C++0x een beetje gangbaar is zijn we nog wel even verder.
MSVC++ heeft _snprintf oid ( volgens mij al sinds 2003 of 2005 ). Tja ... :|

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


Acties:
  • 0 Henk 'm!

  • Soultaker
  • Registratie: September 2000
  • Laatst online: 14:15
Maar ondanks de naam verschillen de semantics wanneer de buffer te klein is: _snprintf() zero-terminate de buffer niet dus als je de string vervolgens aan een andere functie doorgeeft is de kans dat er buiten de buffer gelezen wordt vrij groot, en de return value is -1 in dit geval (waarbij de standaardfunctie het totale aantal karakters returnt, wat nuttig is om een grotere buffer te alloceren; toegegeven: dat is belangrijker bij vsnprintf dan snprintf).

[ Voor 6% gewijzigd door Soultaker op 01-04-2011 15:33 ]

Pagina: 1