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

Appearance settings

Commit 77f7375

Browse filesBrowse files
committed
rewrite(IPAddress): fix implementation
fix implementation and add discussion questions (safe using of IPAddress).
1 parent d85523f commit 77f7375
Copy full SHA for 77f7375

File tree

2 files changed

+44
-6
lines changed
Filter options

2 files changed

+44
-6
lines changed

‎api/IPAddress.cpp

Copy file name to clipboardExpand all lines: api/IPAddress.cpp
+29-4Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,34 @@ IPAddress::IPAddress(uint8_t o1, uint8_t o2, uint8_t o3, uint8_t o4, uint8_t o5,
3939
// IPv4 only
4040
IPAddress::IPAddress(uint32_t address)
4141
{
42-
uint32_t& addressRef = reinterpret_cast<uint32_t&>(_address[IPADDRESS_V4_BYTES_INDEX]);
43-
addressRef = address;
42+
memcpy(&_address[IPADDRESS_V4_BYTES_INDEX], &address, 4); // This method guarantees a defined behavior. Any pointer conversions to write to ADDRESS storage (as a multibyte integer) are undefined behavior when the lifetime of the multibyte type has not previously started.
43+
44+
// C++ standard draft [basic.life#7](https://eel.is/c++draft/basic.life#7)
45+
// Before the lifetime of an object has started but after the storage which the object
46+
// will occupy has been allocated or, after the lifetime of an object has ended and
47+
// before the storage which the object occupied is reused or released, any pointer that
48+
// represents the address of the storage location where the object will be or was
49+
// located may be used but only in limited ways. For an object under construction or
50+
// destruction, see [class.cdtor]. Otherwise, such a pointer refers to allocated storage
51+
// ([basic.stc.dynamic.allocation]), and using the pointer as if the pointer were of
52+
// type void* is well-defined. Indirection through such a pointer is permitted but the
53+
// resulting lvalue may only be used in limited ways, as described below.
54+
// The program has undefined behavior if
55+
// --the pointer is used as the operand of a delete-expression,
56+
// --the pointer is used as the operand of a static_cast ([expr.static.cast]), except
57+
// when the conversion is to pointer to cv void, or to pointer to cv void and subsequently
58+
// to pointer to cv char, cv unsigned char, or cv std::byte ([cstddef.syn]), or
59+
60+
// C++ standard draft [basic.life#8](https://eel.is/c++draft/basic.life#8)
61+
// Similarly, before the lifetime of an object has started but after the storage which
62+
// the object will occupy has been allocated or, after the lifetime of an object has
63+
// ended and before the storage which the object occupied is reused or released, any
64+
// glvalue that refers to the original object may be used but only in limited ways.
65+
// For an object under construction or destruction, see [class.cdtor]. Otherwise, such
66+
// a glvalue refers to allocated storage ([basic.stc.dynamic.allocation]), and using
67+
// the properties of the glvalue that do not depend on its value is well-defined.
68+
// The program has undefined behavior if
69+
// -- the glvalue is used to access the object, or
4470

4571
// NOTE on conversion/comparison and uint32_t:
4672
// These conversions are host platform dependent.
@@ -244,8 +270,7 @@ IPAddress& IPAddress::operator=(uint32_t address)
244270
// See note on conversion/comparison and uint32_t
245271
_type = IPv4;
246272
memset(_address, 0, sizeof(_address));
247-
uint32_t& addressRef = reinterpret_cast<uint32_t&>(_address[IPADDRESS_V4_BYTES_INDEX]);
248-
addressRef = address;
273+
memcpy(&_address[IPADDRESS_V4_BYTES_INDEX], &address, 4);
249274
return *this;
250275
}
251276

‎api/IPAddress.h

Copy file name to clipboardExpand all lines: api/IPAddress.h
+15-2Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
#pragma once
2121

22+
#include <string.h>
2223
#include <stdint.h>
2324
#include "Printable.h"
2425
#include "String.h"
@@ -41,7 +42,10 @@ enum IPType {
4142

4243
class IPAddress : public Printable {
4344
private:
44-
alignas(alignof(uint32_t)) uint8_t _address[16]{};
45+
alignas(alignof(uint32_t)) uint8_t _address[16]{}; // If the implementation does not require
46+
// storage as a multibyte integer, you can
47+
// remove the storage field alignment.
48+
// Address (as uint32) is accessed by copying.
4549
IPType _type{IPv4};
4650

4751
// Access the raw byte array containing the address. Because this returns a pointer
@@ -59,6 +63,7 @@ class IPAddress : public Printable {
5963
IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet);
6064
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);
6165
// IPv4; see implementation note
66+
// NOTE: address MUST BE BigEndian.
6267
IPAddress(uint32_t address);
6368
// Default IPv4
6469
IPAddress(const uint8_t *address);
@@ -71,7 +76,15 @@ class IPAddress : public Printable {
7176

7277
// Overloaded cast operator to allow IPAddress objects to be used where a uint32_t is expected
7378
// NOTE: IPv4 only; see implementation note
74-
operator uint32_t() const { return _type == IPv4 ? *reinterpret_cast<const uint32_t*>(&_address[IPADDRESS_V4_BYTES_INDEX]) : 0; };
79+
// NOTE: Data of the returned integer in the native endiannes, but relevant ordering is a BigEndian.
80+
// The user is responsible for ensuring that the value is converted to BigEndian.
81+
operator uint32_t() const {
82+
uint32_t ret;
83+
memcpy(&ret, &_address[IPADDRESS_V4_BYTES_INDEX], 4);
84+
// NOTE: maybe use the placement-new for starting of the integer type lifetime in the storage when constructing an IPAddress?
85+
// FIXME: need endiannes checking? how do this with the arduino-api?
86+
return _type == IPv4 ? ret : 0;
87+
};
7588

7689
bool operator==(const IPAddress& addr) const;
7790
bool operator!=(const IPAddress& addr) const { return !(*this == addr); };

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.