1  /* Reduced from haproxy-2.7.1: src/tcpcheck.c.  */
       2  
       3  /* { dg-additional-options "-Wno-analyzer-too-complex" } */
       4  
       5  typedef __SIZE_TYPE__ size_t;
       6  #define NULL ((void *)0)
       7  
       8  extern void *calloc(size_t __nmemb, size_t __size)
       9      __attribute__((__nothrow__, __leaf__)) __attribute__((__malloc__))
      10      __attribute__((__alloc_size__(1, 2)));
      11  extern char *strdup(const char *__s) __attribute__((__nothrow__, __leaf__))
      12  __attribute__((__malloc__)) __attribute__((__nonnull__(1)));
      13  extern char *strstr(const char *__haystack, const char *__needle)
      14      __attribute__((__nothrow__, __leaf__)) __attribute__((__pure__))
      15      __attribute__((__nonnull__(1, 2)));
      16  extern size_t strlen(const char *__s) __attribute__((__nothrow__, __leaf__))
      17  __attribute__((__pure__)) __attribute__((__nonnull__(1)));
      18  struct list {
      19    struct list *n;
      20    struct list *p;
      21  };
      22  struct buffer {
      23    size_t size;
      24    char *area;
      25    size_t data;
      26    size_t head;
      27  };
      28  struct proxy;
      29  struct ist {
      30    char *ptr;
      31    size_t len;
      32  };
      33  static inline int isttest(const struct ist ist) { return ist.ptr != NULL; }
      34  
      35  enum http_meth_t {
      36    HTTP_METH_OPTIONS,
      37    /* [...snip...] */
      38  } __attribute__((packed));
      39  
      40  struct http_meth {
      41    enum http_meth_t meth;
      42    struct buffer str;
      43  };
      44  enum tcpcheck_send_type {
      45    /* [...snip...] */
      46    TCPCHK_SEND_HTTP,
      47  };
      48  enum tcpcheck_rule_type {
      49    TCPCHK_ACT_SEND = 0,
      50    /* [...snip...] */
      51  };
      52  struct tcpcheck_http_hdr {
      53    struct ist name;
      54    struct list value;
      55    struct list list;
      56  };
      57  struct tcpcheck_send {
      58    enum tcpcheck_send_type type;
      59    union {
      60      /* [...snip...] */
      61      struct {
      62        unsigned int flags;
      63        struct http_meth meth;
      64        union {
      65          struct ist uri;
      66          /* [...snip...] */
      67        };
      68        struct ist vsn;
      69        struct list hdrs;
      70        /* [...snip...] */
      71      } http;
      72    };
      73  };
      74  struct tcpcheck_rule {
      75    /* [...snip...] */
      76    enum tcpcheck_rule_type action;
      77    /* [...snip...] */
      78    union {
      79      /* [...snip...] */
      80      struct tcpcheck_send send;
      81      /* [...snip...] */
      82    };
      83  };
      84  enum http_meth_t find_http_meth(const char *str, const int len);
      85  void free_tcpcheck(struct tcpcheck_rule *rule, int in_pool);
      86  void free_tcpcheck_http_hdr(struct tcpcheck_http_hdr *hdr);
      87  
      88  #define ist(str) ({                                                    \
      89  	char *__x = (void *)(str);                                     \
      90  	(struct ist){                                                  \
      91  		.ptr = __x,                                            \
      92  		.len = __builtin_constant_p(str) ?                     \
      93  			((void *)str == (void *)0) ? 0 :               \
      94  			__builtin_strlen(__x) :                        \
      95  			({                                             \
      96  				size_t __l = 0;                        \
      97  				if (__x) for (__l--; __x[++__l]; ) ;   \
      98  				__l;                                   \
      99  			})                                             \
     100  	};                                                             \
     101  })
     102  
     103  struct tcpcheck_rule *proxy_parse_httpchk_req(char **args, int cur_arg,
     104                                                struct proxy *px, char **errmsg) {
     105    struct tcpcheck_rule *chk = NULL;
     106    struct tcpcheck_http_hdr *hdr = NULL;
     107    char *meth = NULL, *uri = NULL, *vsn = NULL;
     108    char *hdrs, *body;
     109  
     110    hdrs = (*args[cur_arg + 2] ? strstr(args[cur_arg + 2], "\r\n") : NULL);
     111    body = (*args[cur_arg + 2] ? strstr(args[cur_arg + 2], "\r\n\r\n") : NULL);
     112    if (hdrs || body) {
     113      /* [...snip...] */
     114      goto error;
     115    }
     116  
     117    chk = calloc(1, sizeof(*chk));
     118    if (!chk) {
     119      /* [...snip...] */
     120      goto error;
     121    }
     122    chk->action = TCPCHK_ACT_SEND;
     123    chk->send.type = TCPCHK_SEND_HTTP;
     124    chk->send.http.flags |= 0x0004;
     125    chk->send.http.meth.meth = HTTP_METH_OPTIONS;
     126    ((&chk->send.http.hdrs)->n = (&chk->send.http.hdrs)->p =
     127         (&chk->send.http.hdrs));
     128  
     129    if (*args[cur_arg]) {
     130      if (!*args[cur_arg + 1])
     131        uri = args[cur_arg];
     132      else
     133        meth = args[cur_arg];
     134    }
     135    if (*args[cur_arg + 1])
     136      uri = args[cur_arg + 1];
     137    if (*args[cur_arg + 2])
     138      vsn = args[cur_arg + 2];
     139  
     140    if (meth) { /* { dg-bogus "check of 'meth' for NULL after already dereferencing it" } */
     141      chk->send.http.meth.meth = find_http_meth(meth, strlen(meth));
     142      chk->send.http.meth.str.area = strdup(meth);
     143      chk->send.http.meth.str.data = strlen(meth);
     144      if (!chk->send.http.meth.str.area) {
     145        /* [...snip...] */
     146        goto error;
     147      }
     148    }
     149    if (uri) {
     150      chk->send.http.uri = ist(strdup(uri));
     151      if (!isttest(chk->send.http.uri)) {
     152        /* [...snip...] */
     153        goto error;
     154      }
     155    }
     156    if (vsn) { /* { dg-bogus "check of 'vsn' for NULL after already dereferencing it" } */
     157      chk->send.http.vsn = ist(strdup(vsn));
     158      if (!isttest(chk->send.http.vsn)) {
     159        /* [...snip...] */
     160        goto error;
     161      }
     162    }
     163    return chk;
     164  
     165  error:
     166    free_tcpcheck_http_hdr(hdr);
     167    free_tcpcheck(chk, 0);
     168    return NULL;
     169  }