Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit52b367a

Browse files
committed
Rewrite IPAddress without union
Using a union allowed undefined behavior for 8-bit integer INPUT and OUTPUT arguments through a 32-bit integer (and vice versa).Write throught union::uint8_t[16] and read thoutght union::uint32_t[4]is a undefined behavior.C++ standard says (https://timsong-cpp.github.io/cppwp/n4659/class.union#1):"At most one of the non-static data members of an object of union typecan be active at any time, that is, the value of at most one of thenon-static data members can be stored in a union at any time. [ Note:One special guarantee is made in order to simplify the use of unions:If a standard-layout union contains several standard-layout structsthat share a common initial sequence, and if a non-static data memberof an object of this standard-layout union type is active and is oneof the standard-layout structs, it is permitted to inspect the commoninitial sequence of any of the standard-layout struct members; see[class.mem].  — end note ]"and (https://timsong-cpp.github.io/cppwp/n4659/class.mem#22):"Two standard-layout unions are layout-compatible if they have the same number of non-static data members and corresponding non-static data members (in any order) have layout-compatible types."you can't hope that compilers don't seem to do undefined behavior at the momentAlso createdespressif/arduino-esp32#8829 PR dependent on changing the current API.
1 parentfc9a636 commit52b367a

File tree

2 files changed

+56
-82
lines changed

2 files changed

+56
-82
lines changed

‎api/IPAddress.cpp‎

Lines changed: 50 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -19,53 +19,30 @@
1919

2020
#include"IPAddress.h"
2121
#include"Print.h"
22+
#include<algorithm>
23+
#include<cstdint>
2224

2325
usingnamespacearduino;
2426

25-
IPAddress::IPAddress(): IPAddress(IPv4) {}
27+
IPAddress::IPAddress()= default;
2628

27-
IPAddress::IPAddress(IPType ip_type)
28-
{
29-
_type = ip_type;
30-
memset(_address.bytes,0,sizeof(_address.bytes));
31-
}
29+
IPAddress::IPAddress(IPType ip_type) : _type(ip_type) {}
3230

3331
IPAddress::IPAddress(uint8_t first_octet,uint8_t second_octet,uint8_t third_octet,uint8_t fourth_octet)
3432
{
35-
_type = IPv4;
36-
memset(_address.bytes,0,sizeof(_address.bytes));
37-
_address.bytes[IPADDRESS_V4_BYTES_INDEX] = first_octet;
38-
_address.bytes[IPADDRESS_V4_BYTES_INDEX +1] = second_octet;
39-
_address.bytes[IPADDRESS_V4_BYTES_INDEX +2] = third_octet;
40-
_address.bytes[IPADDRESS_V4_BYTES_INDEX +3] = fourth_octet;
33+
_address[IPADDRESS_V4_BYTES_INDEX] = first_octet;
34+
_address[IPADDRESS_V4_BYTES_INDEX +1] = second_octet;
35+
_address[IPADDRESS_V4_BYTES_INDEX +2] = third_octet;
36+
_address[IPADDRESS_V4_BYTES_INDEX +3] = fourth_octet;
4137
}
4238

43-
IPAddress::IPAddress(uint8_t o1,uint8_t o2,uint8_t o3,uint8_t o4,uint8_t o5,uint8_t o6,uint8_t o7,uint8_t o8,uint8_t o9,uint8_t o10,uint8_t o11,uint8_t o12,uint8_t o13,uint8_t o14,uint8_t o15,uint8_t o16) {
44-
_type = IPv6;
45-
_address.bytes[0] = o1;
46-
_address.bytes[1] = o2;
47-
_address.bytes[2] = o3;
48-
_address.bytes[3] = o4;
49-
_address.bytes[4] = o5;
50-
_address.bytes[5] = o6;
51-
_address.bytes[6] = o7;
52-
_address.bytes[7] = o8;
53-
_address.bytes[8] = o9;
54-
_address.bytes[9] = o10;
55-
_address.bytes[10] = o11;
56-
_address.bytes[11] = o12;
57-
_address.bytes[12] = o13;
58-
_address.bytes[13] = o14;
59-
_address.bytes[14] = o15;
60-
_address.bytes[15] = o16;
61-
}
39+
IPAddress::IPAddress(uint8_t o1,uint8_t o2,uint8_t o3,uint8_t o4,uint8_t o5,uint8_t o6,uint8_t o7,uint8_t o8,uint8_t o9,uint8_t o10,uint8_t o11,uint8_t o12,uint8_t o13,uint8_t o14,uint8_t o15,uint8_t o16) : _address{o1, o2, o3, o4, o5, o6, o7, o8, o9, o10, o11, o12, o13, o14, o15, o16}, _type(IPv6) {}
6240

63-
IPAddress::IPAddress(uint32_t address)
41+
// IPv4 only
42+
IPAddress::IPAddress(uint32_t address)
6443
{
65-
// IPv4 only
66-
_type = IPv4;
67-
memset(_address.bytes,0,sizeof(_address.bytes));
68-
_address.dword[IPADDRESS_V4_DWORD_INDEX] = address;
44+
uint32_t& addressRef =reinterpret_cast<uint32_t&>(_address[IPADDRESS_V4_BYTES_INDEX]);
45+
addressRef = address;
6946

7047
// NOTE on conversion/comparison and uint32_t:
7148
// These conversions are host platform dependent.
@@ -78,14 +55,12 @@ IPAddress::IPAddress(uint32_t address)
7855

7956
IPAddress::IPAddress(constuint8_t *address) : IPAddress(IPv4, address) {}
8057

81-
IPAddress::IPAddress(IPType ip_type,constuint8_t *address)
58+
IPAddress::IPAddress(IPType ip_type,constuint8_t *address) : _type(ip_type)
8259
{
83-
_type = ip_type;
8460
if (ip_type == IPv4) {
85-
memset(_address.bytes,0,sizeof(_address.bytes));
86-
memcpy(&_address.bytes[IPADDRESS_V4_BYTES_INDEX], address,sizeof(uint32_t));
61+
std::copy(address, address +4, &_address[IPADDRESS_V4_BYTES_INDEX]);
8762
}else {
88-
memcpy(_address.bytes, address,sizeof(_address.bytes));
63+
std::copy(address, address + _address.size(),_address.begin());
8964
}
9065
}
9166

@@ -97,18 +72,18 @@ IPAddress::IPAddress(const char *address)
9772
StringIPAddress::toString4()const
9873
{
9974
char szRet[16];
100-
snprintf(szRet,sizeof(szRet),"%u.%u.%u.%u", _address.bytes[IPADDRESS_V4_BYTES_INDEX], _address.bytes[IPADDRESS_V4_BYTES_INDEX +1], _address.bytes[IPADDRESS_V4_BYTES_INDEX +2], _address.bytes[IPADDRESS_V4_BYTES_INDEX +3]);
75+
snprintf(szRet,sizeof(szRet),"%u.%u.%u.%u", _address[IPADDRESS_V4_BYTES_INDEX], _address[IPADDRESS_V4_BYTES_INDEX +1], _address[IPADDRESS_V4_BYTES_INDEX +2], _address[IPADDRESS_V4_BYTES_INDEX +3]);
10176
returnString(szRet);
10277
}
10378

10479
StringIPAddress::toString6()const
10580
{
10681
char szRet[40];
10782
snprintf(szRet,sizeof(szRet),"%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x",
108-
_address.bytes[0], _address.bytes[1], _address.bytes[2], _address.bytes[3],
109-
_address.bytes[4], _address.bytes[5], _address.bytes[6], _address.bytes[7],
110-
_address.bytes[8], _address.bytes[9], _address.bytes[10], _address.bytes[11],
111-
_address.bytes[12], _address.bytes[13], _address.bytes[14], _address.bytes[15]);
83+
_address[0], _address[1], _address[2], _address[3],
84+
_address[4], _address[5], _address[6], _address[7],
85+
_address[8], _address[9], _address[10], _address[11],
86+
_address[12], _address[13], _address[14], _address[15]);
11287
returnString(szRet);
11388
}
11489

@@ -135,7 +110,7 @@ bool IPAddress::fromString4(const char *address)
135110
int16_t acc = -1;// Accumulator
136111
uint8_t dots =0;
137112

138-
memset(_address.bytes,0,sizeof(_address.bytes));
113+
_address.fill(0);
139114
while (*address)
140115
{
141116
char c = *address++;
@@ -157,7 +132,7 @@ bool IPAddress::fromString4(const char *address)
157132
/* No value between dots, e.g. '1..'*/
158133
returnfalse;
159134
}
160-
_address.bytes[IPADDRESS_V4_BYTES_INDEX + dots++] = acc;
135+
_address[IPADDRESS_V4_BYTES_INDEX + dots++] = acc;
161136
acc = -1;
162137
}
163138
else
@@ -175,7 +150,7 @@ bool IPAddress::fromString4(const char *address)
175150
/* No value between dots, e.g. '1..'*/
176151
returnfalse;
177152
}
178-
_address.bytes[IPADDRESS_V4_BYTES_INDEX +3] = acc;
153+
_address[IPADDRESS_V4_BYTES_INDEX +3] = acc;
179154
_type = IPv4;
180155
returntrue;
181156
}
@@ -215,8 +190,8 @@ bool IPAddress::fromString6(const char *address) {
215190
if (colons ==7)
216191
// too many separators
217192
returnfalse;
218-
_address.bytes[colons *2] = acc >>8;
219-
_address.bytes[colons *2 +1] = acc &0xff;
193+
_address[colons *2] = acc >>8;
194+
_address[colons *2 +1] = acc &0xff;
220195
colons++;
221196
acc =0;
222197
}
@@ -233,15 +208,15 @@ bool IPAddress::fromString6(const char *address) {
233208
// Too many segments (double colon must be at least one zero field)
234209
returnfalse;
235210
}
236-
_address.bytes[colons *2] = acc >>8;
237-
_address.bytes[colons *2 +1] = acc &0xff;
211+
_address[colons *2] = acc >>8;
212+
_address[colons *2 +1] = acc &0xff;
238213
colons++;
239214

