Bug Summary

File:missing/string.h
Warning:line 64, column 12
Null pointer passed to 1st parameter expecting 'nonnull'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name lwan-mod-rewrite.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -fmath-errno -fno-rounding-math -mconstructor-aliases -fno-plt -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib/clang/12.0.1 -include /home/buildbot/lwan-worker/clang-analyze/build/lwan-build-config.h -D _FILE_OFFSET_BITS=64 -D _TIME_BITS=64 -I /home/buildbot/lwan-worker/clang-analyze/build/src/lib/missing -I /usr/include/luajit-2.0 -I /usr/include/valgrind -I /home/buildbot/lwan-worker/clang-analyze/build/src/lib -I /home/buildbot/lwan-worker/clang-analyze/build -internal-isystem /usr/local/include -internal-isystem /usr/lib/clang/12.0.1/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-unused-parameter -Wno-free-nonheap-object -std=gnu99 -fdebug-compilation-dir /home/buildbot/lwan-worker/clang-analyze/build/src/lib -ferror-limit 19 -stack-protector 2 -fgnuc-version=4.2.1 -analyzer-output=html -faddrsig -o /home/buildbot/lwan-worker/clang-analyze/CLANG/2021-09-28-035938-802865-1 -x c /home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-mod-rewrite.c

/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-mod-rewrite.c

