<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array"/>
  <modified type="array">
    <modified>
      <diff>@@ -379,7 +379,9 @@ char *do_item_stats(int *bytes) {
 char* do_item_stats_sizes(int *bytes) {
     const int num_buckets = 32768;   /* max 1MB object, divided into 32 bytes size buckets */
     unsigned int *histogram = (unsigned int *)malloc((size_t)num_buckets * sizeof(int));
-    char *buf = (char *)malloc(2 * 1024 * 1024); /* 2MB max response size */
+    size_t bufsize = (2 * 1024 * 1024), offset = 0;
+    char *buf = (char *)malloc(bufsize); /* 2MB max response size */
+    char terminator[] = &quot;END\r\n&quot;;
     int i;
 
     if (histogram == 0 || buf == 0) {
@@ -405,10 +407,11 @@ char* do_item_stats_sizes(int *bytes) {
     *bytes = 0;
     for (i = 0; i &lt; num_buckets; i++) {
         if (histogram[i] != 0) {
-            *bytes += sprintf(&amp;buf[*bytes], &quot;%d %u\r\n&quot;, i * 32, histogram[i]);
+            offset = append_to_buffer(buf, bufsize, offset, sizeof(terminator), &quot;%d %u\r\n&quot;, i * 32, histogram[i]);
         }
     }
-    *bytes += sprintf(&amp;buf[*bytes], &quot;END\r\n&quot;);
+    offset = append_to_buffer(buf, bufsize, offset, 0, terminator);
+    *bytes = (int) offset;
     free(histogram);
     return buf;
 }</diff>
      <filename>items.c</filename>
    </modified>
    <modified>
      <diff>@@ -140,6 +140,34 @@ static rel_time_t realtime(const time_t exptime) {
     }
 }
 
+size_t append_to_buffer(char* const buffer_start,
+                        const size_t buffer_size,
+                        const size_t buffer_off,
+                        const size_t reserved,
+                        const char* fmt,
+                        ...) {
+    va_list ap;
+    ssize_t written;
+    size_t left = buffer_size - buffer_off;
+
+    if (left &lt;= reserved) {
+        return buffer_off;
+    }
+
+    va_start(ap, fmt);
+    written = vsnprintf(&amp;buffer_start[buffer_off], left, fmt, ap);
+    va_end(ap);
+
+    if (written &lt; 0) {
+        return buffer_off;
+    } else if (written &gt;= left) {
+        buffer_start[buffer_off] = 0;
+        return buffer_off;
+    }
+
+    return buffer_off + written;
+}
+
 static void stats_init(void) {
     stats.curr_items = stats.total_items = stats.curr_conns = stats.total_conns = stats.conn_structs = 0;
     stats.get_cmds = stats.set_cmds = stats.get_hits = stats.get_misses = stats.evictions = 0;
@@ -1031,9 +1059,10 @@ static void process_stat(conn *c, token_t *tokens, const size_t ntokens) {
     command = tokens[COMMAND_TOKEN].value;
 
     if (ntokens == 2 &amp;&amp; strcmp(command, &quot;stats&quot;) == 0) {
-        char temp[1024];
+        size_t bufsize = 2048, offset = 0;
+        char temp[bufsize];
+        char terminator[] = &quot;END&quot;;
         pid_t pid = getpid();
-        char *pos = temp;
 
 #ifndef WIN32
         struct rusage usage;
@@ -1041,31 +1070,32 @@ static void process_stat(conn *c, token_t *tokens, const size_t ntokens) {
 #endif /* !WIN32 */
 
         STATS_LOCK();
-        pos += sprintf(pos, &quot;STAT pid %u\r\n&quot;, pid);
-        pos += sprintf(pos, &quot;STAT uptime %u\r\n&quot;, now);
-        pos += sprintf(pos, &quot;STAT time %ld\r\n&quot;, now + stats.started);
-        pos += sprintf(pos, &quot;STAT version &quot; VERSION &quot;\r\n&quot;);
-        pos += sprintf(pos, &quot;STAT pointer_size %d\r\n&quot;, 8 * sizeof(void *));
+        offset = append_to_buffer(temp, bufsize, offset, sizeof(terminator), &quot;STAT pid %u\r\n&quot;, pid);
+        offset = append_to_buffer(temp, bufsize, offset, sizeof(terminator), &quot;STAT uptime %u\r\n&quot;, now);
+        offset = append_to_buffer(temp, bufsize, offset, sizeof(terminator), &quot;STAT time %ld\r\n&quot;, now + stats.started);
+        offset = append_to_buffer(temp, bufsize, offset, sizeof(terminator), &quot;STAT version &quot; VERSION &quot;\r\n&quot;);
+        offset = append_to_buffer(temp, bufsize, offset, sizeof(terminator), &quot;STAT pointer_size %lu\r\n&quot;, 8 * sizeof(void *));
 #ifndef WIN32
-        pos += sprintf(pos, &quot;STAT rusage_user %ld.%06ld\r\n&quot;, usage.ru_utime.tv_sec, usage.ru_utime.tv_usec);
-        pos += sprintf(pos, &quot;STAT rusage_system %ld.%06ld\r\n&quot;, usage.ru_stime.tv_sec, usage.ru_stime.tv_usec);
+        offset = append_to_buffer(temp, bufsize, offset, sizeof(terminator), &quot;STAT rusage_user %ld.%06d\r\n&quot;, usage.ru_utime.tv_sec, (int) usage.ru_utime.tv_usec);
+        offset = append_to_buffer(temp, bufsize, offset, sizeof(terminator), &quot;STAT rusage_system %ld.%06d\r\n&quot;, usage.ru_stime.tv_sec, (int) usage.ru_stime.tv_usec);
 #endif /* !WIN32 */
-        pos += sprintf(pos, &quot;STAT curr_items %u\r\n&quot;, stats.curr_items);
-        pos += sprintf(pos, &quot;STAT total_items %u\r\n&quot;, stats.total_items);
-        pos += sprintf(pos, &quot;STAT bytes %llu\r\n&quot;, stats.curr_bytes);
-        pos += sprintf(pos, &quot;STAT curr_connections %u\r\n&quot;, stats.curr_conns - 1); /* ignore listening conn */
-        pos += sprintf(pos, &quot;STAT total_connections %u\r\n&quot;, stats.total_conns);
-        pos += sprintf(pos, &quot;STAT connection_structures %u\r\n&quot;, stats.conn_structs);
-        pos += sprintf(pos, &quot;STAT cmd_get %llu\r\n&quot;, stats.get_cmds);
-        pos += sprintf(pos, &quot;STAT cmd_set %llu\r\n&quot;, stats.set_cmds);
-        pos += sprintf(pos, &quot;STAT get_hits %llu\r\n&quot;, stats.get_hits);
-        pos += sprintf(pos, &quot;STAT get_misses %llu\r\n&quot;, stats.get_misses);
-        pos += sprintf(pos, &quot;STAT evictions %llu\r\n&quot;, stats.evictions);
-        pos += sprintf(pos, &quot;STAT bytes_read %llu\r\n&quot;, stats.bytes_read);
-        pos += sprintf(pos, &quot;STAT bytes_written %llu\r\n&quot;, stats.bytes_written);
-        pos += sprintf(pos, &quot;STAT limit_maxbytes %llu\r\n&quot;, (uint64_t) settings.maxbytes);
-        pos += sprintf(pos, &quot;STAT threads %u\r\n&quot;, settings.num_threads);
-        pos += sprintf(pos, &quot;END&quot;);
+        offset = append_to_buffer(temp, bufsize, offset, sizeof(terminator), &quot;STAT curr_items %u\r\n&quot;, stats.curr_items);
+        offset = append_to_buffer(temp, bufsize, offset, sizeof(terminator), &quot;STAT total_items %u\r\n&quot;, stats.total_items);
+        offset = append_to_buffer(temp, bufsize, offset, sizeof(terminator), &quot;STAT bytes %&quot; PRINTF_INT64_MODIFIER &quot;u\r\n&quot;, stats.curr_bytes);
+        offset = append_to_buffer(temp, bufsize, offset, sizeof(terminator), &quot;STAT curr_connections %u\r\n&quot;, stats.curr_conns - 1); /* ignore listening conn */
+        offset = append_to_buffer(temp, bufsize, offset, sizeof(terminator), &quot;STAT total_connections %u\r\n&quot;, stats.total_conns);
+        offset = append_to_buffer(temp, bufsize, offset, sizeof(terminator), &quot;STAT connection_structures %u\r\n&quot;, stats.conn_structs);
+        offset = append_to_buffer(temp, bufsize, offset, sizeof(terminator), &quot;STAT cmd_get %&quot; PRINTF_INT64_MODIFIER &quot;u\r\n&quot;, stats.get_cmds);
+        offset = append_to_buffer(temp, bufsize, offset, sizeof(terminator), &quot;STAT cmd_set %&quot; PRINTF_INT64_MODIFIER &quot;u\r\n&quot;, stats.set_cmds);
+        offset = append_to_buffer(temp, bufsize, offset, sizeof(terminator), &quot;STAT get_hits %&quot; PRINTF_INT64_MODIFIER &quot;u\r\n&quot;, stats.get_hits);
+        offset = append_to_buffer(temp, bufsize, offset, sizeof(terminator), &quot;STAT get_misses %&quot; PRINTF_INT64_MODIFIER &quot;u\r\n&quot;, stats.get_misses);
+        offset = append_to_buffer(temp, bufsize, offset, sizeof(terminator), &quot;STAT hit_rate %g%%\r\n&quot;, (stats.get_hits + stats.get_misses) == 0 ? 0.0 : (double)stats.get_hits * 100 / (stats.get_hits + stats.get_misses));
+        offset = append_to_buffer(temp, bufsize, offset, sizeof(terminator), &quot;STAT evictions %&quot; PRINTF_INT64_MODIFIER &quot;u\r\n&quot;, stats.evictions);
+        offset = append_to_buffer(temp, bufsize, offset, sizeof(terminator), &quot;STAT bytes_read %&quot; PRINTF_INT64_MODIFIER &quot;u\r\n&quot;, stats.bytes_read);
+        offset = append_to_buffer(temp, bufsize, offset, sizeof(terminator), &quot;STAT bytes_written %&quot; PRINTF_INT64_MODIFIER &quot;u\r\n&quot;, stats.bytes_written);
+        offset = append_to_buffer(temp, bufsize, offset, sizeof(terminator), &quot;STAT limit_maxbytes %&quot; PRINTF_INT64_MODIFIER &quot;u\r\n&quot;, (uint64_t) settings.maxbytes);
+        offset = append_to_buffer(temp, bufsize, offset, sizeof(terminator), &quot;STAT threads %u\r\n&quot;, settings.num_threads);
+        offset = append_to_buffer(temp, bufsize, offset, 0, terminator);
         STATS_UNLOCK();
         out_string(c, temp);
         return;
@@ -1082,21 +1112,23 @@ static void process_stat(conn *c, token_t *tokens, const size_t ntokens) {
 #ifdef HAVE_MALLOC_H
 #ifdef HAVE_STRUCT_MALLINFO
     if (strcmp(subcommand, &quot;malloc&quot;) == 0) {
-        char temp[512];
+        size_t bufsize = 512, offset = 0;
+        char temp[bufsize];
+        char terminator[] = &quot;END&quot;;
         struct mallinfo info;
-        char *pos = temp;
 
         info = mallinfo();
-        pos += sprintf(pos, &quot;STAT arena_size %d\r\n&quot;, info.arena);
-        pos += sprintf(pos, &quot;STAT free_chunks %d\r\n&quot;, info.ordblks);
-        pos += sprintf(pos, &quot;STAT fastbin_blocks %d\r\n&quot;, info.smblks);
-        pos += sprintf(pos, &quot;STAT mmapped_regions %d\r\n&quot;, info.hblks);
-        pos += sprintf(pos, &quot;STAT mmapped_space %d\r\n&quot;, info.hblkhd);
-        pos += sprintf(pos, &quot;STAT max_total_alloc %d\r\n&quot;, info.usmblks);
-        pos += sprintf(pos, &quot;STAT fastbin_space %d\r\n&quot;, info.fsmblks);
-        pos += sprintf(pos, &quot;STAT total_alloc %d\r\n&quot;, info.uordblks);
-        pos += sprintf(pos, &quot;STAT total_free %d\r\n&quot;, info.fordblks);
-        pos += sprintf(pos, &quot;STAT releasable_space %d\r\nEND&quot;, info.keepcost);
+        offset = append_to_buffer(temp, bufsize, offset, sizeof(terminator), &quot;STAT arena_size %d\r\n&quot;, info.arena);
+        offset = append_to_buffer(temp, bufsize, offset, sizeof(terminator), &quot;STAT free_chunks %d\r\n&quot;, info.ordblks);
+        offset = append_to_buffer(temp, bufsize, offset, sizeof(terminator), &quot;STAT fastbin_blocks %d\r\n&quot;, info.smblks);
+        offset = append_to_buffer(temp, bufsize, offset, sizeof(terminator), &quot;STAT mmapped_regions %d\r\n&quot;, info.hblks);
+        offset = append_to_buffer(temp, bufsize, offset, sizeof(terminator), &quot;STAT mmapped_space %d\r\n&quot;, info.hblkhd);
+        offset = append_to_buffer(temp, bufsize, offset, sizeof(terminator), &quot;STAT max_total_alloc %d\r\n&quot;, info.usmblks);
+        offset = append_to_buffer(temp, bufsize, offset, sizeof(terminator), &quot;STAT fastbin_space %d\r\n&quot;, info.fsmblks);
+        offset = append_to_buffer(temp, bufsize, offset, sizeof(terminator), &quot;STAT total_alloc %d\r\n&quot;, info.uordblks);
+        offset = append_to_buffer(temp, bufsize, offset, sizeof(terminator), &quot;STAT total_free %d\r\n&quot;, info.fordblks);
+        offset = append_to_buffer(temp, bufsize, offset, sizeof(terminator), &quot;STAT releasable_space %d\r\n&quot;, info.keepcost);
+        offset = append_to_buffer(temp, bufsize, offset, 0, terminator);
         out_string(c, temp);
         return;
     }</diff>
      <filename>memcached.c</filename>
    </modified>
    <modified>
      <diff>@@ -57,6 +57,12 @@
 # include &lt;unistd.h&gt;
 #endif
 
+#if __WORDSIZE == 64
+#define PRINTF_INT64_MODIFIER &quot;l&quot;
+#else
+#define PRINTF_INT64_MODIFIER &quot;ll&quot;
+#endif
+
 /** Time relative to server start. Smaller than time_t on 64-bit systems. */
 typedef unsigned int rel_time_t;
 </diff>
      <filename>memcached.h</filename>
    </modified>
    <modified>
      <diff>@@ -288,8 +288,9 @@ void do_slabs_free(void *ptr, const size_t size, unsigned int id) {
 /*@null@*/
 char* do_slabs_stats(int *buflen) {
     int i, total;
-    char *buf = (char *)malloc(power_largest * 200 + 100);
-    char *bufcurr = buf;
+    size_t bufsize = power_largest * 1024 + 100, offset = 0;
+    char *buf = (char *)malloc(bufsize);
+    char terminator[] = &quot;END\r\n&quot;;
 
     *buflen = 0;
     if (buf == NULL) return NULL;
@@ -303,19 +304,19 @@ char* do_slabs_stats(int *buflen) {
             slabs = p-&gt;slabs;
             perslab = p-&gt;perslab;
 
-            bufcurr += sprintf(bufcurr, &quot;STAT %d:chunk_size %u\r\n&quot;, i, p-&gt;size);
-            bufcurr += sprintf(bufcurr, &quot;STAT %d:chunks_per_page %u\r\n&quot;, i, perslab);
-            bufcurr += sprintf(bufcurr, &quot;STAT %d:total_pages %u\r\n&quot;, i, slabs);
-            bufcurr += sprintf(bufcurr, &quot;STAT %d:total_chunks %u\r\n&quot;, i, slabs*perslab);
-            bufcurr += sprintf(bufcurr, &quot;STAT %d:used_chunks %u\r\n&quot;, i, slabs*perslab - p-&gt;sl_curr);
-            bufcurr += sprintf(bufcurr, &quot;STAT %d:free_chunks %u\r\n&quot;, i, p-&gt;sl_curr);
-            bufcurr += sprintf(bufcurr, &quot;STAT %d:free_chunks_end %u\r\n&quot;, i, p-&gt;end_page_free);
+            offset = append_to_buffer(buf, bufsize, offset, sizeof(terminator), &quot;STAT %d:chunk_size %u\r\n&quot;, i, p-&gt;size);
+            offset = append_to_buffer(buf, bufsize, offset, sizeof(terminator), &quot;STAT %d:chunks_per_page %u\r\n&quot;, i, perslab);
+            offset = append_to_buffer(buf, bufsize, offset, sizeof(terminator), &quot;STAT %d:total_pages %u\r\n&quot;, i, slabs);
+            offset = append_to_buffer(buf, bufsize, offset, sizeof(terminator), &quot;STAT %d:total_chunks %u\r\n&quot;, i, slabs*perslab);
+            offset = append_to_buffer(buf, bufsize, offset, sizeof(terminator), &quot;STAT %d:used_chunks %u\r\n&quot;, i, slabs * perslab - p-&gt;sl_curr);
+            offset = append_to_buffer(buf, bufsize, offset, sizeof(terminator), &quot;STAT %d:free_chunks %u\r\n&quot;, i, p-&gt;sl_curr);
+            offset = append_to_buffer(buf, bufsize, offset, sizeof(terminator), &quot;STAT %d:free_chunks_end %u\r\n&quot;, i, p-&gt;end_page_free);
             total++;
         }
     }
-    bufcurr += sprintf(bufcurr, &quot;STAT active_slabs %d\r\nSTAT total_malloced %llu\r\n&quot;, total, (unsigned long long)mem_malloced);
-    bufcurr += sprintf(bufcurr, &quot;END\r\n&quot;);
-    *buflen = bufcurr - buf;
+    offset = append_to_buffer(buf, bufsize, offset, sizeof(terminator), &quot;STAT active_slabs %d\r\nSTAT total_malloced %llu\r\n&quot;, total, mem_malloced);
+    offset = append_to_buffer(buf, bufsize, offset, 0, terminator);
+    *buflen = (int) offset;
     return buf;
 }
 </diff>
      <filename>slabs.c</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>314682f7f15d34da1791c24e058a41a17f53fbce</id>
    </parent>
  </parents>
  <author>
    <name>Tony Tung</name>
    <email>ttung@facebook.com</email>
  </author>
  <url>http://github.com/dustin/memcached/commit/d8e7fcb2a62908510eae38fbe36b42352f977b5b</url>
  <id>d8e7fcb2a62908510eae38fbe36b42352f977b5b</id>
  <committed-date>2008-05-16T20:18:52-07:00</committed-date>
  <authored-date>2008-05-16T20:18:52-07:00</authored-date>
  <message>Replace usage of sprintf in stats output with a safer function.</message>
  <tree>ca2c74702e3d6fd9f1c0f925971bda9b771e5c73</tree>
  <committer>
    <name>Dustin Sallings</name>
    <email>dustin@spy.net</email>
  </committer>
</commit>
