-
Notifications
You must be signed in to change notification settings - Fork 7.9k
Enable -Wassign-enum
in the Cirrus clang build (plus two fixes)
#10641
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
Conversation
Some code fails with this warning - e.g. enums are (ab)used by the JIT and others as bit fields, which is not correct. |
This is the only ASAN build for push, so I don't think it should be failing, especially in the build step. |
How would you suggest fixing those bit fields? |
2070acc
to
ec7eb72
Compare
Dropped the two fix commits because #10640 was merged to PHP-8.1. |
I was hoping there was an attribute to specify whether an enum could be bit-wised but it doesn't seem so... Depends on how many errors there are. I think it would be fair to convert those cases to |
I tried to find out whether using enums as bit fields is even allowed in the standard, and apparently, the standard doesn't disallow it. Though I think using real bit fields would be preferable. While this clang warning is very useful to find obvious mistakes (like the ones I already fixed), it can easily be silenced by adding an explicit cast. This adds some clutter to the code for a warning workaround, but in this case (if bit fields are not desired) I think it's worth it. |
ec7eb72
to
d0c5a7e
Compare
I've added workarounds. Let's see if I've found them all. Waiting for CI to finish. |
d0c5a7e
to
b8640ba
Compare
Now the compiler succeeds, but the linker fails:
I think this is due to patch "set CXXFLAGS as well", and I believe PHP needs to call |
b8640ba
to
5e1ae38
Compare
@MaxKellermann Sounds good, thank you! |
To find mistakes with enums. See php#10617 (review)
The flags were set to zero right before this operation, so it's impossible for the `&=` to remove any flag.
5e1ae38
to
3678c0a
Compare
That worked. ASAN_DEBUG_NTS build succeeded (only the tests are still running atm). |
|
C allows using bitmasks in enums. Instead of fixing the problems by typecasting hacks, it's better to include the necessary bits into the enums declarations. The bigger problem that |
The problem here is the inverted masks (for bit-wise AND). You don't want to add inverted versions of all flags, do you?
I don't think that alone is a problem. If a warning option is only available in clang and we decide it's a benefit (because it finds bugs - and indeed this one found a few in PHP), we should take advantage of it. |
I agree with this. I understand it's annoying to have a failing build after building successfully locally but that's still better than a potential regression. |
We have to add just ENUM_MAX_RANGE (that is power of 2 minus 1).
Finding problems is good, hiding them is not. This might help to find real problem in a couple of places, but adding type casts will hide problems forever. |
No, that doesn't work. Why would it? Take this line: php-src/ext/opcache/jit/zend_jit_trace.c Line 7637 in da777d4
clang complains about this line, because ~ZEND_JIT_TRACE_HALT is not in the enum 's range.
php-src/ext/opcache/jit/zend_jit_internal.h Line 377 in da777d4
Therefore, ~ZEND_JIT_TRACE_HALT == ~0x40 == 0xffffffbf == -65 . This value is not found anywhere in enum _zend_jit_trace_stop .
Let's say you add some |
Which problems will it hide?
That is correct, and I had already acknowledged that (prior to researching it, I wasn't sure). The code was correct already before I added the casts, and this clang warning is indeed a false positive. It is arguable whether adding workarounds for false positives is a good idea. The other type of workaround (using the underlying type as bit field) is worse IMO because it removes information from the source code, making it less readable and more obscure. Anyway, there is no right and now wrong about that decision; it is personal taste. Not my idea - I created this PR only because @iluuu1994 asked to enable this warning. |
If ZEND_JIT_TRACE_HALT = 0x40 is the higher possible bit, the ENUM_MAX_RANGE should be 0x7f. This should eliminate warning without type casting, of course, if -Wassign-enum in CLANG follows C semantic. |
I don't understand. How can adding an enumerator with value This isn't about C semantics. As I already said, the code is correct. Warnings are not about incorrect code, but about suspicious code that may be buggy. |
|
I think what you meant was "multiplied by 2", or "shift left by 1", and minus 1.
Oops, I messed up the third value. This doesn't actually work. We'd need a case for each possible combination, which we obviously can't once we have more than 2-3 flags. |
That's not how this clang warning is implemented. I repeat: clang sees the value |
Then, this is a clang bug (or feature), because we don't assign |
I tried something here: 9b76379 This adds a macro to create bit enums. Basically, it just declares the enum, calculates the mask by @dstogov Are you happy with this approach? This way we have compile time safety for non-bit enums and at least runtime safety (in debug mode) for bit-enums. |
You didn't ask me, but I'll drop my opinion anyway: I don't like it, because I hate the preprocessor, and this adds just more weird macros. C has a native way to declare bit fields. For
This isn't obscure and you can use it without fiddling bits and masks. No hard-coded shifted values like
becomes:
Initialization is also easy; this:
becomes:
Really, can it be any easier? To trade some performance for memory overhead, omit the This is completely type safe; bad operations lead to compiler errors (not warnings, not optional). There is no overhead for passing those structs around if they fit in a register; it even results in identical machine code! Let me godbolt this for you: https://godbolt.org/z/a6ncYT1n1 (If this convinces you, I'd be happy to submit a PR.) |
I tried to keep it as close to the original code to avoid breaking code. Granted, that's not relevant for the .c file I picked. If we can adjust the declaration using bitfields does seem preferable. There are some enums I don't think we can change, like Whether a new concept like bit enums are worth it for these few cases, I'm not sure. |
But that's not a bit field, is it? I don't see any bit-wise operations on it. |
See #10617 (review)
I've submitted the two fixes to PHP-8.1 as well: #10640 - if that PR gets merged, I'll drop these commits here. You decide.