1/*
2 * lwan - simple web server
3 * Copyright (c) 2015 Leandro A. F. Pereira <leandro@hardinfo.org>
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
18 * USA.
19 */
20
21#define _GNU_SOURCE
22#include <ctype.h>
23#include <limits.h>
24#include <stdlib.h>
25#include <string.h>
26#include <sys/stat.h>
27
28#include "lwan-private.h"
29
30#include "patterns.h"
31#include "lwan-array.h"
32#include "lwan-mod-rewrite.h"
33#include "lwan-strbuf.h"
34
35#ifdef HAVE_LUA
36#include <lauxlib.h>
37#include <lua.h>
38#include <lualib.h>
39
40#include "lwan-lua.h"
41#endif
42
43enum pattern_flag {
44 PATTERN_HANDLE_REWRITE = 1 << 0,
45 PATTERN_HANDLE_REDIRECT = 1 << 1,
46 PATTERN_HANDLE_MASK = PATTERN_HANDLE_REWRITE | PATTERN_HANDLE_REDIRECT,
47
48 PATTERN_EXPAND_LWAN = 1 << 2,
49 PATTERN_EXPAND_LUA = 1 << 3,
50 PATTERN_EXPAND_MASK = PATTERN_EXPAND_LWAN | PATTERN_EXPAND_LUA,
51
52 PATTERN_COND_COOKIE = 1 << 4,
53 PATTERN_COND_ENV_VAR = 1 << 5,
54 PATTERN_COND_STAT = 1 << 6,
55 PATTERN_COND_QUERY_VAR = 1 << 7,
56 PATTERN_COND_POST_VAR = 1 << 8,
57 PATTERN_COND_HEADER = 1 << 9,
58 PATTERN_COND_LUA = 1 << 10,
59 PATTERN_COND_METHOD = 1 << 11,
60 PATTERN_COND_ACCEPT_ENCODING = 1 << 12,
61 PATTERN_COND_PROXIED = 1 << 13,
62 PATTERN_COND_HTTP10 = 1 << 14,
63 PATTERN_COND_HAS_QUERY_STRING = 1 << 15,
64 PATTERN_COND_MASK = PATTERN_COND_COOKIE | PATTERN_COND_ENV_VAR |
65 PATTERN_COND_STAT | PATTERN_COND_QUERY_VAR |
66 PATTERN_COND_POST_VAR | PATTERN_COND_HEADER |
67 PATTERN_COND_LUA | PATTERN_COND_METHOD |
68 PATTERN_COND_ACCEPT_ENCODING |
69 PATTERN_COND_PROXIED | PATTERN_COND_HTTP10 |
70 PATTERN_COND_HAS_QUERY_STRING,
71
72 PATTERN_COND_STAT__HAS_IS_FILE = 1 << 16,
73 PATTERN_COND_STAT__HAS_IS_DIR = 1 << 17,
74 PATTERN_COND_STAT__IS_FILE = 1 << 18,
75 PATTERN_COND_STAT__IS_DIR = 1 << 19,
76
77 PATTERN_COND_STAT__FILE_CHECK =
78 PATTERN_COND_STAT__HAS_IS_FILE | PATTERN_COND_STAT__IS_FILE,
79 PATTERN_COND_STAT__DIR_CHECK =
80 PATTERN_COND_STAT__HAS_IS_DIR | PATTERN_COND_STAT__IS_DIR,
81};
82
83struct pattern {
84 char *pattern;
85 char *expand_pattern;
86 struct {
87 struct lwan_key_value cookie;
88 struct lwan_key_value env_var;
89 struct lwan_key_value query_var;
90 struct lwan_key_value post_var;
91 struct lwan_key_value header;
92 struct {
93 char *path;
94 } stat;
95 struct {
96 char *script;
97 } lua;
98 enum lwan_request_flags request_flags;
99 /* FIXME: Use pahole to find alignment holes? */
100 } condition;
101 enum pattern_flag flags;
102};
103
104DEFINE_ARRAY_TYPE(pattern_array, struct pattern)struct pattern_array { struct lwan_array base; }; __attribute__
((unused)) static inline struct pattern *pattern_array_append
( struct pattern_array *array) { return (struct pattern *)lwan_array_append_heap
(&array->base, sizeof(struct pattern)); } __attribute__
((unused)) static inline struct pattern_array *coro_pattern_array_new
(struct coro *coro) { return (struct pattern_array *)coro_lwan_array_new
(coro, 0); } __attribute__((unused)) static inline struct pattern
*pattern_array_get_array(struct pattern_array *array) { return
(struct pattern *)array->base.base; } __attribute__((unused
)) __attribute__((nonnull(1))) static inline void pattern_array_init
( struct pattern_array *array) { array->base = (struct lwan_array
){.base = ((void*)0), .elements = 0}; } __attribute__((unused
)) static inline int pattern_array_reset( struct pattern_array
*array) { return lwan_array_reset(&array->base, ((void
*)0)); } __attribute__((unused)) static inline struct pattern
*pattern_array_append0(struct pattern_array *array) { struct
pattern *element = pattern_array_append(array); if (element)
memset(element, 0, sizeof(*element)); return element; } __attribute__
((unused)) static inline void pattern_array_sort( struct pattern_array
*array, int (*cmp)(const void *a, const void *b)) { lwan_array_sort
(&array->base, sizeof(struct pattern), cmp); } __attribute__
((unused)) static inline size_t pattern_array_get_elem_index(
const struct pattern_array *array, struct pattern *elem) { (
(void) sizeof ((elem >= (struct pattern *)array->base.base
) ? 1 : 0), __extension__ ({ if (elem >= (struct pattern *
)array->base.base) ; else __assert_fail ("elem >= (struct pattern *)array->base.base"
, "/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-mod-rewrite.c"
, 104, __extension__ __PRETTY_FUNCTION__); })); ((void) sizeof
((elem < (struct pattern *)array->base.base + array->
base.elements) ? 1 : 0), __extension__ ({ if (elem < (struct
pattern *)array->base.base + array->base.elements) ; else
__assert_fail ("elem < (struct pattern *)array->base.base + array->base.elements"
, "/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-mod-rewrite.c"
, 104, __extension__ __PRETTY_FUNCTION__); })); return (size_t
)(elem - (struct pattern *)array->base.base); } __attribute__
((unused)) static inline struct pattern *pattern_array_get_elem
(const struct pattern_array *array, size_t index) { ((void) sizeof
((index <= array->base.elements) ? 1 : 0), __extension__
({ if (index <= array->base.elements) ; else __assert_fail
("index <= array->base.elements", "/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-mod-rewrite.c"
, 104, __extension__ __PRETTY_FUNCTION__); })); return &(
(struct pattern *)array->base.base)[index]; } __attribute__
((unused)) static inline size_t pattern_array_len( const struct
pattern_array *array) { return array->base.elements; }
105
106struct private_data {
107 struct pattern_array patterns;
108};
109
110static enum lwan_http_status module_redirect_to(struct lwan_request *request,
111 const char *url)
112{
113 const struct lwan_key_value headers[] = {
114 {"Location", coro_strdup(request->conn->coro, url)},
115 {},
116 };
117
118 request->response.headers =
119 coro_memdup(request->conn->coro, headers, sizeof(headers));
120
121 if (LIKELY(headers[0].value && request->response.headers)__builtin_expect((!!(headers[0].value && request->
response.headers)), (1))
)
122 return HTTP_MOVED_PERMANENTLY;
123
124 return HTTP_INTERNAL_ERROR;
125}
126
127static enum lwan_http_status module_rewrite_as(struct lwan_request *request,
128 const char *url)
129{
130 request->url.value = coro_strdup(request->conn->coro, url);
131
132 if (UNLIKELY(!request->url.value)__builtin_expect(((!request->url.value)), (0)))
133 return HTTP_INTERNAL_ERROR;
134
135 request->url.len = strlen(request->url.value);
136 request->original_url = request->url;
137 request->flags |= RESPONSE_URL_REWRITTEN;
138
139 return HTTP_OK;
140}
141
142#define MAX_INT_DIGITS(3 * sizeof(int)) (3 * sizeof(int))
143
144static __attribute__((noinline)) int parse_int_len(const char *s, size_t len,
145 int default_value)
146{
147 if (UNLIKELY(len > MAX_INT_DIGITS)__builtin_expect(((len > (3 * sizeof(int)))), (0)))
148 return default_value;
149
150 return parse_int(strndupa(s, len)(__extension__ ({ const char *__old = (s); size_t __len = strnlen
(__old, (len)); char *__new = (char *) __builtin_alloca (__len
+ 1); __new[__len] = '\0'; (char *) memcpy (__new, __old, __len
); }))
, default_value);
151}
152
153static const char *expand_string(const char *expand_pattern,
154 const char *orig,
155 char buffer[static PATH_MAX4096],
156 const struct str_find *sf,
157 int captures)
158{
159 struct lwan_strbuf strbuf;
160 const char *ptr;
161
162 ptr = strchr(expand_pattern, '%');
163 if (!ptr)
164 return expand_pattern;
165
166 if (!lwan_strbuf_init_with_fixed_buffer(&strbuf, buffer, PATH_MAX4096))
167 return NULL((void*)0);
168
169 do {
170 size_t index_len = strspn(ptr + 1, "0123456789");
171
172 if (ptr > expand_pattern) {
173 const size_t len = (size_t)(ptr - expand_pattern);
174
175 if (UNLIKELY(!lwan_strbuf_append_str(&strbuf, expand_pattern, len))__builtin_expect(((!lwan_strbuf_append_str(&strbuf, expand_pattern
, len))), (0))
)
176 return NULL((void*)0);
177
178 expand_pattern += len;
179 }
180
181 if (LIKELY(index_len > 0)__builtin_expect((!!(index_len > 0)), (1))) {
182 const int index = parse_int_len(ptr + 1, index_len, -1);
183
184 if (UNLIKELY(index < 0 || index > captures)__builtin_expect(((index < 0 || index > captures)), (0)
)
)
185 return NULL((void*)0);
186
187 if (UNLIKELY(!lwan_strbuf_append_str(__builtin_expect(((!lwan_strbuf_append_str( &strbuf, orig
+ sf[index].sm_so, (size_t)(sf[index].sm_eo - sf[index].sm_so
)))), (0))
188 &strbuf, orig + sf[index].sm_so,__builtin_expect(((!lwan_strbuf_append_str( &strbuf, orig
+ sf[index].sm_so, (size_t)(sf[index].sm_eo - sf[index].sm_so
)))), (0))
189 (size_t)(sf[index].sm_eo - sf[index].sm_so)))__builtin_expect(((!lwan_strbuf_append_str( &strbuf, orig
+ sf[index].sm_so, (size_t)(sf[index].sm_eo - sf[index].sm_so
)))), (0))
)
190 return NULL((void*)0);
191
192 expand_pattern += index_len;
193 } else if (UNLIKELY(!lwan_strbuf_append_char(&strbuf, '%'))__builtin_expect(((!lwan_strbuf_append_char(&strbuf, '%')
)), (0))
) {
194 return NULL((void*)0);
195 }
196
197 expand_pattern++;
198 } while ((ptr = strchr(expand_pattern, '%')));
199
200 const size_t remaining_len = strlen(expand_pattern);
201 if (remaining_len &&
202 !lwan_strbuf_append_str(&strbuf, expand_pattern, remaining_len))
203 return NULL((void*)0);
204
205 if (UNLIKELY(!lwan_strbuf_get_length(&strbuf))__builtin_expect(((!lwan_strbuf_get_length(&strbuf))), (0
))
)
206 return NULL((void*)0);
207
208 return lwan_strbuf_get_buffer(&