240215
if (double_colons != -1) {
241216
for (int i = colons *2 - double_colons *2 -1; i >=0; i--)
242-
_address.bytes[16 - colons *2 + double_colons *2 + i] = _address.bytes[double_colons *2 + i];
217+
_address[16 - colons *2 + double_colons *2 + i] = _address[double_colons *2 + i];
243218
for (int i = double_colons *2; i <16 - colons *2 + double_colons *2; i++)
244-
_address.bytes[i] =0;
219+
_address[i] =0;
245220
}
246221

247222
_type = IPv6;
@@ -252,8 +227,10 @@ IPAddress& IPAddress::operator=(const uint8_t *address)
252227
{
253228
// IPv4 only conversion from byte pointer
254229
_type = IPv4;
255-
memset(_address.bytes,0,sizeof(_address.bytes));
256-
memcpy(&_address.bytes[IPADDRESS_V4_BYTES_INDEX], address,sizeof(uint32_t));
230+
231+
_address.fill(0);
232+
std::copy(address, address +4, &_address[IPADDRESS_V4_BYTES_INDEX]);
233+
257234
return *this;
258235
}
259236

@@ -268,35 +245,35 @@ IPAddress& IPAddress::operator=(uint32_t address)
268245
// IPv4 conversion
269246
// See note on conversion/comparison and uint32_t
270247
_type = IPv4;
271-
memset(_address.bytes,0,sizeof(_address.bytes));
272-
_address.dword[IPADDRESS_V4_DWORD_INDEX] = address;
248+
_address.fill(0);
249+
uint32_t& addressRef =reinterpret_cast<uint32_t&>(_address[IPADDRESS_V4_BYTES_INDEX]);
250+
addressRef = address;
273251
return *this;
274252
}
275253

