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
RPMLint reports serios compiler warning in Font.cpp #1187
Comments
This is a known issue that has been reported for a while by SFML's own CI static analysis pass: |
This is the corresponding code: // Build the key by combining the code point, bold flag, and outline thickness
Uint64 key = (static_cast<Uint64>(*reinterpret_cast<Uint32*>(&outlineThickness)) << 32)
| (static_cast<Uint64>(bold ? 1 : 0) << 31)
| static_cast<Uint64>(codePoint); The cast is safe here because we just want a unique key, we are not interested in the value itself. However, this means that outlineTichkness values that differ by tiny amount (like 1e-5) will produce distinct keys and thus produce two different glyphs although they will visually be similar in terms of pixels. I would rather truncate the floating point value to a fixed number of decimals, multiply by the corresponding power of ten to make it integer, and perform a true cast to int32. This would remove the warning, and ensure that outlineThickness values that are close enough will use the same glyph. |
I propose a mapping function such as this: #include <cstring>
#include <cstdint>
template <class T, class U>
inline T reinterpret(const U& input)
{
T output;
std::memcpy(&output, &input, sizeof(U));
return output;
}
std::uint64_t combine(float outlineThickness, bool bold, std::uint32_t codePoint)
{
return (reinterpret<std::uint64_t>(outlineThickness) << 32) | (static_cast<std::uint64_t>(bold) << 31) | codePoint;
} This will get rid of the warning and not even incur any performance penalty over the current implementation. The problem (and justification for the warning) is that the current implementation is allowed to invoke undefined behaviour when compiled by optimizing compilers. Even though we are telling the compiler to read the same address "in a different way" it will have no objections to reading from a completely different address because it assumes that pointers to objects of different types cannot reside at the same address. @LaurentGomila The solution you propose would work in trivial cases, however there are edge cases where we really shouldn't try to be overly smart. If the user for whatever reason wants to scale glyphs using an |
@binary1248 that looks broken on big-endian to me |
@jcowgill How so?
|
Example: #include <iostream>
#include <iomanip>
#include <cstring>
#include <stdint.h>
template <class T, class U>
inline T reinterpret(const U& input)
{
T output {};
std::memcpy(&output, &input, sizeof(U));
return output;
}
int main(void)
{
uint32_t x = 0xDEADBEEF;
std::cout << std::uppercase << std::hex << std::setw(16) << std::setfill('0');
std::cout << reinterpret<uint64_t>(x) << std::endl;
} Little endian prints: Therefore Note that you need |
True, it should rather be |
@jcowgill Thanks for pointing that out. Indeed I overlooked that I was passing 2 differently sized types to #include <cstring>
template <typename T, typename U>
inline T reinterpret(const U& input)
{
T output;
std::memcpy(&output, &input, sizeof(U));
return output;
}
Uint64 combine(float outlineThickness, bool bold, Uint32 codePoint)
{
return (static_cast<Uint64>(reinterpret<Uint32>(outlineThickness)) << 32) | (static_cast<Uint64>(bold) << 31) | codePoint;
} |
So, whats stopping us to commit this now ? |
I've been busy with releasing 2.4.2 and exams the past few weeks. If @binary1248's solution is accepted by everyone, I could or binary1248 could create a PR for it. |
Is this already merged? |
See #1396. |
When compiling for openSUSE 42.2 and 42.3 (not yes released) I get this error:
GCC 4.8 is used for native builds.
The text was updated successfully, but these errors were encountered: