From: Vladimir Davydov <vdavydov.dev@gmail.com> To: Serge Petrenko <sergepetrenko@tarantool.org> Cc: tarantool-patches@freelists.org Subject: Re: [tarantool-patches] [PATCH] xrow: print corrupted rows on decoding error. Date: Wed, 27 Mar 2019 12:18:57 +0300 [thread overview] Message-ID: <20190327091857.tk5yxwhhgy2eloia@esperanza> (raw) In-Reply-To: <8222472E-3EB1-4B68-8AA3-F5677EB5F001@tarantool.org> On Tue, Mar 19, 2019 at 03:19:31PM +0300, Serge Petrenko wrote: > Hi! > Thankyou for review! > The fixes are on the branch, and an incremental diff is below. > > > 18 марта 2019 г., в 20:58, Vladimir Davydov <vdavydov.dev@gmail.com> написал(а): > > > > On Fri, Mar 15, 2019 at 07:02:38PM +0300, Serge Petrenko wrote: > >> Add row hex printing to log on verbose level. This would be useful > >> during investigation of errors related to invalid msgpack packet > >> arrival. > >> > >> Related to #4040 > >> --- > >> https://github.com/tarantool/tarantool/tree/sp/xrow-decode-verbose-err > >> > >> > >> src/box/xrow.c | 27 +++++++++++++++++++++++++++ > >> 1 file changed, 27 insertions(+) > >> > >> diff --git a/src/box/xrow.c b/src/box/xrow.c > >> index bddae1d5b..8a5254902 100644 > >> --- a/src/box/xrow.c > >> +++ b/src/box/xrow.c > >> @@ -88,14 +88,29 @@ mp_decode_vclock(const char **data, struct vclock *vclock) > >> return 0; > >> } > >> > >> +static inline void > >> +say_dump_row_hex(const char *start, const char *end) > >> +{ > >> + char *buf = (char *)malloc(3 * (end - start) + 1); > > > > Theoretically, malloc() may fail. You'd better check it and print > > a warning in this case. Anyway, do we really need to use malloc() > > here at all? Won't tt_static_buf be enough for typical cases. > > Done, please see the incremental diff below. There are too many changes for an incremental diff. It's time for v2. > I still use malloc for sizes greater than TT_STATIC_BUF_LEN, > but check for an allocation error. No, please don't. I don't want branching here - it complicates the code without yielding any benefits. I just suggested to use tt_static_buf *instead of* malloc. If you think it's inadequate, then please use malloc() as before. > > > > >> + char *pos = buf; > >> + for (const char *cur = start; cur < end; ++cur) { > >> + pos += sprintf(pos, "%02hhX ", *cur); > >> + } > >> + *pos = 0; > >> + say_verbose("Corrupted row is: %s", buf); > > > > say_verbose() will turn into no-op, but you allocate a buffer and format > > the message anyway. Please fix that by using say_log_level_is_enabled() > > before doing anything. > > Fixed. > > > >> + free(buf); > >> +} > >> + > >> int > >> xrow_header_decode(struct xrow_header *header, const char **pos, > >> const char *end, bool end_is_exact) > >> { > >> memset(header, 0, sizeof(struct xrow_header)); > >> const char *tmp = *pos; > >> + const char * const start = *pos; > >> if (mp_check(&tmp, end) != 0) { > >> error: > >> + say_dump_row_hex(start, end); > >> diag_set(ClientError, ER_INVALID_MSGPACK, "packet header"); > >> return -1; > >> } > >> @@ -163,6 +178,7 @@ error: > >> if (*pos < end && header->type != IPROTO_NOP) { > >> const char *body = *pos; > >> if (mp_check(pos, end)) { > >> + say_dump_row_hex(start, end); > >> diag_set(ClientError, ER_INVALID_MSGPACK, "packet body"); > >> return -1; > >> } > >> @@ -171,6 +187,7 @@ error: > >> header->body[0].iov_len = *pos - body; > >> } > >> if (end_is_exact && *pos < end) { > >> + say_dump_row_hex(start,end); > >> diag_set(ClientError, ER_INVALID_MSGPACK, "packet body"); > > > > It would be better to add a helper function that would set diag and > > print a corrupted row so that we don't miss it in case we add another > > point of failure. Dunno, may be it's even worth adding a new exception > > class with logging built in. > > Done, please, see below. > I don’t like the idea with a new exception class. > If we introduce it, we’ll have to store the whole > corrupted row, which can be quite big, until logging happens. Okay. > > diff --git a/src/box/xrow.c b/src/box/xrow.c > index 3854874cc..000647111 100644 > --- a/src/box/xrow.c > +++ b/src/box/xrow.c > @@ -88,17 +88,44 @@ mp_decode_vclock(const char **data, struct vclock *vclock) > return 0; > } > > +/** > + * Set diagnostics with an error and log the corrupted row > + * which caused the error. > + * @param what - exception to set. > + * @param desc_str - error description string. > + */ > static inline void > -say_dump_row_hex(const char *start, const char *end) > +xrow_on_decode_err(const char *start, const char *end, uint32_t what, > + const char *desc_str) This should be a macro (perhaps a macro + a helper function), otherwise the line number where an error occurred will be lost. > { > - char *buf = (char *)malloc(3 * (end - start) + 1); > + diag_set(ClientError, what, desc_str); > + > + if (!say_log_level_is_enabled(S_VERBOSE)) > + return; > + > + size_t len = 3 * (end - start + 1); > + char *buf; > + > + if (len <= TT_STATIC_BUF_LEN) { > + buf = tt_static_buf(); > + } else { > + buf = (char *)malloc(len); > + if (!buf) { > + say_verbose("Got a corrupted row during decoding. "\ > + "Not enough memory to dump row contents."); > + return; > + } > + } > + > char *pos = buf; > for (const char *cur = start; cur < end; ++cur) { > pos += sprintf(pos, "%02hhX ", *cur); > } Please use snprintf. I'm not quite familiar with the %02hhX specifier. What does the output look like? Could you give an example in the commit message? BTW, it'd be really nice to have a test covering this code - should be pretty easy to add. Also, is the output format consistent with some unix tool (hexdump maybe)? > *pos = 0; > say_verbose("Corrupted row is: %s", buf); > - free(buf); > + > + if (len > TT_STATIC_BUF_LEN) > + free(buf); > } > > int > @@ -110,8 +137,7 @@ xrow_header_decode(struct xrow_header *header, const char **pos, > const char * const start = *pos; > if (mp_check(&tmp, end) != 0) { > error: > - say_dump_row_hex(start, end); > - diag_set(ClientError, ER_INVALID_MSGPACK, "packet header"); > + xrow_on_decode_err(start, end, ER_INVALID_MSGPACK, "packet header"); > return -1; > } > > @@ -178,8 +204,7 @@ error: > if (*pos < end && header->type != IPROTO_NOP) { > const char *body = *pos; > if (mp_check(pos, end)) { > - say_dump_row_hex(start, end); > - diag_set(ClientError, ER_INVALID_MSGPACK, "packet body"); > + xrow_on_decode_err(start, end, ER_INVALID_MSGPACK, "packet body"); You skipped quite a few places where a decoding error might occur, e.g. xrow_decode_sql => ER_MISSING_REQUEST_FIELD doesn't have extra logging while xrow_decode_dml => ER_MISSING_REQUEST_FIELD does. I'd like to see some pattern here. Perhaps, logging every error doesn't make much sense, especially if you primarily target at corrupted input. Let's discuss.
prev parent reply other threads:[~2019-03-27 9:18 UTC|newest] Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top 2019-03-15 16:02 Serge Petrenko 2019-03-18 17:58 ` Vladimir Davydov 2019-03-19 12:19 ` [tarantool-patches] " Serge Petrenko 2019-03-27 9:18 ` Vladimir Davydov [this message]
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=20190327091857.tk5yxwhhgy2eloia@esperanza \ --to=vdavydov.dev@gmail.com \ --cc=sergepetrenko@tarantool.org \ --cc=tarantool-patches@freelists.org \ --subject='Re: [tarantool-patches] [PATCH] xrow: print corrupted rows on decoding error.' \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: link
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox