libmemcached: fix #125: allocation failure on negative expiration
authorMichael Wallner <mike@php.net>
Tue, 9 Aug 2022 08:29:13 +0000 (10:29 +0200)
committerMichael Wallner <mike@php.net>
Tue, 9 Aug 2022 08:29:13 +0000 (10:29 +0200)
ChangeLog-1.1.md
src/libmemcached/flush.cc
src/libmemcached/storage.cc
src/libmemcached/touch.cc
test/tests/memcached/regression/gh_0125.cpp [new file with mode: 0644]

index 9546980e7a5f0fde19f41fec338721bcc90ccb9c..b430d9369aee76e18b32a9398bc0ebce8102f70b 100644 (file)
@@ -1,5 +1,13 @@
 # ChangeLog v1.1
 
+## v 1.1.2
+
+> released 2022-08-08
+
+* Fix handling of negative expiration values, which are somehow allowed by legacy. 
+  See also [gh #125](https://github.com/awesomized/libmemcached/issues/125),
+  and [gh #76](https://github.com/awesomized/libmemcached/issues/76).
+
 ## v 1.1.1
 
 > released 2021-09-16
index 5e358b0863ea7aa6271f521ed7072db0e1b88413..e0b45b68adf56c0d59f1a4aa9b3d71b18c68d7bb 100644 (file)
@@ -61,10 +61,10 @@ static memcached_return_t memcached_flush_binary(Memcached *ptr, time_t expirati
 
 static memcached_return_t memcached_flush_textual(Memcached *ptr, time_t expiration,
                                                   const bool reply) {
-  char buffer[MEMCACHED_MAXIMUM_INTEGER_DISPLAY_LENGTH + 1];
+  char buffer[MEMCACHED_MAXIMUM_INTEGER_DISPLAY_LENGTH + 1 + 1];
   int send_length = 0;
   if (expiration) {
-    send_length = snprintf(buffer, sizeof(buffer), "%llu", (unsigned long long) expiration);
+    send_length = snprintf(buffer, sizeof(buffer), "%lld", (long long) expiration);
   }
 
   if (size_t(send_length) >= sizeof(buffer) or send_length < 0) {
index eacc04f0f69b3fc767003e10a05f9d8594c6d5dd..31eadb1e2e9fa9aa8416a18ee673014f6c421854 100644 (file)
@@ -189,9 +189,9 @@ memcached_send_ascii(Memcached *ptr, memcached_instance_st *instance, const char
         memcached_literal_param("snprintf(MEMCACHED_MAXIMUM_INTEGER_DISPLAY_LENGTH)"));
   }
 
-  char expiration_buffer[MEMCACHED_MAXIMUM_INTEGER_DISPLAY_LENGTH + 1];
-  int expiration_buffer_length = snprintf(expiration_buffer, sizeof(expiration_buffer), " %llu",
-                                          (unsigned long long) expiration);
+  char expiration_buffer[MEMCACHED_MAXIMUM_INTEGER_DISPLAY_LENGTH + 1 + 1];
+  int expiration_buffer_length = snprintf(expiration_buffer, sizeof(expiration_buffer), " %lld",
+                                          (long long) expiration);
   if (size_t(expiration_buffer_length) >= sizeof(expiration_buffer) or expiration_buffer_length < 0)
   {
     return memcached_set_error(
index 6d8fdc4efd4e63b838a743359e36088b4414c4cf..b55f33e0e032e59a15651f2f6595d83146b7b89f 100644 (file)
@@ -17,9 +17,9 @@
 
 static memcached_return_t ascii_touch(memcached_instance_st *instance, const char *key,
                                       size_t key_length, time_t expiration) {
-  char expiration_buffer[MEMCACHED_MAXIMUM_INTEGER_DISPLAY_LENGTH + 1];
-  int expiration_buffer_length = snprintf(expiration_buffer, sizeof(expiration_buffer), " %llu",
-                                          (unsigned long long) expiration);
+  char expiration_buffer[MEMCACHED_MAXIMUM_INTEGER_DISPLAY_LENGTH + 1 + 1];
+  int expiration_buffer_length = snprintf(expiration_buffer, sizeof(expiration_buffer), " %lld",
+                                          (long long) expiration);
   if (size_t(expiration_buffer_length) >= sizeof(expiration_buffer) + 1
       or expiration_buffer_length < 0)
   {
diff --git a/test/tests/memcached/regression/gh_0125.cpp b/test/tests/memcached/regression/gh_0125.cpp
new file mode 100644 (file)
index 0000000..ca04af2
--- /dev/null
@@ -0,0 +1,15 @@
+#include "test/lib/common.hpp"
+#include "test/lib/MemcachedCluster.hpp"
+
+TEST_CASE("memcached_regression_gh_0125") {
+  auto test = MemcachedCluster::network();
+  auto memc = &test.memc;
+  auto blob = random_ascii_string(1024);
+  auto binary = GENERATE(0, 1);
+
+  test.enableBinaryProto(binary);
+  INFO("binary: " << binary);
+
+  memcached_return_t rc = memcached_set(memc, S("key"), blob.c_str(), blob.length(), -123, 0);
+  REQUIRE_SUCCESS(rc);
+}