[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: Xen reliance on non-standard GCC features
On 05.06.2023 15:26, Roberto Bagnara wrote: > On 05/06/23 11:28, Jan Beulich wrote: >> On 05.06.2023 07:28, Roberto Bagnara wrote: >>> U1) Use of _Static_assert in C99 mode. >>> >>> U2) Empty initialization lists, both in C99 mode (ARM64 and X86_64) >>> and C18 mode (only X86_64). >>> >>> U3) Returning void expressions. >> >> As per above, tiny extensions like these are, I think, unlikely to be >> mentioned anywhere explicitly (or more than in passing). For the last of >> the three it may further be that it pre-dates when gcc started to >> properly document extensions. Oh, actually - U3 is documented along with >> -Wreturn-type. > > Noted: thanks! > >> Uses are generally intentional afaik, but eliminating cases of U2 and U3 >> would likely be possible with just slight overall impact. > > Ok. As this has an impact on MISRA compliance at some stage we will need > an official position on the subject. > >> As to U2, it's not clear why you distinguish C99 and C18 mode. > > I specified that because for MISRA compliance we need to stick > to one version of the language: while most translation units > are compiled in C99 mode, some are compiled in C18 mode and some > in C90 mode. However, I agree this is OT for the current discussion. > >> Throughout >> this summary of yours it would likely have been helpful if an example was >> provided for the behavior your describing, when the wording doesn't make >> it crystal clear (e.g. no example needed for U1 and U3 above). > > You are right: here are a few examples for U2: > > xen/arch/arm/cpuerrata.c:92.12-92.35: > empty initializer list (ill-formed for the C99 standard, ISO/IEC 9899:1999 > Section 6.7.8: "An empty initialization list." [STD.emptinit]). Tool used is > `/usr/bin/aarch64-linux-gnu-gcc-12' > xen/include/xen/spinlock.h:31.21-31.23: expanded from macro `_LOCK_DEBUG' > xen/include/xen/spinlock.h:143.57-143.67: expanded from macro > `SPIN_LOCK_UNLOCKED' > xen/include/xen/spinlock.h:144.43-144.60: expanded from macro > `DEFINE_SPINLOCK' I'm afraid this is a bad example, as it goes hand-in-hand with using another extension. I don't think using a non-empty initialization list is going to work with union lock_debug { }; > xen/arch/arm/cpuerrata.c:678.5-678.6: > empty initializer list (ill-formed for the C99 standard, ISO/IEC 9899:1999 > Section 6.7.8: "An empty initialization list." [STD.emptinit]). Tool used is > `/usr/bin/aarch64-linux-gnu-gcc-12' > > xen/arch/arm/cpufeature.c:33.5-33.6: > empty initializer list (ill-formed for the C99 standard, ISO/IEC 9899:1999 > Section 6.7.8: "An empty initialization list." [STD.emptinit]). Tool used is > `/usr/bin/aarch64-linux-gnu-gcc-12' Both of these are a common idiom we use: The "sentinel" of an array of compound type initializer. >>> U4) Static functions or variables used in inline functions with external >>> linkage. >> >> There's not a lot of "extern inline" that we've accumulated so far, I >> think. The only ones I'm aware of are sort() and bsearch(), and there >> the use is precisely for allowing the compiler to optimize away function >> calls. >> >> The documentation of this functionality is that of the gnu_inline >> function attribute, afaict. That would be 6.33.1 "Common Function >> Attributes" in 13.1.0 doc. > > No, it is not that one: > > xen/common/spinlock.c:316.29-316.40: > static function `observe_head(spinlock_tickets_t*)' is used in an inline > function with external linkage (ill-formed for the C99 standard, ISO/IEC > 9899:1999: "An ill-formed source detected by the parser." > [STD.diag/ext_internal_in_extern_inline_quiet]). Tool used is > `/usr/bin/aarch64-linux-gnu-gcc-12' > xen/common/spinlock.c:301.26-301.37: > `observe_head(spinlock_tickets_t*)' declared here > xen/include/xen/spinlock.h:180.1-180.4: > use 'static' to give inline function `_spin_lock_cb(spinlock_t*, > void(*)(void*), void*)' internal linkage Oh, I see. I guess by introducing another wrapper we could deal with that in sufficiently unintrusive a way. >>> U5) Enumerator values outside the range of `int'. > > Examples: > > xen/arch/x86/include/asm/guest/hyperv-tlfs.h:477.9-477.26: Loc #1 [culprit: > ISO C restricts enumerator values to range of 'int' (2147483648 is too large) > (ill-formed for the C99 standard, ISO/IEC 9899:1999: "An ill-formed source > detected by the parser." [STD.diag/ext_enum_value_not_int]). Tool used is > `/usr/bin/x86_64-linux-gnu-gcc-12'] > xen/arch/x86/include/asm/guest/hyperv-tlfs.h:477.43-477.52: Loc #2 [evidence: > ISO C restricts enumerator values to range of 'int' (2147483648 is too large)] > > xen/arch/x86/include/asm/guest/hyperv-tlfs.h:478.9-478.27: Loc #1 [culprit: > ISO C restricts enumerator values to range of 'int' (2147483649 is too large) > (ill-formed for the C99 standard, ISO/IEC 9899:1999: "An ill-formed source > detected by the parser." [STD.diag/ext_enum_value_not_int]). Tool used is > `/usr/bin/x86_64-linux-gnu-gcc-12'] > xen/arch/x86/include/asm/guest/hyperv-tlfs.h:478.43-478.52: Loc #2 [evidence: > ISO C restricts enumerator values to range of 'int' (2147483649 is too large)] It's not entirely clear to me in how far hyperv-tlfs.h is a header fully of our own. It may be possible to switch to #define instead if we don't "follow" someone else's header. > xen/arch/x86/include/asm/hvm/svm/vmcb.h:143.5-143.27: Loc #1 [culprit: ISO C > restricts enumerator values to range of 'int' (2147483648 is too large) > (ill-formed for the C99 standard, ISO/IEC 9899:1999: "An ill-formed source > detected by the parser." [STD.diag/ext_enum_value_not_int]). Tool used is > `/usr/bin/x86_64-linux-gnu-gcc-12'] > xen/arch/x86/include/asm/hvm/svm/vmcb.h:143.31-143.38: Loc #2 [evidence: ISO > C restricts enumerator values to range of 'int' (2147483648 is too large)] Here we have more leeway, and imo the offending enumerations are an abuse of "enum" in the first place. >>> U6) Empty declarations. > > Examples: > > xen/arch/arm/arm64/lib/find_next_bit.c:57.29: > empty declaration (ill-formed for the C99 standard, ISO/IEC 9899:1999 Section > 6.7: "An empty declaration." [STD.emptdecl]). Tool used is > `/usr/bin/aarch64-linux-gnu-gcc-12' > > xen/arch/arm/arm64/lib/find_next_bit.c:103.34: > empty declaration (ill-formed for the C99 standard, ISO/IEC 9899:1999 Section > 6.7: "An empty declaration." [STD.emptdecl]). Tool used is > `/usr/bin/aarch64-linux-gnu-gcc-12' Looks like these could be taken care of by finally purging our EXPORT_SYMBOL() stub. > xen/arch/arm/include/asm/vreg.h:143.26: > empty declaration (ill-formed for the C99 standard, ISO/IEC 9899:1999 Section > 6.7: "An empty declaration." [STD.emptdecl]). Tool used is > `/usr/bin/aarch64-linux-gnu-gcc-12' > > xen/arch/arm/include/asm/vreg.h:144.26: > empty declaration (ill-formed for the C99 standard, ISO/IEC 9899:1999 Section > 6.7: "An empty declaration." [STD.emptdecl]). Tool used is > `/usr/bin/aarch64-linux-gnu-gcc-12' I'm having trouble spotting anything suspicious there. > xen/arch/arm/include/asm/arm64/flushtlb.h:70.51: > empty declaration (ill-formed for the C99 standard, ISO/IEC 9899:1999 Section > 6.7: "An empty declaration." [STD.emptdecl]). Tool used is > `/usr/bin/aarch64-linux-gnu-gcc-12' Same here. I the tool having an issue with the instantiation of (inline) functions by way of a macro? >>> U7) Empty enum definitions. > > Example: > > xen/arch/arm/include/asm/vgic.h:275.6-275.17: > enum declaration `gic_sgi_mode' is incomplete (ill-formed for the C99 > standard, ISO/IEC 9899:1999 Section 6.7.2.2: "An incomplete enum > declaration." [STD.emptenum]). Tool used is > `/usr/bin/aarch64-linux-gnu-gcc-12' > >> ... here I wonder whether instead you mean forward declaration of enums >> (i.e. what the standard allows for structures and unions only). > > It is reported as an enum forward declaration if the enum is later > properly declared. My understanding is that this is not the case > for the example above. asm/gic.h provides the full definition. There looks to be exactly one case (smp.c) where asm/vgic.h is included but asm/gic.h isn't. As there may be peculiarities to this, Arm maintainers would need to take a look to decide whether also including the other header that is an option. >>> U8) Conversion between incompatible pointer types. >> >> Do we have any uses that aren't, by using casts, documenting that the >> conversions are deliberate? Otherwise I would expect the compiler to >> warn, and hence the build to fail due to -Werror. Then again I'm sure >> we have ample uses of casts left which are actually bogus. > > Examples: > > xen/common/kernel.c:552.18-552.47: > implicit cast converts from `const __typeof__(*(¶ms))*' (that is `const > struct xen_platform_parameters*') to `void*' (ill-formed for the C99 > standard, ISO/IEC 9899:1999 Section 6.5.16.1: "Implicit conversion from a > pointer to an incompatible pointer." [STD.pteincmp]). Tool used is > `/usr/bin/aarch64-linux-gnu-gcc-12' > xen/include/xen/guest_access.h:65.23-65.24: expanded from macro > `copy_to_guest_offset' > xen/include/xen/guest_access.h:104.5-104.41: expanded from macro > `copy_to_guest' > > xen/common/kernel.c:566.14-566.59: > implicit cast converts from `const __typeof__(*(chgset))*' (that is `const > char*') to `void*' (ill-formed for the C99 standard, ISO/IEC 9899:1999 > Section 6.5.16.1: "Implicit conversion from a pointer to an incompatible > pointer." [STD.pteincmp]). Tool used is `/usr/bin/aarch64-linux-gnu-gcc-12' > xen/include/xen/guest_access.h:65.23-65.24: expanded from macro > `copy_to_guest_offset' > xen/include/xen/guest_access.h:104.5-104.41: expanded from macro > `copy_to_guest' > > xen/common/kernel.c:613.14-613.41: > implicit cast converts from `const __typeof__(*(&fi))*' (that is `const > struct xen_feature_info*') to `void*' (ill-formed for the C99 standard, > ISO/IEC 9899:1999 Section 6.5.16.1: "Implicit conversion from a pointer to an > incompatible pointer." [STD.pteincmp]). Tool used is > `/usr/bin/aarch64-linux-gnu-gcc-12' > xen/include/xen/guest_access.h:123.23-123.24: expanded from macro > `__copy_to_guest_offset' > xen/include/xen/guest_access.h:152.5-152.43: expanded from macro > `__copy_to_guest' > > xen/common/kernel.c:645.14-645.71: > implicit cast converts from `const __typeof__(*(deny ? xen_deny() : > saved_cmdline))*' (that is `const char*') to `void*' (ill-formed for the C99 > standard, ISO/IEC 9899:1999 Section 6.5.16.1: "Implicit conversion from a > pointer to an incompatible pointer." [STD.pteincmp]). Tool used is > `/usr/bin/aarch64-linux-gnu-gcc-12' > xen/include/xen/guest_access.h:65.23-65.24: expanded from macro > `copy_to_guest_offset' > xen/include/xen/guest_access.h:104.5-104.41: expanded from macro > `copy_to_guest' > > xen/common/memory.c:1745.20-1745.53: > implicit cast converts from `const __typeof__(*(&topology))*' (that is `const > struct xen_vnuma_topology_info*') to `void*' (ill-formed for the C99 > standard, ISO/IEC 9899:1999 Section 6.5.16.1: "Implicit conversion from a > pointer to an incompatible pointer." [STD.pteincmp]). Tool used is > `/usr/bin/aarch64-linux-gnu-gcc-12' > xen/include/xen/guest_access.h:123.23-123.24: expanded from macro > `__copy_to_guest_offset' > xen/include/xen/guest_access.h:152.5-152.43: expanded from macro > `__copy_to_guest' > > xen/common/memory.c:1808.14-1808.47: > implicit cast converts from `const __typeof__(*(&topology))*' (that is `const > struct xen_vnuma_topology_info*') to `void*' (ill-formed for the C99 > standard, ISO/IEC 9899:1999 Section 6.5.16.1: "Implicit conversion from a > pointer to an incompatible pointer." [STD.pteincmp]). Tool used is > `/usr/bin/aarch64-linux-gnu-gcc-12' > xen/include/xen/guest_access.h:123.23-123.24: expanded from macro > `__copy_to_guest_offset' > xen/include/xen/guest_access.h:152.5-152.43: expanded from macro > `__copy_to_guest' > > xen/common/memory.c:1841.14-1841.47: > implicit cast converts from `const __typeof__(*(&grdm.map))*' (that is `const > struct xen_reserved_device_memory_map*') to `void*' (ill-formed for the C99 > standard, ISO/IEC 9899:1999 Section 6.5.16.1: "Implicit conversion from a > pointer to an incompatible pointer." [STD.pteincmp]). Tool used is > `/usr/bin/aarch64-linux-gnu-gcc-12' > xen/include/xen/guest_access.h:123.23-123.24: expanded from macro > `__copy_to_guest_offset' > xen/include/xen/guest_access.h:152.5-152.43: expanded from macro > `__copy_to_guest' These are all a common pattern. Line 65 in xen/guest_access.h is (void)((hnd).p == _s); \ i.e. not an assignment in the first place. Nearby assignments don't involve _s, yet that's pretty clearly what is being referred to by const __typeof__(*(...))*. In pointer comparisons, differring qualifiers are okay afaik (6.5.9), so I wonder whether the tool is becoming confused here. I don't know the acronyms used, but isn't STD.pteincmp referring to comparisons rather that assignments? > xen/common/efi/boot.c:335.16-335.56: > implicit cast converts from `const CHAR16*' (that is `const unsigned short*') > to `void*' (ill-formed for the C99 standard, ISO/IEC 9899:1999 Section > 6.5.16.1: "Implicit conversion from a pointer to an incompatible pointer." > [STD.pteincmp]). Tool used is `/usr/bin/aarch64-linux-gnu-gcc-12' Same here - comparison of the result of wmemchr() (const CHAR16*) with an expression derived from "data" (void*). > xen/common/libfdt/fdt_overlay.c:733.69-733.87: > implicit cast converts from `const char*' to `void*' (ill-formed for the C99 > standard, ISO/IEC 9899:1999 Section 6.5.16.1: "Implicit conversion from a > pointer to an incompatible pointer." [STD.pteincmp]). Tool used is > `/usr/bin/aarch64-linux-gnu-gcc-12' Same here again, I think. >>> U9) Conversion between function pointers and object pointers. > > Example: > xen/arch/x86/apic.c:1159.16-1159.55: Loc #1 [culprit: c_style cast converts > from `const void*' to `unsigned(*)(void)' (ill-formed for the C99 standard, > ISO/IEC 9899:1999 Annex J.5.7: "A pointer to a function is converted to a > pointer to an object or a pointer to an object is converted to a pointer to a > function (6.5.4, 6.3.2.3)." [STD.funojptr]). Tool used is > `/usr/bin/x86_64-linux-gnu-gcc-12'] > >> Uses I'm readily aware of are deliberate. Plus isn't this shorthand >> for going through uintptr_t intermediately only anyway? > > I don't understand the last sentence. 6.3.2.3 allows conversions between integer and pointer types. Hence isn't intermediately going through uintptr_t merely a more verbose way of casting between function and object pointers directly: ptr = (void *)(uintptr_t)func; vs ptr = (void *)func; ? >>> Here is a list of extensions that are documented in the GCC manual: >> >> I suppose that this list wasn't meant to be complete? The most >> prominent example is probably asm(). > > As far as I can tell the list was almost complete (I realize now > that the use of the keyword __signed__ was omitted because > investigation was not completed). But I am probably misunderstanding > you. Well, your list didn't include asm(), which is an extension we can't do without. We also use __attribute__(()) extensively. And while hunting for extensions which aren't documented in their own dedicated sections, I think I had come across more. I didn't write these down, and if at all possible I'd prefer to avoid repeating the exercise. Jan
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |