Skip to content

Commit c71bb79

Browse files
authored
Merge pull request letscontrolit#2421 from TD-er/feature/compiletime_check
[Build] Run compile time checks on struct sizes
2 parents 587b8cb + 417af27 commit c71bb79

File tree

3 files changed

+82
-33
lines changed

3 files changed

+82
-33
lines changed

src/ESPEasy-Globals.h

Lines changed: 21 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,23 @@
66
#define STR(x) STR_HELPER(x)
77
#endif
88

9+
#include <cstddef>
10+
11+
// ********************************************************************************
12+
// Check struct sizes at compile time
13+
// Usage:
14+
// struct foo
15+
// {
16+
// char bla[16];
17+
// };
18+
//
19+
// check_size<foo, 8>();
20+
// ********************************************************************************
21+
template <typename ToCheck, std::size_t ExpectedSize, std::size_t RealSize = sizeof(ToCheck)>
22+
void check_size() {
23+
static_assert(ExpectedSize == RealSize, "Size is off!");
24+
}
25+
926
// ********************************************************************************
1027
// User specific configuration
1128
// ********************************************************************************
@@ -702,6 +719,8 @@ struct SecurityStruct
702719
} SecuritySettings;
703720

704721

722+
723+
705724
/*********************************************************************************************\
706725
* Custom Variables for usage in rules and http.
707726
* Syntax: %vX%
@@ -992,37 +1011,6 @@ SettingsStruct* SettingsStruct_ptr = new SettingsStruct;
9921011
SettingsStruct& Settings = *SettingsStruct_ptr;
9931012
*/
9941013

995-
String ReportOffsetErrorInStruct(const String& structname, size_t offset) {
996-
String error;
997-
error.reserve(48 + structname.length());
998-
error = F("Error: Incorrect offset in struct: ");
999-
error += structname;
1000-
error += '(';
1001-
error += String(offset);
1002-
error += ')';
1003-
return error;
1004-
}
1005-
1006-
/*********************************************************************************************\
1007-
* Analyze SettingsStruct and report inconsistencies
1008-
* Not a member function to be able to use the F-macro
1009-
\*********************************************************************************************/
1010-
bool SettingsCheck(String& error) {
1011-
error = "";
1012-
#ifdef esp8266
1013-
size_t offset = offsetof(SettingsStruct, ResetFactoryDefaultPreference);
1014-
if (offset != 1224) {
1015-
error = ReportOffsetErrorInStruct(F("SettingsStruct"), offset);
1016-
}
1017-
#endif
1018-
if (!Settings.networkSettingsEmpty()) {
1019-
if (Settings.IP[0] == 0 || Settings.Gateway[0] == 0 || Settings.Subnet[0] == 0 || Settings.DNS[0] == 0) {
1020-
error += F("Error: Either fill all IP settings fields or leave all empty");
1021-
}
1022-
}
1023-
1024-
return error.length() == 0;
1025-
}
10261014

10271015
/*********************************************************************************************\
10281016
* ControllerSettingsStruct definition
@@ -1455,12 +1443,12 @@ struct LogStruct {
14551443
}
14561444
}
14571445

1446+
String Message[LOG_STRUCT_MESSAGE_LINES];
1447+
unsigned long timeStamp[LOG_STRUCT_MESSAGE_LINES];
14581448
int write_idx;
14591449
int read_idx;
1460-
unsigned long timeStamp[LOG_STRUCT_MESSAGE_LINES];
14611450
unsigned long lastReadTimeStamp;
14621451
byte log_level[LOG_STRUCT_MESSAGE_LINES];
1463-
String Message[LOG_STRUCT_MESSAGE_LINES];
14641452

14651453
} Logging;
14661454

src/ESPEasy.ino

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ void setup()
129129
WiFi.persistent(false); // Do not use SDK storage of SSID/WPA parameters
130130
WiFi.setAutoReconnect(false);
131131
WiFi.mode(WIFI_OFF);
132+
run_compiletime_checks();
132133
lowestFreeStack = getFreeStackWatermark();
133134
lowestRAM = FreeMem();
134135

src/ESPEasy_checks.ino

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
void run_compiletime_checks() {
2+
check_size<CRCStruct, 168u>();
3+
check_size<SecurityStruct, 593u>();
4+
const unsigned int SettingsStructSize = (244 + 82* TASKS_MAX);
5+
check_size<SettingsStruct, SettingsStructSize>();
6+
check_size<ControllerSettingsStruct, 748u>();
7+
check_size<NotificationSettingsStruct, 996u>();
8+
check_size<ExtraTaskSettingsStruct, 472u>();
9+
check_size<EventStruct, 96u>(); // Is not stored
10+
11+
// LogStruct is mainly dependent on the number of lines.
12+
// Has to be round up to multiple of 4.
13+
const unsigned int LogStructSize = ((12u + 17* LOG_STRUCT_MESSAGE_LINES) + 3) & ~3;
14+
check_size<LogStruct, LogStructSize >(); // Is not stored
15+
check_size<DeviceStruct, 7u>();
16+
check_size<ProtocolStruct, 10u>();
17+
check_size<NotificationStruct, 3u>();
18+
check_size<NodeStruct, 24u>();
19+
check_size<systemTimerStruct, 28u>();
20+
check_size<RTCStruct, 16u>();
21+
check_size<rulesTimerStatus, 12u>();
22+
check_size<portStatusStruct, 4u>();
23+
check_size<ResetFactoryDefaultPreference_struct, 4u>();
24+
check_size<GpioFactorySettingsStruct, 11u>();
25+
26+
}
27+
28+
29+
30+
String ReportOffsetErrorInStruct(const String& structname, size_t offset) {
31+
String error;
32+
error.reserve(48 + structname.length());
33+
error = F("Error: Incorrect offset in struct: ");
34+
error += structname;
35+
error += '(';
36+
error += String(offset);
37+
error += ')';
38+
return error;
39+
}
40+
41+
/*********************************************************************************************\
42+
* Analyze SettingsStruct and report inconsistencies
43+
* Not a member function to be able to use the F-macro
44+
\*********************************************************************************************/
45+
bool SettingsCheck(String& error) {
46+
error = "";
47+
#ifdef esp8266
48+
size_t offset = offsetof(SettingsStruct, ResetFactoryDefaultPreference);
49+
if (offset != 1224) {
50+
error = ReportOffsetErrorInStruct(F("SettingsStruct"), offset);
51+
}
52+
#endif
53+
if (!Settings.networkSettingsEmpty()) {
54+
if (Settings.IP[0] == 0 || Settings.Gateway[0] == 0 || Settings.Subnet[0] == 0 || Settings.DNS[0] == 0) {
55+
error += F("Error: Either fill all IP settings fields or leave all empty");
56+
}
57+
}
58+
59+
return error.length() == 0;
60+
}

0 commit comments

Comments
 (0)