Hi
On Fri, Aug 15, 2014 at 11:35 AM, Thomas H.P. Andersen <[email protected]> wrote:
> On Fri, Aug 15, 2014 at 10:55 AM, David Herrmann <[email protected]>
> wrote:
>> Hi
>>
>> On Thu, Aug 14, 2014 at 8:07 PM, Lennart Poettering
>> <[email protected]> wrote:
>>> On Fri, 18.07.14 16:02, Thomas H.P. Andersen ([email protected]) wrote:
>>>
>>>> 1716f6dcf54d4c181c2e2558e3d5414f54c8d9ca (resolved: add LLMNR support
>>>> for looking up names) broke the build on clang.
>>>>
>>>> src/resolve/resolved-manager.c:553:43: error: non-const static data
>>>> member must be initialized out of line
>>>> uint8_t buffer[CMSG_SPACE(MAX(sizeof(struct in_pktinfo), sizeof(struct
>>>> in6_pktinfo)))
>>>>
>>>> Moving the MAX(...) to a separate line fixes that problem but another
>>>> error then happens:
>>>>
>>>> src/resolve/resolved-manager.c:554:25: error: fields must have a
>>>> constant size: 'variable length array in structure' extension will
>>>> never be supported
>>>> uint8_t buffer[CMSG_SPACE(size)
>>>>
>>>> We have encountered the same problem before and Lennart was able to
>>>> write the code in a different way. Would this be possible here too?
>>>
>>> My sugegstion here would be to maybe rewrite the MAX() macro to use
>>> __builtin_constant_p() so that it becomes constant if the params are
>>> constant, and only uses code block when it isn't. Or so...
>>>
>>> http://lists.freedesktop.org/archives/systemd-devel/2014-August/021912.html
>>
>> Hm, I don't know whether that works. See the description here:
>> https://gcc.gnu.org/onlinedocs/gcc-4.3.3/gcc/Other-Builtins.html
>>
>> What you propose is something like my attached patch, I guess? Along
>> the lines of:
>> (__builtin_constant_p(A) && __builtin_constant_p(B)) ?
>> ((A) > (B) ? (A) : (B)) :
>> ({ ....OLD_MAX.... })
>>
>> Thing is, the ELSE case is not considered a compile-time constant by
>> LLVM. Therefore, the whole expression is not considered a compile-time
>> constant. I don't know whether conditions with __builtin_constant_p()
>> are evaluated at the parser-step. The GCC example replaces the ELSE
>> case with -1, effectively making both compile-time constants.
>>
>> I also added a test-case to make sure __builtin_constant_p doesn't
>> evaluate the arguments.
>>
>> Can someone with LLVM set up give this a spin?
>
> I still get:
> src/resolve/resolved-manager.c:844:43: error: non-const static data
> member must be initialized out of line
> uint8_t buffer[CMSG_SPACE(MAX(sizeof(struct
> in_pktinfo), sizeof(struct in6_pktinfo)))
> ^
Thanks for trying!
Result is as I expected. Evaluation takes place _after_ validating
compile-time constants, and thus __builtin_constant_p in combination
with ?: will not work if not both cases are constant. Maybe it works
with __builtin_choose_expr()?
Can you try the attached patch?
If that still doesn't work, I guess we're left with your proposed
solution below, or we add MAX_CONST() which just does (A > B)?A:B.
> I got the following to compile but I have not have time to test it at
> all. Too ugly to live I guess...
>
> diff --git a/src/resolve/resolved-dns-stream.c
> b/src/resolve/resolved-dns-stream.c
> index eb78587..1b415ae 100644
> --- a/src/resolve/resolved-dns-stream.c
> +++ b/src/resolve/resolved-dns-stream.c
> @@ -62,10 +62,14 @@ static int dns_stream_complete(DnsStream *s, int error) {
> }
>
> static int dns_stream_identify(DnsStream *s) {
> + const size_t size = __builtin_constant_p(
> + MAX(sizeof(struct in_pktinfo), sizeof(struct in6_pktinfo))) ?
> + MAX(sizeof(struct in_pktinfo), sizeof(struct in6_pktinfo)) :
> 0;
No reason to make "size" constant. You can use:
size_t size = MAX(....);
uint8_t buffer[...];
This will be similar to alloca(), I think... or maybe I'm wrong..
Thanks
David
> union {
> struct cmsghdr header; /* For alignment */
> - uint8_t buffer[CMSG_SPACE(MAX(sizeof(struct
> in_pktinfo), sizeof(struct in6_pktinfo)))
> + uint8_t buffer[CMSG_SPACE(size)
> + EXTRA_CMSG_SPACE /* kernel appears
> to require extra space */];
> +
> } control;
> struct msghdr mh = {};
> struct cmsghdr *cmsg;
> @@ -73,6 +77,7 @@ static int dns_stream_identify(DnsStream *s) {
> int r;
>
> assert(s);
> + assert(size > 0);
>
> if (s->identified)
> return 0;
> diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c
> index bfbdc7d..1342fb1 100644
> --- a/src/resolve/resolved-manager.c
> +++ b/src/resolve/resolved-manager.c
> @@ -839,9 +839,12 @@ fail:
>
> int manager_recv(Manager *m, int fd, DnsProtocol protocol, DnsPacket **ret) {
> _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
> + const size_t size = __builtin_constant_p(
> + MAX(sizeof(struct in_pktinfo), sizeof(struct in6_pktinfo))) ?
> + MAX(sizeof(struct in_pktinfo), sizeof(struct in6_pktinfo)) :
> 0;
> union {
> struct cmsghdr header; /* For alignment */
> - uint8_t buffer[CMSG_SPACE(MAX(sizeof(struct
> in_pktinfo), sizeof(struct in6_pktinfo)))
> + uint8_t buffer[CMSG_SPACE(size)
> + CMSG_SPACE(int) /* ttl/hoplimit */
> + EXTRA_CMSG_SPACE /* kernel appears
> to require extra buffer space */];
> } control;
> @@ -855,6 +858,7 @@ int manager_recv(Manager *m, int fd, DnsProtocol
> protocol, DnsPacket **ret) {
> assert(m);
> assert(fd >= 0);
> assert(ret);
> + assert(size > 0);
>
> r = ioctl(fd, FIONREAD, &ms);
> if (r < 0)
diff --git a/src/shared/macro.h b/src/shared/macro.h
index 5619c32..ac0f3a6 100644
--- a/src/shared/macro.h
+++ b/src/shared/macro.h
@@ -133,12 +133,15 @@ static inline unsigned long ALIGN_POWER2(unsigned long u) {
})
#undef MAX
-#define MAX(a,b) \
- __extension__ ({ \
- typeof(a) _a = (a); \
- typeof(b) _b = (b); \
- _a > _b ? _a : _b; \
- })
+#define MAX(_A, _B) \
+ __extension__ (__builtin_choose_expr( \
+ (__builtin_constant_p(_A) && __builtin_constant_p(_B)), \
+ (((_A) > (_B)) ? (_A) : (_B)), \
+ ({ \
+ typeof(_A) _a = (_A); \
+ typeof(_B) _b = (_B); \
+ _a > _b ? _a : _b; \
+ })))
#define MAX3(x,y,z) \
__extension__ ({ \
diff --git a/src/test/test-util.c b/src/test/test-util.c
index 1850f97..d348ac5 100644
--- a/src/test/test-util.c
+++ b/src/test/test-util.c
@@ -70,6 +70,20 @@ static void test_align_power2(void) {
}
}
+static void test_max(void) {
+ /* try triggering compile-errors for non-const initializers */
+ static const struct {
+ int a;
+ } val1 = {
+ .a = MAX(10, 100),
+ };
+ int d = 0;
+
+ assert_se(val1.a == 100);
+ assert_se(MAX(++d, 0) == 1);
+ assert_se(d == 1);
+}
+
static void test_first_word(void) {
assert_se(first_word("Hello", ""));
assert_se(first_word("Hello", "Hello"));
@@ -926,6 +940,7 @@ int main(int argc, char *argv[]) {
test_streq_ptr();
test_align_power2();
+ test_max();
test_first_word();
test_close_many();
test_parse_boolean();
_______________________________________________
systemd-devel mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/systemd-devel