MINOR: compiler: add a new macro ALREADY_CHECKED()

This macro may be used to block constant propagation that lets the compiler
detect a possible NULL dereference on a variable resulting from an explicit
assignment in an impossible check. Sometimes a function is called which does
safety checks and returns NULL if safe conditions are not met. The place
where it's called cannot hit this condition and dereferencing the pointer
without first checking it will make the compiler emit a warning about a
"potential null pointer dereference" which is hard to work around. This
macro "washes" the pointer and prevents the compiler from emitting tests
branching to undefined instructions. It may only be used when the developer
is absolutely certain that the conditions are guaranteed and that the
pointer passed in argument cannot be NULL by design.

A typical use case is a top-level function doing this :

     if (frame->type == HEADERS)
        parse_frame(frame);

Then parse_frame() does this :

    void parse_frame(struct frame *frame)
    {
        const char *frame_hdr;

        frame_hdr = frame_hdr_start(frame);
        if (*frame_hdr == FRAME_HDR_BEGIN)
            process_frame(frame);
    }

and :

    const char *frame_hdr_start(const struct frame *frame)
    {
        if (frame->type == HEADERS)
            return frame->data;
        else
            return NULL;
    }

Above parse_frame() is only called for frame->type == HEADERS so it will
never get a NULL in return from frame_hdr_start(). Thus it's always safe
to dereference *frame_hdr since the check was already performed above.
It's then safe to address it this way instead of inventing dummy error
code paths that may create real bugs :

    void parse_frame(struct frame *frame)
    {
        const char *frame_hdr;

        frame_hdr = frame_hdr_start(frame);
        ALREADY_CHECKED(frame_hdr);
        if (*frame_hdr == FRAME_HDR_BEGIN)
            process_frame(frame);
    }
This commit is contained in:
Willy Tarreau 2018-12-08 15:20:43 +01:00
parent 50d660c545
commit 071d4b31ff
1 changed files with 14 additions and 0 deletions

View File

@ -94,6 +94,20 @@
#define my_unreachable() #define my_unreachable()
#endif #endif
/* This macro may be used to block constant propagation that lets the compiler
* detect a possible NULL dereference on a variable resulting from an explicit
* assignment in an impossible check. Sometimes a function is called which does
* safety checks and returns NULL if safe conditions are not met. The place
* where it's called cannot hit this condition and dereferencing the pointer
* without first checking it will make the compiler emit a warning about a
* "potential null pointer dereference" which is hard to work around. This
* macro "washes" the pointer and prevents the compiler from emitting tests
* branching to undefined instructions. It may only be used when the developer
* is absolutely certain that the conditions are guaranteed and that the
* pointer passed in argument cannot be NULL by design.
*/
#define ALREADY_CHECKED(p) do { asm("" : "=rm"(p) : "0"(p)); } while (0)
/* /*
* Gcc >= 3 provides the ability for the programme to give hints to the * Gcc >= 3 provides the ability for the programme to give hints to the
* compiler about what branch of an if is most likely to be taken. This * compiler about what branch of an if is most likely to be taken. This