]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
bufq: unwrite fix
authorStefan Eissing <stefan@eissing.org>
Thu, 3 Oct 2024 08:15:07 +0000 (10:15 +0200)
committerDaniel Stenberg <daniel@haxx.se>
Thu, 3 Oct 2024 11:27:36 +0000 (13:27 +0200)
`Curl_bufq_unwrite()` used the head instead of the tail chunk to shrink
the bufq's content. Fix this and add test case that checks correct
behaviour.

Amended test 2601 accordingly.

Reported-by: Chris Stubbs
Closes #15136

.github/scripts/spellcheck.words
docs/internals/BUFQ.md
lib/bufq.c
tests/unit/unit2601.c

index 9ae95ac1d210b8b7c398454b93bd742d76fadbae..4254ec9557f89d95a0fcc496756e60fecb68b9f8 100644 (file)
@@ -889,6 +889,7 @@ unsanitized
 Unshare
 unsharing
 untrusted
+unwrite
 UPN
 upstreaming
 URI
index 60843819ef637d20a07ba8b173f4f1855b43aac2..bb577845217219e688a2a85c1a1aba32c50d03d1 100644 (file)
@@ -76,6 +76,17 @@ void Curl_bufq_skip(struct bufq *q, size_t amount);
 
 This removes `amount` number of bytes from the `bufq`.
 
+## unwrite
+
+It is possible to undo writes by calling:
+
+```
+CURLcode Curl_bufq_unwrite(struct bufq *q, size_t len);
+```
+
+This will remove `len` bytes from the end of the bufq again. When removing
+more bytes than are present, CURLE_AGAIN is returned and the bufq will be
+empty.
 
 ## lifetime
 
index 4e67c3a3e8247e96de0fd64b984cdabbf155e518..547d4d376293391f03654ee2d0b87e51f430af9f 100644 (file)
@@ -491,7 +491,7 @@ CURLcode Curl_bufq_cwrite(struct bufq *q,
 CURLcode Curl_bufq_unwrite(struct bufq *q, size_t len)
 {
   while(len && q->tail) {
-    len -= chunk_unwrite(q->head, len);
+    len -= chunk_unwrite(q->tail, len);
     prune_tail(q);
   }
   return len ? CURLE_AGAIN : CURLE_OK;
index 7e7a14554e2bc00c7c04b15631efea1fbc40b6cf..1744d9d315676fa780490e7e25606ec662c28c62 100644 (file)
@@ -209,6 +209,41 @@ static void check_bufq(size_t pool_spares,
   }
   fail_unless(nread == nwritten, "did not get the same out as put in");
 
+  /* CHECK bufq_unwrite: write a string repeatedly into the second chunk.
+   * bufq_unwrite() 1 byte. Read strings again and check for content.
+   * We had a bug that unwrite used the head chunk instead of tail, which
+   * did corrupt the read values. */
+  if(TRUE) {
+    const unsigned char buf[] = "0123456789--";
+    size_t roffset;
+    Curl_bufq_reset(&q);
+    while(Curl_bufq_len(&q) < chunk_size) {
+      n = Curl_bufq_write(&q, buf, sizeof(buf), &result);
+      fail_unless(n > 0 && (size_t)n == sizeof(buf), "write incomplete");
+      if(result)
+        break;
+    }
+    result = Curl_bufq_unwrite(&q, 1);
+    roffset = 0;
+    while(!Curl_bufq_is_empty(&q)) {
+      unsigned char rbuf[sizeof(buf)];
+      n = Curl_bufq_read(&q, rbuf, sizeof(rbuf), &result);
+      fail_unless(n > 0, "read should work");
+      if(result)
+        break;
+      if(n != sizeof(rbuf)) {
+        fail_unless(Curl_bufq_is_empty(&q), "should be last read");
+      }
+      if(memcmp(buf, rbuf, n)) {
+        fprintf(stderr, "at offset %zu expected '%.*s', got '%.*s'\n",
+                roffset, (int)n, buf, (int)n, rbuf);
+        fail("read buf content wrong");
+      }
+      roffset += n;
+    }
+    Curl_bufq_reset(&q);
+  }
+
   dump_bufq(&q, "at end of test");
   Curl_bufq_free(&q);
   if(pool_spares > 0)