From: Justin Cinkelj <justin.cink...@xlab.si>
Committer: Nadav Har'El <n...@scylladb.com>
Branch: master

calloc: allow 0-sized allocation

The calloc(nmemb, size=0) failed due to division by 0 in
"std::numeric_limits<size_t>::max() / size".
Fix this by checking for 0 value before division.

Included is also a small test case for calloc.

Signed-off-by: Justin Cinkelj <justin.cink...@xlab.si>
Message-Id: <20170615061205.16074-1-justin.cink...@xlab.si>

---
diff --git a/core/mempool.cc b/core/mempool.cc
--- a/core/mempool.cc
+++ b/core/mempool.cc
@@ -1564,6 +1564,8 @@ static inline void* std_malloc(size_t size, size_t alignment)

 void* calloc(size_t nmemb, size_t size)
 {
+    if (nmemb == 0 || size == 0)
+        return malloc(0);
     if (nmemb > std::numeric_limits<size_t>::max() / size)
         return nullptr;
     auto n = nmemb * size;
diff --git a/modules/tests/Makefile b/modules/tests/Makefile
--- a/modules/tests/Makefile
+++ b/modules/tests/Makefile
@@ -86,7 +86,8 @@ tests := tst-pthread.so misc-ramdisk.so tst-vblk.so tst-bsd-evh.so \
        tst-pthread-setcancelstate.so tst-syscall.so tst-pin.so tst-run.so \
        tst-ifaddrs.so tst-pthread-affinity-inherit.so tst-sem-timed-wait.so \
        tst-ttyname.so tst-pthread-barrier.so tst-feexcept.so tst-math.so \
-       tst-sigaltstack.so tst-fread.so tst-tcp-cork.so tst-tcp-v6.so
+       tst-sigaltstack.so tst-fread.so tst-tcp-cork.so tst-tcp-v6.so \
+       tst-calloc.so

 #      libstatic-thread-variable.so tst-static-thread-variable.so \

diff --git a/tests/tst-calloc.cc b/tests/tst-calloc.cc
--- a/tests/tst-calloc.cc
+++ b/tests/tst-calloc.cc
@@ -0,0 +1,67 @@
+/*
+* Copyright (C) 2017 XLAB d.o.o.
+*
+* This work is open source software, licensed under the terms of the
+* BSD license as described in the LICENSE file in the top-level directory.
+*/
+// To compile on Linux, use: g++ -g -pthread -std=c++11 tests/tst-calloc.cc
+
+#include <string.h>
+#include <iostream>
+
+// This test assures that the calloc function works as expected in the various
+// situations it can be used at.
+void pass_if(const char *got, const char *expected, int size, const char* msg)
+{
+    if (memcmp(expected, got, size)) {
+        std::cerr << "FAIL: " << msg << "\n";
+        std::cerr << "ERROR: got ";
+        std::cerr << got;
+        std::cerr << " but expected ";
+        std::cerr << expected;
+        std::cerr << "\n";
+        exit(1);
+    }
+    else {
+        std::cerr << "PASS: " << msg << "\n";
+    }
+}
+
+int main()
+{
+    char *buf1;
+    const char ref0[11] = "\0";
+    const char refX[11] = "XXXXXXXXXX";
+    int len1, len2;
+
+    len1 = 1;
+    len2 = 10;
+    buf1 = (char*)calloc(len1, len2);
+    pass_if(buf1, ref0, len1 * len2, "calloc(1, 10)");
+    memset(buf1, 'X', len1 * len2);
+    free(buf1);
+
+    len1 = 2;
+    len2 = 5;
+    buf1 = (char*)calloc(len1, len2);
+    pass_if(buf1, ref0, len1 * len2, "calloc(2, 5)");
+    memset(buf1, 'X', len1 * len2);
+    free(buf1);
+
+    len1 = 1;
+    len2 = 0;
+    buf1 = (char*)calloc(len1, len2);
+    pass_if(buf1, ref0, len1 * len2, "calloc(1, 0)");
+    //memset(buf1, 'X', len1 * len2);
+    free(buf1);
+
+    len1 = 0;
+    len2 = 1;
+    buf1 = (char*)calloc(len1, len2);
+    pass_if(buf1, ref0, len1 * len2, "calloc(0, 1)");
+    memset(buf1, 'X', len1 * len2);
+    free(buf1);
+
+    std::cerr << "PASSED\n";
+    return 0;
+}

--
You received this message because you are subscribed to the Google Groups "OSv 
Development" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to osv-dev+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to