276254
bool IPAddress::operator==(const IPAddress& addr)const {
277-
return (addr._type == _type)
278-
&& (memcmp(addr._address.bytes, _address.bytes,sizeof(_address.bytes)) ==0);
255+
return addr._type == _type &&std::equal(addr._address.begin(), addr._address.end(), _address.begin());
279256
}
280257

281258
bool IPAddress::operator==(constuint8_t* addr)const
282259
{
283260
// IPv4 only comparison to byte pointer
284261
// Can't support IPv6 as we know our type, but not the length of the pointer
285-
return _type == IPv4 &&memcmp(addr, &_address.bytes[IPADDRESS_V4_BYTES_INDEX],sizeof(uint32_t)) ==0;
262+
return _type == IPv4 &&std::equal(_address.begin(), _address.end(), addr);
286263
}
287264

288265
uint8_t IPAddress::operator[](int index)const {
289266
if (_type == IPv4) {
290-
return _address.bytes[IPADDRESS_V4_BYTES_INDEX + index];
267+
return _address[IPADDRESS_V4_BYTES_INDEX + index];
291268
}
292-
return _address.bytes[index];
269+
return _address[index];
293270
}
294271

295272
uint8_t& IPAddress::operator[](int index) {
296273
if (_type == IPv4) {
297-
return _address.bytes[IPADDRESS_V4_BYTES_INDEX + index];
274+
return _address[IPADDRESS_V4_BYTES_INDEX + index];
298275
}
299-
return _address.bytes[index];
276+
return _address[index];
300277
}
301278

