-
Notifications
You must be signed in to change notification settings - Fork 2.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Aliasing] Prevent aliasing issues + remove C-style casts #3765
Conversation
TD-er
commented
Aug 14, 2021
•
edited
Loading
edited
- [Build] Add -fno-strict-aliasing as build flag make builds more stable
- [Casts] Change C-style (uint8_t*) casts into reinterpret_cast
- [Casts] Change C-style casts (int) and (float) into static_casts
It may prevent optimisations where the compiler may cause issues when allocated memory is not aligned for 4-byte access when storing/reading int from a `char array` allocated memory block for example.
Would really appreciate if one or two people could check the commits here to see if I made obvious errors in replacing the C-style casts. |
Besides that 1 remark, no obvious mistakes that I can detect 👍 |
re: esp8266/Arduino#8261 (comment) |
@mcspr The only thing we can do is actually try it and see if we still encounter "strange behavior". The main problem I'm having with those hard to reproduce crashes is that I truly have no clue why they happen. |
Memory errors are inconclusive though, and if it's something like that it is pretty hard to track only by the trace itself. btw, I'd Originally, I thought of reinterpret_casts of F(...) -> string, but those seem to be correct b/c conversion happens const char* -> flashstringhelper* -> const char* again, so it does not seem to violate any rules regarding the object(s) lifetime.
Could only find a single entry of std::list, were the traces pointing there? btw, I would not mind at-ping if the issue happens again (since I am not subscribed to the repo). I do suspect some linker issues with pio builds, since I happened on some weird problem where F(...) / PSTR(...) macros returned nullptr, which broke strlen_P by dereferencing nullptr. Hard to detect as well, and probably happens when it decides to keep the existing build directory.... |
Hmm nullptr when using F()/PSTR() is an interesting one. I have suspected PIO linker issues in the past, but was never able to prove it. And the |
Oh almost forgot... For example: void foo(const char* text);
void foo(const __FlashStringHelper * text);
// Call the function:
foo(F("bar")); If you use |
something like that. under unknown conditions, this piece of code triggered an error on strlen_P(...) breaking on PSTR(...) result (i.e. and the most fun one to find out this appended nullptr pointer to commands list: Still not being able to track that down 🤷 Wouldn't explain the missing PSTR(...) though. |
Isn't that just like a forward declaration so you don't need to include the header file where that class is defined in the .h file of Only difference here is that it is never actually defined, so you can never create an instance of it, only have a pointer to it. |
Hmm that one is tricky. |
Yeah, looks like it. It would've triggered incomplete type error if it is ever dereferenced, I just wondered if never declaring it somehow confused the optimizer and made it seem unused. Another angle is string de-duplication introduced in the 2.6.x, since the linker is supposed to track __pstr__ just as it does with normal inline C-strings [1]. Not a lot of changes in the actual header implementing flash-strings, so compiler might've done something different. I dug up the specific .elf + .bin pair I had failing re. above, with terminal command registration of [1] https://github.com/earlephilhower/newlib-xtensa/blob/xtensa-4_0_0-lock-arduino/newlib/libc/sys/xtensa/sys/pgmspace.h plus, it's inside a gcc extension block, which has some weird rules about lifetimes |
Or, maybe not exactly. I dug up at least two .elf files with 'broken' flash string pointer loading, which both seem to try to do this optimization by encoding the value directly in the instruction argument ( edit: and my memory had been fuzzy around the actual pointer values, it was not a null but some semi-random number void _mqttInitCommands() {
terminalRegisterCommand(F("MQTT.RESET"), [](const terminal::CommandContext&) { ... });
terminalRegisterCommand(F("MQTT.INFO"), [](const terminal::CommandContext&) { ... });
} (gdb) disassemble '_mqttInitCommands()'
Dump of assembler code for function _mqttInitCommands():
0x402083a4 <+0>: l32r a3, 0x40208398
0x402083a7 <+3>: movi a2, 0x7a7
0x402083aa <+6>: addi a1, a1, -16
0x402083ad <+9>: slli a2, a2, 17
0x402083b0 <+12>: s32i a0, a1, 12
0x402083b3 <+15>: call0 0x40213488 <terminalRegisterCommand(__FlashStringHelper const*, void (*)(terminal::CommandContext const&))>
0x402083b6 <+18>: l32r a3, 0x4020839c
0x402083b9 <+21>: l32r a2, 0x402083a0
0x402083bc <+24>: call0 0x40213488 <terminalRegisterCommand(__FlashStringHelper const*, void (*)(terminal::CommandContext const&))>
0x402083bf <+27>: l32i a0, a1, 12
0x402083c2 <+30>: addi a1, a1, 16
0x402083c5 <+33>: ret.n
End of assembler dump.
(gdb) x (*0x4020839c)
0x40208380 <_FUN(terminal::CommandContext const&)>: 0x02f0c112
(gdb) p (const char*)(*0x402083a0)
$1 = 0x4026fa70 <_mqttInitCommands()::__pstr__> "MQTT.INFO"
(gdb) x (*0x40208398)
0x40209c70 <_FUN(terminal::CommandContext const&)>: 0x02f0c112 0x7a7 << 17 is 0xf4e0000 though and not some flash location pointer (unless I misunderstood the math around it) |
btw, I think this got tracked down to the mingw-w64 aka windows toolchain, but not sure how to proceed just yet: |