Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package memcached for openSUSE:Factory checked in at 2026-08-04 21:29:57 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/memcached (Old) and /work/SRC/openSUSE:Factory/.memcached.new.16738 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "memcached" Tue Aug 4 21:29:57 2026 rev:76 rq:1369291 version:1.6.45 Changes: -------- --- /work/SRC/openSUSE:Factory/memcached/memcached.changes 2026-07-09 22:18:11.195691713 +0200 +++ /work/SRC/openSUSE:Factory/.memcached.new.16738/memcached.changes 2026-08-04 21:30:06.215111555 +0200 @@ -1,0 +2,34 @@ +Mon Aug 3 13:22:24 UTC 2026 - Petr Gajdos <[email protected]> + +- update to 1.6.45: + * proxy: extra warning for user config error + * proto: convert more strto calls + * proto: meta preparse F flag fix + * proxy: fix res:line() returning wrong response + * proxy: fix overread of spaces for large gets + * ascii: safely convert flag args to numerics + * ascii: fix unlocked refcount-- on error path + * proxy: key filter null byte written to wrong place + * proxy: fix detail len clamp in request logging + * proxy: enforce minimum rate limit + * ascii: fix refcount leak on ms parse error + * proxy: reserve enough log space for proxy BE_EVENT + * network: fix segfault on OOM during net read + * proxy: fix missing default handler in resnull + * stats: cap stats prefix count at 2^16 + * binprot: GETK against extstore internal miss can hang worker + * proxy: fix memory leak after failed request render + * proxy: fix underflow in key hash filters + * logger: closed worker fix again + * ascii: fix crash with invalid automove windows + * proxy: fix footgun when excessive backend labels + * slabs: fix off by one in slab picker loop + * ascii: fix potential overrun when given all spaces + * proxy: fix mutator crash in flagcopyall + * restart: avoid runaway read with corrupt file + * proxy: fix ring hash default mode + * tls: uninitialized string can be used in error + * proxy: fix off by one in request_append + * logger: fix use-after-free of closed watcher + +------------------------------------------------------------------- @@ -4 +38 @@ -- update to 1.6.44: +- update to 1.6.44: [bsc#1270716] Old: ---- memcached-1.6.44.tar.gz New: ---- memcached-1.6.45.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ memcached.spec ++++++ --- /var/tmp/diff_new_pack.dHiHVm/_old 2026-08-04 21:30:07.175144863 +0200 +++ /var/tmp/diff_new_pack.dHiHVm/_new 2026-08-04 21:30:07.179145002 +0200 @@ -42,7 +42,7 @@ %endif %endif Name: memcached -Version: 1.6.44 +Version: 1.6.45 Release: 0 Summary: A high-performance, distributed memory object caching system License: BSD-3-Clause ++++++ memcached-1.6.44.tar.gz -> memcached-1.6.45.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/memcached-1.6.44/configure new/memcached-1.6.45/configure --- old/memcached-1.6.44/configure 2026-07-07 06:24:04.000000000 +0200 +++ new/memcached-1.6.45/configure 2026-07-10 06:35:10.000000000 +0200 @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.72 for memcached 1.6.44. +# Generated by GNU Autoconf 2.72 for memcached 1.6.45. # # Report bugs to <[email protected]>. # @@ -604,8 +604,8 @@ # Identity of this package. PACKAGE_NAME='memcached' PACKAGE_TARNAME='memcached' -PACKAGE_VERSION='1.6.44' -PACKAGE_STRING='memcached 1.6.44' +PACKAGE_VERSION='1.6.45' +PACKAGE_STRING='memcached 1.6.45' PACKAGE_BUGREPORT='[email protected]' PACKAGE_URL='' @@ -1383,7 +1383,7 @@ # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -'configure' configures memcached 1.6.44 to adapt to many kinds of systems. +'configure' configures memcached 1.6.45 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1454,7 +1454,7 @@ if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of memcached 1.6.44:";; + short | recursive ) echo "Configuration of memcached 1.6.45:";; esac cat <<\_ACEOF @@ -1579,7 +1579,7 @@ test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -memcached configure 1.6.44 +memcached configure 1.6.45 generated by GNU Autoconf 2.72 Copyright (C) 2023 Free Software Foundation, Inc. @@ -2194,7 +2194,7 @@ This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by memcached $as_me 1.6.44, which was +It was created by memcached $as_me 1.6.45, which was generated by GNU Autoconf 2.72. Invocation command line was $ $0$ac_configure_args_raw @@ -3745,7 +3745,7 @@ # Define the identity of the package. PACKAGE='memcached' - VERSION='1.6.44' + VERSION='1.6.45' printf "%s\n" "#define PACKAGE \"$PACKAGE\"" >>confdefs.h @@ -9429,7 +9429,7 @@ # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by memcached $as_me 1.6.44, which was +This file was extended by memcached $as_me 1.6.45, which was generated by GNU Autoconf 2.72. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -9497,7 +9497,7 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config='$ac_cs_config_escaped' ac_cs_version="\\ -memcached config.status 1.6.44 +memcached config.status 1.6.45 configured by $0, generated by GNU Autoconf 2.72, with options \\"\$ac_cs_config\\" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/memcached-1.6.44/doc/Makefile new/memcached-1.6.45/doc/Makefile --- old/memcached-1.6.44/doc/Makefile 2026-07-07 06:24:07.000000000 +0200 +++ new/memcached-1.6.45/doc/Makefile 2026-07-10 06:35:12.000000000 +0200 @@ -194,10 +194,10 @@ PACKAGE = memcached PACKAGE_BUGREPORT = [email protected] PACKAGE_NAME = memcached -PACKAGE_STRING = memcached 1.6.44 +PACKAGE_STRING = memcached 1.6.45 PACKAGE_TARNAME = memcached PACKAGE_URL = -PACKAGE_VERSION = 1.6.44 +PACKAGE_VERSION = 1.6.45 PATH_SEPARATOR = : PKG_CONFIG = /usr/bin/pkg-config PKG_CONFIG_LIBDIR = @@ -208,7 +208,7 @@ SET_MAKE = SHELL = /bin/bash STRIP = -VERSION = 1.6.44 +VERSION = 1.6.45 XML2RFC = no XSLTPROC = no abs_builddir = /home/dormando/p/code/memcached/doc diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/memcached-1.6.44/logger.c new/memcached-1.6.45/logger.c --- old/memcached-1.6.44/logger.c 2026-05-18 23:43:09.000000000 +0200 +++ new/memcached-1.6.45/logger.c 2026-07-10 06:32:06.000000000 +0200 @@ -379,6 +379,7 @@ } if (dlen > 150) { dlen = 150; + le->dlen = dlen; } // be_namelen and be_portlen can't be longer than 255+6 le->reqlen = reqlen; @@ -550,7 +551,7 @@ [LOGGER_PROXY_USER] = {512, LOG_PROXYUSER, _logger_log_text, _logger_parse_text, "type=proxy_user msg=%s" }, - [LOGGER_PROXY_BE_ERROR] = {512, LOG_PROXYEVENTS, _logger_log_proxy_errbe, _logger_parse_prx_errbe, + [LOGGER_PROXY_BE_ERROR] = {1024, LOG_PROXYEVENTS, _logger_log_proxy_errbe, _logger_parse_prx_errbe, NULL }, @@ -687,9 +688,17 @@ (skip_scr = (char *) bipbuf_request(w->buf, scratch_len + 128)) == NULL) { if (logger_thread_poll_watchers(0, x) <= 0) { L_DEBUG("LOGGER: Watcher had no free space for line of size (%d)\n", scratch_len + 128); + // Oddity; poll_watchers can free *w, recheck it. + if (watchers[x] == NULL) { + break; + } w->failed_flush = true; } } + // See oddity note above. + if (watchers[x] == NULL) { + continue; + } if (w->failed_flush) { L_DEBUG("LOGGER: Fast skipped for watcher [%d] due to failed_flush\n", w->sfd); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/memcached-1.6.44/memcached.c new/memcached-1.6.45/memcached.c --- old/memcached-1.6.44/memcached.c 2026-07-07 05:19:47.000000000 +0200 +++ new/memcached-1.6.45/memcached.c 2026-07-10 06:32:06.000000000 +0200 @@ -2456,9 +2456,13 @@ fprintf(stderr, "Couldn't realloc input buffer\n"); } c->rbytes = 0; /* ignore what we read */ - out_of_memory(c, "SERVER_ERROR out of memory reading request"); - c->close_after_write = true; - return READ_MEMORY_ERROR; + if (!resp_start(c)) { + return READ_ERROR; + } else { + out_of_memory(c, "SERVER_ERROR out of memory reading request"); + c->close_after_write = true; + return READ_MEMORY_ERROR; + } } c->rcurr = c->rbuf = new_rbuf; c->rsize *= 2; @@ -5279,8 +5283,8 @@ goto error; } settings.slab_automove_window = atoi(subopts_value); - if (settings.slab_automove_window < 3) { - fprintf(stderr, "slab_automove_window must be > 2\n"); + if (settings.slab_automove_window < 3 || settings.slab_automove_window > 1800) { + fprintf(stderr, "slab_automove_window must be > 2 and < 1800\n"); goto error; } break; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/memcached-1.6.44/memcached.spec new/memcached-1.6.45/memcached.spec --- old/memcached-1.6.44/memcached.spec 2026-07-07 06:24:04.000000000 +0200 +++ new/memcached-1.6.45/memcached.spec 2026-07-10 06:35:09.000000000 +0200 @@ -27,7 +27,7 @@ %endif Name: memcached -Version: 1.6.44 +Version: 1.6.45 Release: 1%{?dist} Summary: High Performance, Distributed Memory Object Cache diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/memcached-1.6.44/proto_parser.c new/memcached-1.6.45/proto_parser.c --- old/memcached-1.6.44/proto_parser.c 2026-07-03 02:30:18.000000000 +0200 +++ new/memcached-1.6.45/proto_parser.c 2026-07-10 06:32:06.000000000 +0200 @@ -333,15 +333,6 @@ * PARSER UTIL CODE */ -// TODO: -// - the safe_strto calls in here are still "string-y" - they're going to -// parse until a space or newline. This is perfectly safe for any time we're -// in this code; since we can't get here without a \n or a space (ie; -// non-digit) -// - I'm not converting these to tokto*'s right now, because what they're -// pulling the flag while in a loop. So we need yet another interface (or -// refactor of existing interface). This code is safe, just not consistent. - int mc_prcmp(mcp_parser_t *pr, int token, const char *s) { int len = 0; const char *t = mcmc_token_get(pr->request, &pr->tok, token, &len); @@ -421,7 +412,7 @@ bool mc_parse_exptime(mc_resp *resp, mcp_parser_t *pr, int token, rel_time_t *exptime) { int32_t exptime_int = 0; - if (!safe_strtol(&pr->request[pr->tok.tokens[1]], &exptime_int)) { + if (mcmc_token_get_32(pr->request, &pr->tok, token, &exptime_int) != MCMC_OK) { pout_string(resp, "CLIENT_ERROR invalid exptime argument"); return false; } @@ -521,30 +512,30 @@ case 'N': of->locked = 1; of->vivify = 1; - if (!safe_strtol(&pr->request[pr->tok.tokens[i]+1], &tmp_int)) { + if (mcmc_token_get_flag_arg_32(pr->request, &pr->tok, i, &tmp_int) == MCMC_OK) { + of->autoviv_exptime = realtime(EXPTIME_TO_POSITIVE_TIME(tmp_int)); + } else { *errstr = "CLIENT_ERROR bad token in command line format"; of->has_error = 1; - } else { - of->autoviv_exptime = realtime(EXPTIME_TO_POSITIVE_TIME(tmp_int)); } break; case 'T': of->locked = 1; - if (!safe_strtol(&pr->request[pr->tok.tokens[i]+1], &tmp_int)) { - *errstr = "CLIENT_ERROR bad token in command line format"; - of->has_error = 1; - } else { + if (mcmc_token_get_flag_arg_32(pr->request, &pr->tok, i, &tmp_int) == MCMC_OK) { of->exptime = realtime(EXPTIME_TO_POSITIVE_TIME(tmp_int)); of->new_ttl = true; + } else { + *errstr = "CLIENT_ERROR bad token in command line format"; + of->has_error = 1; } break; case 'R': of->locked = 1; - if (!safe_strtol(&pr->request[pr->tok.tokens[i]+1], &tmp_int)) { + if (mcmc_token_get_flag_arg_32(pr->request, &pr->tok, i, &tmp_int) == MCMC_OK) { + of->recache_time = realtime(EXPTIME_TO_POSITIVE_TIME(tmp_int)); + } else { *errstr = "CLIENT_ERROR bad token in command line format"; of->has_error = 1; - } else { - of->recache_time = realtime(EXPTIME_TO_POSITIVE_TIME(tmp_int)); } break; case 'l': @@ -578,24 +569,28 @@ break; // mset-related. case 'F': - if (!safe_strtoflags(&pr->request[pr->tok.tokens[i]+1], &of->client_flags)) { +#ifdef LARGE_CLIENT_FLAGS + if (mcmc_token_get_flag_arg_u64(pr->request, &pr->tok, i, &of->client_flags) != MCMC_OK) { +#else + if (mcmc_token_get_flag_arg_u32(pr->request, &pr->tok, i, &of->client_flags) != MCMC_OK) { +#endif of->has_error = true; } break; case 'C': // mset, mdelete, marithmetic - if (!safe_strtoull(&pr->request[pr->tok.tokens[i]+1], &of->req_cas_id)) { - *errstr = "CLIENT_ERROR bad token in command line format"; - of->has_error = true; - } else { + if (mcmc_token_get_flag_arg_u64(pr->request, &pr->tok, i, &of->req_cas_id) == MCMC_OK) { of->has_cas = true; + } else { + *errstr = "CLIENT_ERROR bad token in command line format"; + of->has_error = 1; } break; case 'E': // ms, md, ma - if (!safe_strtoull(&pr->request[pr->tok.tokens[i]+1], &of->cas_id_in)) { - *errstr = "CLIENT_ERROR bad token in command line format"; - of->has_error = true; - } else { + if (mcmc_token_get_flag_arg_u64(pr->request, &pr->tok, i, &of->cas_id_in) == MCMC_OK) { of->has_cas_in = true; + } else { + *errstr = "CLIENT_ERROR bad token in command line format"; + of->has_error = 1; } break; case 'M': // mset and marithmetic mode switch @@ -604,13 +599,13 @@ of->mode = pr->request[pr->tok.tokens[i]+1]; break; case 'J': // marithmetic initial value - if (!safe_strtoull(&pr->request[pr->tok.tokens[i]+1], &of->initial)) { + if (mcmc_token_get_flag_arg_u64(pr->request, &pr->tok, i, &of->initial) != MCMC_OK) { *errstr = "CLIENT_ERROR invalid numeric initial value"; of->has_error = 1; } break; case 'D': // marithmetic delta value - if (!safe_strtoull(&pr->request[pr->tok.tokens[i]+1], &of->delta)) { + if (mcmc_token_get_flag_arg_u64(pr->request, &pr->tok, i, &of->delta) != MCMC_OK) { *errstr = "CLIENT_ERROR invalid numeric delta value"; of->has_error = 1; } @@ -769,7 +764,7 @@ // does cas value exist? if (handle_cas) { - if (!safe_strtoull(&pr->request[pr->tok.tokens[5]], &req_cas_id)) { + if (mcmc_token_get_u64(pr->request, &pr->tok, 5, &req_cas_id) != MCMC_OK) { pout_string(resp, "CLIENT_ERROR bad command line format"); return NULL; } @@ -871,7 +866,7 @@ return; } - if (!safe_strtoull(&pr->request[pr->tok.tokens[2]], &delta)) { + if (mcmc_token_get_u64(pr->request, &pr->tok, 2, &delta) != MCMC_OK) { pout_string(resp, "CLIENT_ERROR invalid numeric delta argument"); return; } @@ -961,7 +956,7 @@ return; } - if (!safe_strtol(&pr->request[pr->tok.tokens[2]], &exptime_int)) { + if (mcmc_token_get_32(pr->request, &pr->tok, 2, &exptime_int) != MCMC_OK) { pout_string(resp, "CLIENT_ERROR invalid exptime argument"); return; } @@ -1282,9 +1277,11 @@ return; error: if (it) { - do_item_remove(it); if (of.locked) { + do_item_remove(it); item_unlock(hv); + } else { + item_remove(it); } } pout_errstring(resp, errstr); @@ -1466,6 +1463,7 @@ break; default: pout_errstring(resp, "SERVER_ERROR Unhandled storage type."); + item_remove(it); return; } @@ -1517,9 +1515,8 @@ return; error: - // Note: no errors possible after the item was successfully allocated. - // So we're just looking at dumping error codes and returning. pout_errstring(resp, errstr); + item_remove(it); } void process_mdelete_cmd(LIBEVENT_THREAD *t, mcp_parser_t *pr, mc_resp *resp) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/memcached-1.6.44/proto_proxy.c new/memcached-1.6.45/proto_proxy.c --- old/memcached-1.6.44/proto_proxy.c 2026-03-05 00:05:05.000000000 +0100 +++ new/memcached-1.6.45/proto_proxy.c 2026-07-10 06:32:06.000000000 +0200 @@ -616,7 +616,8 @@ * large multiget, if not we should just nuke the connection. */ char *ptr = c->rcurr; - while (*ptr == ' ') { /* ignore leading whitespaces */ + char *end = c->rcurr + c->rbytes-6; + while (*ptr == ' ' && ptr != end) { /* ignore leading whitespaces */ ++ptr; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/memcached-1.6.44/proto_text.c new/memcached-1.6.45/proto_text.c --- old/memcached-1.6.44/proto_text.c 2026-07-07 06:16:48.000000000 +0200 +++ new/memcached-1.6.45/proto_text.c 2026-07-10 06:32:06.000000000 +0200 @@ -368,7 +368,8 @@ * large multiget, if not we should just nuke the connection. */ char *ptr = c->rcurr; - while (*ptr == ' ') { /* ignore leading whitespaces */ + char *end = c->rcurr + c->rbytes-6; + while (*ptr == ' ' && ptr != end) { /* ignore leading whitespaces */ ++ptr; } @@ -931,6 +932,10 @@ out_string(c, "CLIENT_ERROR bad command line format"); return; } + if (level < 3 || level > 1800) { + out_string(c, "CLIENT_ERROR automove window too low or too high"); + return; + } settings.slab_automove_window = level; settings.slab_automove_version++; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/memcached-1.6.44/proxy_lua.c new/memcached-1.6.45/proxy_lua.c --- old/memcached-1.6.44/proxy_lua.c 2026-05-18 23:43:09.000000000 +0200 +++ new/memcached-1.6.45/proxy_lua.c 2026-07-10 06:32:06.000000000 +0200 @@ -750,7 +750,7 @@ size_t remain = klen - (t1 - key); // must be at least one character inbetween the tags to hash. if (remain > 1) { - const char *t2 = memchr(t1, conf[1], remain); + const char *t2 = memchr(t1+1, conf[1], remain-1); if (t2) { *newlen = t2 - t1 - 1; @@ -940,6 +940,9 @@ luaL_checktype(L, -1, LUA_TSTRING); size_t len = 0; const char *bepfx = lua_tolstring(L, -1, &len); + if (len > MAX_LABELLEN-1) { + len = MAX_LABELLEN-1; + } memcpy(p->beprefix, bepfx, len); p->beprefix[len+1] = '\0'; lua_pop(L, 1); // pop beprefix string. @@ -989,7 +992,7 @@ } memcpy(p->key_filter_conf, conf, len); - p->key_filter_conf[len+1] = '\0'; + p->key_filter_conf[len] = '\0'; } else { proxy_lua_error(L, "hash filter requires 'filter_conf' string"); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/memcached-1.6.44/proxy_mutator.c new/memcached-1.6.45/proxy_mutator.c --- old/memcached-1.6.44/proxy_mutator.c 2026-05-19 00:12:18.000000000 +0200 +++ new/memcached-1.6.45/proxy_mutator.c 2026-07-10 06:32:06.000000000 +0200 @@ -489,6 +489,8 @@ case CMD_DELETE: p->src = "NOT_FOUND"; break; + default: + return -1; } p->slen = strlen(p->src); @@ -823,7 +825,7 @@ return -1; } int tlen = 0; - if (mcmc_token_has_flag_bit(&srs->tok, c->bit) == MCMC_OK) { + if (mcmc_token_has_flag_bit(&srq->pr.tok, c->bit) == MCMC_OK) { const char *tok = mcmc_token_get_flag(srq->pr.request, &srq->pr.tok, c->f, &tlen); p->slen = 1; if (tok && tlen > 0) { @@ -1118,6 +1120,9 @@ if (size != mut->aused) { proxy_lua_error(L, "mutator failed to properly initialize, memory not filled correctly"); } + if (scount == 0) { + proxy_lua_error(L, "mutator failed to initialize, no steps given"); + } mut->scount = scount; return 1; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/memcached-1.6.44/proxy_network.c new/memcached-1.6.45/proxy_network.c --- old/memcached-1.6.44/proxy_network.c 2026-07-07 06:16:48.000000000 +0200 +++ new/memcached-1.6.45/proxy_network.c 2026-07-10 06:32:06.000000000 +0200 @@ -601,6 +601,16 @@ } } + // TODO: mcmc's parser needs to use offsets into a string instead + // of pointers. Then all we do is swap the buffer pointer. In the + // meantime this is the smallest possible change to fix the issue + // of res:line() and similar returning the wrong buffer for + // pipelined requests, in cases where the result hasn't been + // reparsed before requesting the line. + ptrdiff_t rebase = r->buf - be->rbuf; + r->resp.value += rebase; + if (r->resp.rline) r->resp.rline += rebase; + P_DEBUG("%s: r->status: %d, r->bread: %d, r->vlen: %lu\n", __func__, r->status, r->bread, r->resp.vlen); if (r->resp.vlen != r->resp.vlen_read) { // shouldn't be possible to have excess in buffer diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/memcached-1.6.44/proxy_ratelim.c new/memcached-1.6.45/proxy_ratelim.c --- old/memcached-1.6.44/proxy_ratelim.c 2025-10-22 06:59:10.000000000 +0200 +++ new/memcached-1.6.45/proxy_ratelim.c 2026-07-10 06:32:06.000000000 +0200 @@ -69,6 +69,12 @@ lim->limit = _tbf_check(L, "limit"); lim->fill_rate = _tbf_check(L, "fillrate"); lim->tick_rate = _tbf_check(L, "tickrate"); + if (lim->fill_rate == 0) { + lim->fill_rate = 1; + } + if (lim->tick_rate == 0) { + lim->tick_rate = 1; + } // seed the token bucket filter. lim->bucket = lim->limit; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/memcached-1.6.44/proxy_request.c new/memcached-1.6.45/proxy_request.c --- old/memcached-1.6.44/proxy_request.c 2026-05-19 00:12:18.000000000 +0200 +++ new/memcached-1.6.45/proxy_request.c 2026-07-10 06:32:06.000000000 +0200 @@ -94,12 +94,12 @@ memset(pr, 0, sizeof(mcp_parser_t)); // TODO: required? int ret = process_request(pr, rq->request, p - temp); + pr->vbuf = vbuf; + pr->vlen = vlen; + if (ret != 0) { - // FIXME: does this leak the vbuf? return ret; } - pr->vbuf = vbuf; - pr->vlen = vlen; return 0; } @@ -109,7 +109,7 @@ char *p = (char *)pr->request + pr->reqlen - 2; // start at the \r assert(*p == '\r'); - if (pr->reqlen + len + 2 > MCP_REQUEST_MAXLEN) { + if (pr->reqlen + len + 2 >= MCP_REQUEST_MAXLEN) { return -1; } @@ -134,11 +134,11 @@ memset(pr, 0, sizeof(mcp_parser_t)); // TODO: required? int ret = process_request(pr, rq->request, p - start); + pr->vbuf = vbuf; + pr->vlen = vlen; if (ret != 0) { return ret; } - pr->vbuf = vbuf; - pr->vlen = vlen; return 0; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/memcached-1.6.44/proxy_result.c new/memcached-1.6.45/proxy_result.c --- old/memcached-1.6.44/proxy_result.c 2026-03-05 00:05:05.000000000 +0100 +++ new/memcached-1.6.45/proxy_result.c 2026-07-10 06:32:06.000000000 +0200 @@ -142,6 +142,10 @@ free(r->buf); r->buf = NULL; + // Do some deeper cleaning: a manually closed res could still + // potentially be fed back into the system, causing errors. + r->blen = 0; + memset(&r->resp, 0, sizeof(r->resp)); } r->tok.ntokens = 0; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/memcached-1.6.44/proxy_ring_hash.c new/memcached-1.6.45/proxy_ring_hash.c --- old/memcached-1.6.44/proxy_ring_hash.c 2024-10-31 21:47:40.000000000 +0100 +++ new/memcached-1.6.45/proxy_ring_hash.c 2026-07-10 06:32:06.000000000 +0200 @@ -135,6 +135,7 @@ size_t len = snprintf(hashstring, hashstring_size, "%s:%s-%d", parts[0], parts[1], k); kt->continuum[*cont].point = (unsigned int) XXH3_64bits(hashstring, len); kt->continuum[*cont].id = id; + (*cont)++; } free(hashstring); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/memcached-1.6.44/restart.c new/memcached-1.6.45/restart.c --- old/memcached-1.6.44/restart.c 2026-03-05 00:05:05.000000000 +0100 +++ new/memcached-1.6.45/restart.c 2026-07-10 06:32:06.000000000 +0200 @@ -156,7 +156,8 @@ // T for TAG, changing the callback we use. // K for key/value, to ship to the active callback. char *p = line; - while (*p != '\n') { + char *end = p + len; + while (*p != '\n' && p != end) { p++; } *p = '\0'; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/memcached-1.6.44/slabs.c new/memcached-1.6.45/slabs.c --- old/memcached-1.6.44/slabs.c 2026-05-19 00:12:18.000000000 +0200 +++ new/memcached-1.6.45/slabs.c 2026-07-10 06:32:06.000000000 +0200 @@ -760,9 +760,8 @@ s_cls->slab_list[x] = s_cls->slab_list[x+1]; } - // FIXME: it's nearly impossible for this to fail, and error handling here - // is gnarly since we'll have to just put the page back where we got it - // from. + // FIXME: it's nearly impossible for this to fail. If it does it can cause + // writing beyond the border, lost pages, etc. // For now we won't handle the error, and a subsequent commit should // remove the need to resize the slab list. do_grow_slab_list(did); @@ -792,7 +791,7 @@ int tries = MAX_NUMBER_OF_SLAB_CLASSES - POWER_SMALLEST + 1; for (; tries > 0; tries--) { cur++; - if (cur > MAX_NUMBER_OF_SLAB_CLASSES) + if (cur >= MAX_NUMBER_OF_SLAB_CLASSES) cur = POWER_SMALLEST; if (cur == did) continue; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/memcached-1.6.44/stats_prefix.c new/memcached-1.6.45/stats_prefix.c --- old/memcached-1.6.44/stats_prefix.c 2024-10-31 21:47:40.000000000 +0100 +++ new/memcached-1.6.45/stats_prefix.c 2026-07-10 06:32:06.000000000 +0200 @@ -6,6 +6,8 @@ #include <string.h> #include <assert.h> +#define MAX_PREFIX_COUNT (1<<16) + /* Hash table that uses the global hash function */ static PREFIX_STATS *prefix_stats[PREFIX_HASH_SIZE]; @@ -60,6 +62,14 @@ return pfs; } + // Hash table is a fixed size and there's no other way to limit memory + // usage. The lookup HT is a fixed size as well so this is also a + // performance problem. The system needs to be deprecated/removed or + // rewritten. + if (num_prefixes >= MAX_PREFIX_COUNT) { + return NULL; + } + pfs = calloc(sizeof(PREFIX_STATS), 1); if (NULL == pfs) { perror("Can't allocate space for stats structure: calloc"); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/memcached-1.6.44/storage.c new/memcached-1.6.45/storage.c --- old/memcached-1.6.44/storage.c 2026-05-18 23:43:09.000000000 +0200 +++ new/memcached-1.6.45/storage.c 2026-07-10 06:32:06.000000000 +0200 @@ -204,7 +204,8 @@ // truncate the data response. resp->iov[p->iovec_data].iov_len = 0; // wipe the extlen iov... wish it was just a flat buffer. - resp->iov[p->iovec_data-1].iov_len = 0; + // this is unconditionally the second iov. + resp->iov[1].iov_len = 0; resp->chunked_data_iov = 0; } else { int i; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/memcached-1.6.44/t/getset.t new/memcached-1.6.45/t/getset.t --- old/memcached-1.6.44/t/getset.t 2026-03-05 00:05:05.000000000 +0100 +++ new/memcached-1.6.45/t/getset.t 2026-07-10 06:32:06.000000000 +0200 @@ -1,7 +1,7 @@ #!/usr/bin/env perl use strict; -use Test::More tests => 37992; +use Test::More tests => 37993; use FindBin qw($Bin); use lib "$Bin/lib"; use MemcachedTest; @@ -23,6 +23,18 @@ is(scalar <$ns>, undef, "long ascii incr was not fine"); }; +SKIP: { + skip "test flaky on old OS. has run on newer ones", 1; +subtest 'oops all spaces' => sub { + my $ns = $server->new_sock; + $ns->autoflush(1); + + my $spaces = ' ' x 14000; + syswrite($ns, $spaces); + is(scalar <$ns>, undef, "errored out"); +}; +}; + # set foo (and should get it) print $sock "set foo 0 0 6\r\nfooval\r\n"; is(scalar <$sock>, "STORED\r\n", "stored foo"); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/memcached-1.6.44/t/proxyunits.lua new/memcached-1.6.45/t/proxyunits.lua --- old/memcached-1.6.44/t/proxyunits.lua 2026-05-18 23:43:09.000000000 +0200 +++ new/memcached-1.6.45/t/proxyunits.lua 2026-07-10 06:32:06.000000000 +0200 @@ -281,6 +281,8 @@ return res end return "ERROR unexpected line, got [" .. line .. "]\r\n" + elseif key == "/response/rbufline" then + return "HD " .. res:line() .. "\r\n" elseif key == "/response/blank" then res:flag_blank("O") return res diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/memcached-1.6.44/t/proxyunits.t new/memcached-1.6.45/t/proxyunits.t --- old/memcached-1.6.44/t/proxyunits.t 2026-07-03 02:30:18.000000000 +0200 +++ new/memcached-1.6.45/t/proxyunits.t 2026-07-10 06:32:06.000000000 +0200 @@ -1079,6 +1079,19 @@ ); }; + subtest 'response:line() under pipeline' => sub { + my $be = $mbe[0]; + my $cmd = "mg /response/rbufline\r\n"; + # pipeline two requests to the same backend + print $ps $cmd . $cmd; + is(scalar <$be>, $cmd, "be received request A"); + is(scalar <$be>, $cmd, "be received request B"); + print $be "HD Oa\r\nHD Ob\r\n"; + is(scalar <$ps>, "HD Oa\r\n", "response A matches"); + is(scalar <$ps>, "HD Ob\r\n", "response B matches"); + check_version($ps); + }; + subtest 'response:flag_blank()' => sub { proxy_test( ps_send => "mg /response/blank f Ofoo t\r\n", diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/memcached-1.6.44/t/slabs-mover.t new/memcached-1.6.45/t/slabs-mover.t --- old/memcached-1.6.44/t/slabs-mover.t 2026-07-03 02:30:18.000000000 +0200 +++ new/memcached-1.6.45/t/slabs-mover.t 2026-07-10 06:32:06.000000000 +0200 @@ -15,6 +15,7 @@ my $sock = $server->sock; { + subtest 'automove window' => \&test_automove_window; subtest 'syntax' => \&test_syntax; subtest 'fill and move pages' => \&test_fill; subtest 'chunked items' => \&test_chunked; @@ -80,6 +81,29 @@ return $sid; } +# TODO: mc metric for automove runs so we can loop for that instead of blind +# sleep. +sub test_automove_window { + print $sock "slabs automove 1\r\n"; + is(scalar <$sock>, "OK\r\n", "automover on"); + print $sock "slabs automove window 0\r\n"; + is(scalar <$sock>, "CLIENT_ERROR automove window too low or too high\r\n", "invalid window"); + + sleep 4; + print $sock "version\r\n"; + like(scalar <$sock>, qr/VERSION/, "daemon still alive"); + + print $sock "slabs automove window 67108864\r\n"; + is(scalar <$sock>, "CLIENT_ERROR automove window too low or too high\r\n", "invalid window"); + sleep 4; + + print $sock "version\r\n"; + like(scalar <$sock>, qr/VERSION/, "daemon still alive"); + + print $sock "slabs automove 0\r\n"; + is(scalar <$sock>, "OK\r\n", "automover off"); +} + # NOTE: Can't validate reflocked items in an integration test since we leak # the memory and cannot de-ref an unlinked item. # TODO: test reflocked chunked items as well diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/memcached-1.6.44/tls.c new/memcached-1.6.45/tls.c --- old/memcached-1.6.44/tls.c 2026-03-05 00:05:05.000000000 +0100 +++ new/memcached-1.6.45/tls.c 2026-07-10 06:32:06.000000000 +0200 @@ -86,6 +86,7 @@ NULL, c->sfd, strerror(errno)); } else { char ssl_err[SSL_ERROR_MSG_SIZE]; + ssl_err[0] = '\0'; // OpenSSL internal error. One or more, but lets only care about // the top error for now. print_ssl_error(ssl_err, SSL_ERROR_MSG_SIZE); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/memcached-1.6.44/vendor/mcmc/mcmc.c new/memcached-1.6.45/vendor/mcmc/mcmc.c --- old/memcached-1.6.44/vendor/mcmc/mcmc.c 2026-07-03 02:30:18.000000000 +0200 +++ new/memcached-1.6.45/vendor/mcmc/mcmc.c 2026-07-10 06:32:06.000000000 +0200 @@ -655,6 +655,21 @@ #undef X +#define X(n, p, c) \ + int n(const char *l, mcmc_tokenizer_t *t, int idx, p *val) { \ + int tlen = 0; \ + const char *tok = _mcmc_token(l, t, idx, &tlen); \ + if (tlen > 1) { \ + return c(tok+1, tlen-1, val); \ + } \ + return MCMC_ERR; \ + } + +X(mcmc_token_get_flag_arg_u32, uint32_t, mcmc_toktou32) +X(mcmc_token_get_flag_arg_u64, uint64_t, mcmc_toktou64) +X(mcmc_token_get_flag_arg_32, int32_t, mcmc_tokto32) +X(mcmc_token_get_flag_arg_64, int64_t, mcmc_tokto64) + int mcmc_token_has_flag(const char *l, mcmc_tokenizer_t *t, char flag) { if (flag < 65 || flag > 122) { return MCMC_ERR; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/memcached-1.6.44/vendor/mcmc/mcmc.h new/memcached-1.6.45/vendor/mcmc/mcmc.h --- old/memcached-1.6.44/vendor/mcmc/mcmc.h 2026-03-05 00:05:05.000000000 +0100 +++ new/memcached-1.6.45/vendor/mcmc/mcmc.h 2026-07-10 06:32:06.000000000 +0200 @@ -154,6 +154,15 @@ int mcmc_token_get_flag_64(const char *l, mcmc_tokenizer_t *t, char flag, int64_t *val); int mcmc_token_get_flag_idx(const char *l, mcmc_tokenizer_t *t, char flag); +// WARNING: these assume a valid index fetched via get_flag_idx or a loop +// iteration against ntokens. +// If exists, convert the argument to the flag at position idx into the +// requested numeric. +int mcmc_token_get_flag_arg_u32(const char *l, mcmc_tokenizer_t *t, int idx, uint32_t *val); +int mcmc_token_get_flag_arg_u64(const char *l, mcmc_tokenizer_t *t, int idx, uint64_t *val); +int mcmc_token_get_flag_arg_32(const char *l, mcmc_tokenizer_t *t, int idx, int32_t *val); +int mcmc_token_get_flag_arg_64(const char *l, mcmc_tokenizer_t *t, int idx, int64_t *val); + #ifdef MCMC_TEST int mcmc_toktou32(const char *t, size_t len, uint32_t *out); int mcmc_toktou64(const char *t, size_t len, uint64_t *out); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/memcached-1.6.44/version.m4 new/memcached-1.6.45/version.m4 --- old/memcached-1.6.44/version.m4 2026-07-07 06:24:04.000000000 +0200 +++ new/memcached-1.6.45/version.m4 2026-07-10 06:35:09.000000000 +0200 @@ -1 +1 @@ -m4_define([VERSION_NUMBER], [1.6.44]) +m4_define([VERSION_NUMBER], [1.6.45])
