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
Unify kroundup macros and fix gcc warnings #1051
Conversation
What does all this ghastly code end up compiling to? This is heavily inlined. Will it be oveflowing the sizes of what is permissible for inline with the extra logic, or does the compiler manage to realise it's mostly const and just replace it with 0 or 1? |
Looking at godbolt it appears that a function doing:
adds 4 instructions for gcc9.2 (x86_64) and a whopping 24 instructions if using clang, compared to my branch. That may have implications for inlining. I'm wondering if we can just do something to do disable the bogus warning, or completely ditch this and only round up if values are < some fixed size. The case the compilers are spotting are only for sizes which wouldn't actually work anyway, so failing to round up and just allocate what the user asked for isn't an issue as rounding up or otherwise it will result in a memory allocation failure. The difference is asking for 9 yotta bytes vs 18 I think :-) My PR already had checks to stop it rounding up if it got too big, but apparently that still triggered the compiler warnings. Was that because the use of INT_MAX is still too large? I haven't managed to reproduce any of these warnings, even using an -m32 capable compiler. Do you know which piece of code gave the warning originally? (Edit: no matter - it's bam_fastq.c:28. I'll try pasting that into godbolt to explore different compiler/arch.) |
The same macro (32 bit version at least) turns up in hts.h, khash.h, kseq.h, rbuf.h, bgzf.c and faidx.c also. Blergh. I guess we could ignore the original problem which was memory failure when you overflow and round down to zero, becoming a free statement instead, but that feels like we're just ignoring known bugs. Still we're no worse off at least as they're already there. However in every single use case it is prior to a realloc (occasionally 2 of the same size) or a malloc, with very variable degrees of bounds and overflow checking. It's not even appropriate to put size checking in kroundup either as sometimes we then take that rounded up value and do things like this:
What this makes me think is that kroundup is a total red herring and what we want is simply a krealloc function which automatically does more some rounding up and has uniformly good overflow checks. However, in the interests of expediency, I'm inclined to go with this as a temporary workaround for the over-zealous warnings reported by some gcc/system combos. Comments? |
Did you remember to use
The version in
Yes, we do need to sort out the places where the rounded-up value gets multiplied by something, although most are likely harmless because the array in question is growing slowly and you run out of memory before it gets the chance to overflow. Some of these (e.g. |
Yep and for this reason IMHO there's little point in inlining the rounding up — you're about to do a relatively expensive memory allocation anyway. In the case of …which is basically equivalent to James's
(IMHO the |
Replace several kroundup32 and kroundup_size_t macro definitions with a new unified implementation. The new one will work correctly for all integer types (both signed and unsigned) up to 64 bits. An attempt to round up that would overflow results in the maximum value that can be stored in the given type. The implementation avoids conditionals involving large values in an attempt to fix some gcc warnings in samtools and bcftools. They appeared after commit 29c294e which fixed a bug where kroundup would wrap around to zero on large values. The warnings are caused by jump threading optimisations that create code paths for the large value cases, which gcc then warns about. See: https://developers.redhat.com/blog/2019/03/13/understanding-gcc-warnings-part-2/ Includes extra tests to ensure the new kroundup works as desired.
@jmarshall Yes, I've also considered moving most of It doesn't make that much difference to the size of the binary:
but checking with Before:
After:
|
Looks like we've reached a good consensus here. I'm happy, but will do a quick bit of compilation and testing and hopefully merge soon. PS. Yes, I forgot to turn on -O2 in godbolt. Oops. I see what you mean about arm too. Nice instruction set! |
Merged, although the samtools cut_target.c:66 warning is still to be resolved. I suspect something like this would work:
Although ideally we'd have kmalloc and krealloc and it'd just work without horrid shenanigans. Patch now to stop compilation errors and we can get more time to come up with a better solution. |
Thanks. Easiest solution for
As it goes from signed to unsigned, it always fits. |
Good point. I'm happy for you to make that 1 line tweak without PR if you wish provided it doesn't trigger any warnings. Looks like you've verified that already. |
I've pushed the fix to samtools. |
Since 29c294e, which fixed overflow bugs in
kroundup32()
andkroundup_size_t()
among other things, samtools and bcftools have been getting gcc warnings likehtslib/kstring.h:163:16: error: argument 1 value ‘18446744073709551615’ exceeds maximum object size 9223372036854775807 [-Werror=alloc-size-larger-than=]
. These apparently appear due to jump threading optimisations which generate code paths for the case whenkroundup
avoids the overflow and then warns thatrealloc()
has been called on the result. (See https://developers.redhat.com/blog/2019/03/13/understanding-gcc-warnings-part-2/ for an explanation.)This is my best attempt to fix this. It replaces several kroundup32 and kroundup_size_t macro definitions with a new unified implementation. The new one will work correctly for all integer types (both signed and unsigned) up to 64 bits. It also avoids conditionals with large numbers in the macro definition to work around the jump threading problem. This mostly works - with this change all of the warnings go from bcftools and only one is left in samtools (where a signed value is rounded up and then multiplied by two in the
realloc
statement, so probably actually legitimate).It's been tested on 32-bit and 64-bit builds, and works on both (barring the issue with samtools).
Includes extra tests to ensure the new kroundup works as desired.
Replaces #1048, which failed on 32-bit.