Skip to content

In curl 7.88.1, wrapping curl_easy_setopt in macro is broken when compiling with GCC <12.1 #10726

Closed
@kchow-FTNT

Description

@kchow-FTNT

I did this

Our project is currently using GCC 10.3 and as far as I know, this should be supported by curl 7.88.1. However, upon trying to upgrade curl from 7.86.0 to 7.88.1 we get some compilation errors in our existing code. The issue is known and appears to be fixed in GCC 12.1; #pragma statements in macros can be reordered and this interferes with disabling -Wdeprecated-declarations.

This is a rough simplification of what our code looks like, and a highly simplified version of the current logic within curl 7.88:

typedef enum {
    CURLOPT_DEPRECATED __attribute__((__deprecated__)),
    CURLOPT_OKAY,
} CURLoption;

int curl_easy_setopt(CURLoption val);

#define CURL_IGNORE_DEPRECATION(statement) \
  _Pragma("GCC diagnostic push") \
  _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") \
  statement \
  _Pragma("GCC diagnostic pop")

static void __attribute__((__warning__("bad"))) __attribute__((__unused__)) __attribute__((__noinline__)) curl_warn(void) {
                __asm__("");
}

#define curl_easy_setopt(_expr) \
  __extension__ ({ \
    CURLoption _internal_opt = (_expr); \
    if (__builtin_constant_p(_internal_opt)) { \
        CURL_IGNORE_DEPRECATION( \
            if (_internal_opt == CURLOPT_DEPRECATED) { \
                curl_warn(); \
            } \
        ) \
    } \
    curl_easy_setopt(_internal_opt);\
  })

#define SPRINGBOARD4(_expr) \
    ({ \
        int ret = (_expr); \
        ret; \
    })

#define SPRINTBOARD3(_expr) \
    ({ \
        if (SPRINGBOARD4(_expr) < 0) { \
            return -1; \
        } \
    })

#define SPRINGBOARD2(_expr) \
  SPRINTBOARD3(_expr)

#define SPRINGBOARD1(_expr) \
  SPRINGBOARD4(_expr)

int test(void) {
    SPRINGBOARD2(curl_easy_setopt(CURLOPT_OKAY));
    if (SPRINGBOARD1(curl_easy_setopt(CURLOPT_OKAY)) < 0) {
        return -1;
    }
    return 0;
}

Please try this code snippet out on godbolt.org under GCC < 12.1 The compiler output should look something like this:

<source>: In function 'test':
<source>:51:5: warning: 'CURLOPT_DEPRECATED' is deprecated [-Wdeprecated-declarations]
   51 |     SPRINGBOARD2(curl_easy_setopt(CURLOPT_OKAY));
      |     ^~~~~~~~~~~~
<source>:2:5: note: declared here
    2 |     CURLOPT_DEPRECATED __attribute__((__deprecated__)),
      |     ^~~~~~~~~~~~~~~~~~
<source>:52:1: error: expected expression before '#pragma'
   52 |     if (SPRINGBOARD1(curl_easy_setopt(CURLOPT_OKAY)) < 0) {
      | ^  
Compiler returned: 1

And the preprocessor output should look something like this:

int test(void) {
   
#pragma GCC diagnostic push
   
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
   
#pragma GCC diagnostic pop
    do { if (({ int ret = (__extension__ ({ CURLoption _internal_opt = (CURLOPT_OKAY); if (__builtin_constant_p(_internal_opt)) { if (_internal_opt == CURLOPT_DEPRECATED) { curl_warn(); } } curl_easy_setopt(_internal_opt); })); ret; }) < 0) { return -1; } } while (0);
    if (
#pragma GCC diagnostic push
   
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
   
#pragma GCC diagnostic pop
   ({ int ret = (__extension__ ({ CURLoption _internal_opt = (CURLOPT_OKAY); if (__builtin_constant_p(_internal_opt)) { if (_internal_opt == CURLOPT_DEPRECATED) { curl_warn(); } } curl_easy_setopt(_internal_opt); })); ret; }) < 0) {
        return -1;
    }
    return 0;
}

Compilation will fail on every macro wrapping curl_easy_setopt. Take a look at the preprocessor output for both to see the reason why; In GCC < 12.1 the #pragma directives are placed in odd positions and depending on how the macro is structured we either get a deprecation warning on the unused deprecated CURLOPT, or the code gets completely mangled and we get the weird expected expression before '#pragma' error.

If you try this same code block with >=12.1 the #pragmas are correctly placed and compilation is fine.

I expected the following

libcurl macros need to be rewritten to handle this case for GCC < 12.1

curl/libcurl version

7.88.1

operating system

Proprietary platform, however this is a compilation issue so that shouldn't matter.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions