Summary > Report 01724d

Bug Summary

File:home/avsej/code/libcouchbase/tools/cbc-proxy.cc
Warning:line 298, column 62
Use of memory after it is freed
Report Bug

Annotated Source Code

1/*
2 * Copyright 2017 Couchbase, Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LCB_NO_DEPR_CXX_CTORS
18
19#include "common/my_inttypes.h"
20#include "config.h"
21#include <sys/types.h>
22#include <libcouchbase/couchbase.h>
23#include <libcouchbase/vbucket.h>
24#include <libcouchbase/api3.h>
25#include <libcouchbase/pktfwd.h>
26#include <memcached/protocol_binary.h>
27#include <iostream>
28#include <iomanip>
29#include <cstdio>
30#include <cerrno>
31#include <sstream>
32#include <signal.h>
33#include "common/options.h"
34#include "common/histogram.h"
35
36#include "internal.h"
37
38#include <event2/event.h>
39#include <event2/listener.h>
40#include <event2/bufferevent.h>
41#include <event2/buffer.h>
42
43using namespace cbc;
44using namespace cliopts;
45
46static void die(const char *msg)
47{
48 fprintf(stderrstderr, "%s\n", msg);
49 exit(EXIT_FAILURE1);
50}
51
52static void good_or_die(lcb_error_t rc, const char *msg = "")
53{
54 if (rc != LCB_SUCCESS) {
55 fprintf(stderrstderr, "%s\n0x%02x: %s\n", msg, rc, lcb_strerror(NULL__null, rc));
56 exit(EXIT_FAILURE1);
57 }
58}
59
60static lcb_t instance = NULL__null;
61static struct event_base *evbase = NULL__null;
62static Histogram hg;
63
64#define LOGARGS(lvl)(instance)->settings, "proxy", LCB_LOG_lvl, "/home/avsej/code/libcouchbase/tools/cbc-proxy.cc"
, 64
(instance)->settings, "proxy", LCB_LOG_##lvl, __FILE__"/home/avsej/code/libcouchbase/tools/cbc-proxy.cc", __LINE__64
65#define CL_LOGFMT"<%s:%s> (cl=%p,fd=%d) " "<%s:%s> (cl=%p,fd=%d) "
66#define CL_LOGID(cl)cl->host, cl->port, (void *)cl, cl->fd cl->host, cl->port, (void *)cl, cl->fd
67
68class Configuration
69{
70 public:
71 Configuration() : o_trace("trace"), o_port("port")
72 {
73 o_trace.abbrev('t').description("Show packet trace on INFO log level");
74 o_port.abbrev('p').description("Port for proxy").setDefault(11211);
75 }
76
77 ~Configuration()
78 {
79 }
80
81 void addToParser(Parser &parser)
82 {
83 m_params.addToParser(parser);
84 parser.addOption(o_trace);
85 parser.addOption(o_port);
86 }
87
88 void processOptions()
89 {
90 }
91
92 void fillCropts(lcb_create_st &opts)
93 {
94 m_params.fillCropts(opts);
95 }
96 lcb_error_t doCtls()
97 {
98 return m_params.doCtls(instance);
99 }
100 bool useTimings()
101 {
102 return m_params.useTimings();
103 }
104 bool shouldDump()
105 {
106 return m_params.shouldDump();
107 }
108
109 bool isTrace()
110 {
111 return o_trace.result();
112 }
113
114 unsigned port()
115 {
116 return o_port.result();
117 }
118
119 private:
120 ConnParams m_params;
121 BoolOption o_trace;
122 UIntOption o_port;
123};
124
125static Configuration config;
126
127static struct evconnlistener *listener = NULL__null;
128
129static void cleanup()
130{
131 if (instance) {
132 if (config.shouldDump()) {
133 lcb_dump(instance, stderrstderr, LCB_DUMP_ALL);
134 }
135 if (config.useTimings()) {
136 hg.write();
137 }
138 if (instance) {
139 lcb_destroy(instance);
140 }
141 }
142 if (listener) {
143 evconnlistener_free(listener);
144 }
145 if (evbase) {
146 event_base_free(evbase);
147 }
148}
149
150struct client {
151 int fd;
152 struct bufferevent *bev;
153 char host[NI_MAXHOST1025 + 1];
154 char port[NI_MAXSERV32 + 1];
155};
156
157static void dump_bytes(const struct client *cl, const char *msg, void *ptr, size_t len)
158{
159 if (!config.isTrace()) {
160 return;
161 }
162
163 int width = 16;
164 const unsigned char *buf = (const unsigned char *)ptr;
165 size_t full_rows = len / width;
166 size_t remainder = len % width;
167 std::stringstream ss;
168
169 ss << msg << ", " << len << " bytes\n"
170 " +-------------------------------------------------+\n"
171 " | 0 1 2 3 4 5 6 7 8 9 a b c d e f |\n"
172 " +--------+-------------------------------------------------+----------------+";
173
174 unsigned int row = 0;
175 while (row < full_rows) {
176 int row_start_index = row * width;
177 // prefix
178 ss << "\n |" << std::setw(8) << std::setfill('0') << std::hex << row_start_index << "|";
179 int row_end_index = row_start_index + width;
180 // hex
181 int i = row_start_index;
182 while (i < row_end_index) {
183 ss << " " << std::setw(2) << std::setfill('0') << std::hex << (unsigned int)buf[i++];
184 }
185 ss << " |";
186 // ascii
187 i = row_start_index;
188 while (i < row_end_index) {
189 char b = buf[i++];
190 if ((b <= 0x1f) || (b >= 0x7f)) {
191 ss << '.';
192 } else {
193 ss << b;
194 }
195 }
196 ss << "|";
197 row++;
198 }
199 if (remainder != 0) {
200 int row_start_index = full_rows * width;
201 // prefix
202 ss << "\n |" << std::setw(8) << std::setfill('0') << std::hex << row_start_index << "|";
203 int row_end_index = row_start_index + remainder;
204 // hex
205 int i = row_start_index;
206 while (i < row_end_index) {
207 ss << " " << std::setw(2) << std::setfill('0') << std::hex << (unsigned int)buf[i++];
208 }
209 i = width - remainder;
210 while (i > 0) {
211 ss << " ";
212 i--;
213 }
214 ss << " |";
215 // ascii
216 i = row_start_index;
217 while (i < row_end_index) {
218 char b = buf[i++];
219 if ((b <= 0x1f) || (b >= 0x7f)) {
220 ss << '.';
221 } else {
222 ss << b;
223 }
224 }
225 i = width - remainder;
226 while (i > 0) {
227 ss << " ";
228 i--;
229 }
230 ss << "|";
231 }
232 ss << "\n +--------+-------------------------------------------------+----------------+";
233 lcb_log(LOGARGS(INFO)(instance)->settings, "proxy", LCB_LOG_INFO, "/home/avsej/code/libcouchbase/tools/cbc-proxy.cc"
, 233
, CL_LOGFMT"<%s:%s> (cl=%p,fd=%d) " "%s", CL_LOGID(cl)cl->host, cl->port, (void *)cl, cl->fd, ss.str().c_str());
234}
235
236static void pktfwd_callback(lcb_t, const void *cookie, lcb_error_t err, lcb_PKTFWDRESP *resp)
237{
238 good_or_die(err, "Failed to forward a packet");
239
240 struct client *cl = (struct client *)cookie;
241 struct evbuffer *output = bufferevent_get_output(cl->bev);
242 for (unsigned ii = 0; ii < resp->nitems; ii++) {
243 dump_bytes(cl, "response", resp->iovs[ii].iov_base, resp->iovs[ii].iov_len);
244 evbuffer_expand(output, resp->iovs[ii].iov_len);
245 evbuffer_add(output, resp->iovs[ii].iov_base, resp->iovs[ii].iov_len);
246 }
247}
248
249static void conn_readcb(struct bufferevent *bev, void *cookie)
250{
251 struct client *cl = (struct client *)cookie;
252 struct evbuffer *input;
253 size_t len;
254
255 input = bufferevent_get_input(bev);
256 len = evbuffer_get_length(input);
257 if (len < 24) {
258 lcb_log(LOGARGS(DEBUG)(instance)->settings, "proxy", LCB_LOG_DEBUG, "/home/avsej/code/libcouchbase/tools/cbc-proxy.cc"
, 258
, CL_LOGFMT"<%s:%s> (cl=%p,fd=%d) " "not enough data for header", CL_LOGID(cl)cl->host, cl->port, (void *)cl, cl->fd);
259 return;
260 }
261
262 protocol_binary_request_header header;
263 evbuffer_copyout(input, &header, sizeof(header));
264 lcb_U32 bodylen = ntohl(header.request.bodylen);
265
266 size_t pktlen = sizeof(header) + bodylen;
267 len = evbuffer_get_length(input);
268 if (len < pktlen) {
269 lcb_log(LOGARGS(DEBUG)(instance)->settings, "proxy", LCB_LOG_DEBUG, "/home/avsej/code/libcouchbase/tools/cbc-proxy.cc"
, 269
, CL_LOGFMT"<%s:%s> (cl=%p,fd=%d) " "not enough data for packet", CL_LOGID(cl)cl->host, cl->port, (void *)cl, cl->fd);
270 return;
271 }
272 void *pkt = malloc(pktlen);
273 evbuffer_remove(input, pkt, pktlen);
274
275 lcb_sched_enter(instance);
276 lcb_CMDPKTFWD cmd = {0};
277 cmd.vb.vtype = LCB_KV_COPY;
278 cmd.vb.u_buf.contig.bytes = pkt;
279 cmd.vb.u_buf.contig.nbytes = pktlen;
280 dump_bytes(cl, "request", pkt, pktlen);
281 good_or_die(lcb_pktfwd3(instance, cl, &cmd), "Failed to forward packet");
282 lcb_sched_leave(instance);
283}
284
285static void conn_eventcb(struct bufferevent *bev, short events, void *cookie)
286{
287 struct client *cl = (struct client *)cookie;
288
289 if (events & BEV_EVENT_EOF0x10) {
1
Assuming the condition is true
2
Taking true branch
290 lcb_log(LOGARGS(INFO)(instance)->settings, "proxy", LCB_LOG_INFO, "/home/avsej/code/libcouchbase/tools/cbc-proxy.cc"
, 290
, CL_LOGFMT"<%s:%s> (cl=%p,fd=%d) " "connection closed", CL_LOGID(cl)cl->host, cl->port, (void *)cl, cl->fd);
291 bufferevent_free(bev);
292 delete cl;
3
Memory is released
293 } else if (events & BEV_EVENT_ERROR0x20) {
294 lcb_log(LOGARGS(ERROR)(instance)->settings, "proxy", LCB_LOG_ERROR, "/home/avsej/code/libcouchbase/tools/cbc-proxy.cc"
, 294
, CL_LOGFMT"<%s:%s> (cl=%p,fd=%d) " "got an error on the connection: %s\n", CL_LOGID(cl)cl->host, cl->port, (void *)cl, cl->fd, strerror(errno(*__errno_location ())));
295 bufferevent_free(bev);
296 delete cl;
297 }
298 lcb_log(LOGARGS(DEBUG)(instance)->settings, "proxy", LCB_LOG_DEBUG, "/home/avsej/code/libcouchbase/tools/cbc-proxy.cc"
, 298
, CL_LOGFMT"<%s:%s> (cl=%p,fd=%d) " "ignore event 0x%02x", CL_LOGID(cl)cl->host, cl->port, (void *)cl, cl->fd, events);
4
Within the expansion of the macro 'CL_LOGID':
a
Use of memory after it is freed
299}
300
301static void listener_cb(struct evconnlistener *, evutil_socket_tint fd, struct sockaddr *addr, int naddr, void *)
302{
303 struct bufferevent *bev;
304 bev = bufferevent_socket_new(evbase, fd, BEV_OPT_CLOSE_ON_FREE);
305
306 if (!bev) {
307 die("Error constructing bufferevent");
308 }
309
310 struct client *cl = new client();
311 cl->fd = fd;
312 cl->bev = bev;
313 getnameinfo(addr, naddr, cl->host, sizeof(cl->host), cl->port, sizeof(cl->port), NI_NUMERICHOST1 | NI_NUMERICSERV2);
314 bufferevent_setcb(bev, conn_readcb, NULL__null, conn_eventcb, cl);
315 bufferevent_enable(bev, EV_READ0x02 | EV_WRITE0x04);
316 lcb_log(LOGARGS(INFO)(instance)->settings, "proxy", LCB_LOG_INFO, "/home/avsej/code/libcouchbase/tools/cbc-proxy.cc"
, 316
, CL_LOGFMT"<%s:%s> (cl=%p,fd=%d) " "new client connection", CL_LOGID(cl)cl->host, cl->port, (void *)cl, cl->fd);
317}
318
319static void setup_listener()
320{
321 struct sockaddr_in sin;
322
323 memset(&sin, 0, sizeof(sin));
324 sin.sin_family = AF_INET2;
325 sin.sin_port = htons(config.port());
326
327 listener = evconnlistener_new_bind(evbase, listener_cb, NULL__null, LEV_OPT_REUSEABLE(1u<<3) | LEV_OPT_CLOSE_ON_FREE(1u<<1), -1,
328 (struct sockaddr *)&sin, sizeof(sin));
329 if (!listener) {
330 die("Failed to create proxy listener");
331 }
332 lcb_log(LOGARGS(INFO)(instance)->settings, "proxy", LCB_LOG_INFO, "/home/avsej/code/libcouchbase/tools/cbc-proxy.cc"
, 332
, "Listening incoming proxy connections on port %d", config.port());
333}
334
335static void bootstrap_callback(lcb_t, lcb_error_t err)
336{
337 good_or_die(err, "Failed to bootstrap");
338 lcb_log(LOGARGS(INFO)(instance)->settings, "proxy", LCB_LOG_INFO, "/home/avsej/code/libcouchbase/tools/cbc-proxy.cc"
, 338
, "connected to Couchbase Server");
339 setup_listener();
340}
341
342static int terminating = 0;
343static void sigint_handler(int)
344{
345 lcb_log(LOGARGS(INFO)(instance)->settings, "proxy", LCB_LOG_INFO, "/home/avsej/code/libcouchbase/tools/cbc-proxy.cc"
, 345
, "terminating the server");
346 if (!terminating) {
347 event_base_loopbreak(evbase);
348 terminating = 1;
349 }
350}
351
352static void real_main(int argc, char **argv)
353{
354 Parser parser;
355
356 config.addToParser(parser);
357 parser.parse(argc, argv);
358 config.processOptions();
359
360 lcb_create_st cropts;
361 memset(&cropts, 0, sizeof cropts);
362 config.fillCropts(cropts);
363
364 /* bind to external libevent loop */
365 evbase = event_base_new();
366 struct lcb_create_io_ops_st ciops;
367 memset(&ciops, 0, sizeof(ciops));
368 ciops.v.v0.type = LCB_IO_OPS_LIBEVENT;
369 ciops.v.v0.cookie = evbase;
370 good_or_die(lcb_create_io_ops(&cropts.v.v3.io, &ciops), "Failed to create and IO ops strucutre for libevent");
371
372 good_or_die(lcb_create(&instance, &cropts), "Failed to create connection");
373 config.doCtls();
374 lcb_set_bootstrap_callback(instance, bootstrap_callback);
375 lcb_set_pktfwd_callback(instance, pktfwd_callback);
376
377 good_or_die(lcb_connect(instance), "Failed to connect to cluster");
378 if (config.useTimings()) {
379 hg.install(instance, stdoutstdout);
380 }
381 std::atexit(cleanup);
382
383 /* setup CTRL-C handler */
384 struct sigaction action;
385 sigemptyset(&action.sa_mask);
386 action.sa_handler__sigaction_handler.sa_handler = sigint_handler;
387 action.sa_flags = 0;
388 sigaction(SIGINT2, &action, NULL__null);
389
390 event_base_dispatch(evbase);
391}
392
393int main(int argc, char **argv)
394{
395 try {
396 real_main(argc, argv);
397 return 0;
398 } catch (std::exception &exc) {
399 std::cerr << exc.what() << std::endl;
400 exit(EXIT_FAILURE1);
401 }
402}