302279
size_tIPAddress::printTo(Print& p)const
@@ -310,7 +287,7 @@ size_t IPAddress::printTo(Print& p) const
310287
int8_t current_start = -1;
311288
int8_t current_length =0;
312289
for (int8_t f =0; f <8; f++) {
313-
if (_address.bytes[f *2] ==0 && _address.bytes[f *2 +1] ==0) {
290+
if (_address[f *2] ==0 && _address[f *2 +1] ==0) {
314291
if (current_start == -1) {
315292
current_start = f;
316293
current_length =1;
@@ -327,10 +304,10 @@ size_t IPAddress::printTo(Print& p) const
327304
}
328305
for (int f =0; f <8; f++) {
329306
if (f < longest_start || f >= longest_start + longest_length) {
330-
uint8_t c1 = _address.bytes[f *2] >>4;
331-
uint8_t c2 = _address.bytes[f *2] &0xf;
332-
uint8_t c3 = _address.bytes[f *2 +1] >>4;
333-
uint8_t c4 = _address.bytes[f *2 +1] &0xf;
307+
uint8_t c1 = _address[f *2] >>4;
308+
uint8_t c2 = _address[f *2] &0xf;
309+
uint8_t c3 = _address[f *2 +1] >>4;
310+
uint8_t c4 = _address[f *2 +1] &0xf;
334311
if (c1 >0) {
335312
n += p.print((char)(c1 <10 ?'0' + c1 :'a' + c1 -10));
336313
}
@@ -357,10 +334,10 @@ size_t IPAddress::printTo(Print& p) const
357334
// IPv4
358335
for (int i =0; i <3; i++)
359336
{
360-
n += p.print(_address.bytes[IPADDRESS_V4_BYTES_INDEX + i], DEC);
337+
n += p.print(_address[IPADDRESS_V4_BYTES_INDEX + i], DEC);
361338
n += p.print('.');
362339
}
363-
n += p.print(_address.bytes[IPADDRESS_V4_BYTES_INDEX +3], DEC);
340+
n += p.print(_address[IPADDRESS_V4_BYTES_INDEX +3], DEC);
364341
return n;
365342
}
366343

‎api/IPAddress.h‎

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,12 @@
1919

2020
#pragma once
2121

22+
#include<array>
2223
#include<stdint.h>
2324
#include"Printable.h"
2425
#include"String.h"
2526

2627
#defineIPADDRESS_V4_BYTES_INDEX12
27-
#defineIPADDRESS_V4_DWORD_INDEX3
2828

2929
// forward declarations of global name space friend classes
3030
classEthernetClass;
@@ -42,17 +42,14 @@ enum IPType {
4242

4343
classIPAddress :publicPrintable {
4444
private:
45-
union {
46-
uint8_t bytes[16];
47-
uint32_t dword[4];
48-
} _address;
49-
IPType _type;
45+
alignas(alignof(uint32_t)) std::array<uint8_t,16> _address{};
46+
IPType _type{IPv4};
5047

5148
// Access the raw byte array containing the address. Because this returns a pointer
5249
// to the internal structure rather than a copy of the address this function should only
5350
// be used when you know that the usage of the returned uint8_t* will be transient and not
5451
// stored.
55-
uint8_t*raw_address() {return _type == IPv4 ? &_address.bytes[IPADDRESS_V4_BYTES_INDEX] : _address.bytes; }
52+
uint8_t*raw_address() {return _type == IPv4 ? &_address[IPADDRESS_V4_BYTES_INDEX] : _address.data(); }
5653

5754
public:
5855
// Constructors
@@ -75,7 +72,7 @@ class IPAddress : public Printable {
7572

7673
// Overloaded cast operator to allow IPAddress objects to be used where a uint32_t is expected
7774
// NOTE: IPv4 only; see implementation note
78-
operatoruint32_t()const {return _type == IPv4 ? _address.dword[IPADDRESS_V4_DWORD_INDEX] :0; };
75+
operatoruint32_t()const {return _type == IPv4 ?*reinterpret_cast<constuint32_t*>(&_address[IPADDRESS_V4_BYTES_INDEX]) :0; };
7976

8077
booloperator==(const IPAddress& addr)const;
8178
booloperator!=(const IPAddress& addr)const {return !(*this == addr); };
@@ -119,4 +116,4 @@ extern const IPAddress IN6ADDR_ANY;
119116
externconst IPAddress INADDR_NONE;
120117
}
121118

122-
using arduino::IPAddress;
119+
using arduino::IPAddress;

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp