Browse Source

ZOOKEEPER-402. zookeeper c library segfaults on data for a node in zookeeper being null

git-svn-id: https://svn.apache.org/repos/asf/hadoop/zookeeper/trunk@777265 13f79535-47bb-0310-9956-ffa450edef68
Patrick D. Hunt 16 years ago
parent
commit
c0500af30f
5 changed files with 50 additions and 6 deletions
  1. 3 0
      CHANGES.txt
  2. 8 5
      src/c/include/zookeeper.h
  3. 11 0
      src/c/src/recordio.c
  4. 7 1
      src/c/src/zookeeper.c
  5. 21 0
      src/c/tests/TestClient.cc

+ 3 - 0
CHANGES.txt

@@ -89,6 +89,9 @@ BUGFIXES:
   ZOOKEEPER-411. Building zookeeper fails on RHEL 5 64 bit during test-cppunit
   (mahadev via phunt)
 
+  ZOOKEEPER-402. zookeeper c library segfaults on data for a node in zookeeper
+  being null. (mahadev via phunt)
+
 IMPROVEMENTS:
   ZOOKEEPER-308. improve the atomic broadcast performance 3x.
   (breed via mahadev)

+ 8 - 5
src/c/include/zookeeper.h

@@ -946,7 +946,8 @@ ZOOAPI void zoo_deterministic_conn_order(int yesOrNo);
  * \param path The name of the node. Expressed as a file name with slashes 
  * separating ancestors of the node.
  * \param value The data to be stored in the node.
- * \param valuelen The number of bytes in data.
+ * \param valuelen The number of bytes in data. To set the data to be NULL use
+  * value as NULL and valuelen as -1.
  * \param acl The initial ACL of the node. If null, the ACL of the parent will be
  *    used.
  * \param flags this parameter can be set to 0 for normal create or an OR
@@ -1047,7 +1048,7 @@ ZOOAPI int zoo_wexists(zhandle_t *zh, const char *path,
  * the client if the node changes.
  * \param buffer the buffer holding the node data returned by the server
  * \param buffer_len is the size of the buffer pointed to by the buffer parameter.
- * It'll be set to the actual data length upon return.
+ * It'll be set to the actual data length upon return. If the data is NULL, length is -1.
  * \param stat if not NULL, will hold the value of stat for the path on return.
  * \return return value of the function call.
  * ZOK operation completed succesfully
@@ -1076,7 +1077,7 @@ ZOOAPI int zoo_get(zhandle_t *zh, const char *path, int watch, char *buffer,
  * is associated with the given instance of the watcher only.
  * \param buffer the buffer holding the node data returned by the server
  * \param buffer_len is the size of the buffer pointed to by the buffer parameter.
- * It'll be set to the actual data length upon return.
+ * It'll be set to the actual data length upon return. If the data is NULL, length is -1.
  * \param stat if not NULL, will hold the value of stat for the path on return.
  * \return return value of the function call.
  * ZOK operation completed succesfully
@@ -1098,7 +1099,8 @@ ZOOAPI int zoo_wget(zhandle_t *zh, const char *path,
  * \param path the name of the node. Expressed as a file name with slashes 
  * separating ancestors of the node.
  * \param buffer the buffer holding data to be written to the node.
- * \param buflen the number of bytes from buffer to write.
+ * \param buflen the number of bytes from buffer to write. To set NULL as data 
+ * use buffer as NULL and buflen as -1.
  * \param version the expected version of the node. The function will fail if 
  * the actual version of the node does not match the expected version. If -1 is 
  * used the version check will not take place. 
@@ -1123,7 +1125,8 @@ ZOOAPI int zoo_set(zhandle_t *zh, const char *path, const char *buffer,
  * \param path the name of the node. Expressed as a file name with slashes 
  * separating ancestors of the node.
  * \param buffer the buffer holding data to be written to the node.
- * \param buflen the number of bytes from buffer to write.
+ * \param buflen the number of bytes from buffer to write. To set NULL as data
+ * use buffer as NULL and buflen as -1.
  * \param version the expected version of the node. The function will fail if 
  * the actual version of the node does not match the expected version. If -1 is 
  * used the version check will not take place. 

+ 11 - 0
src/c/src/recordio.c

@@ -139,6 +139,12 @@ int oa_serialize_buffer(struct oarchive *oa, const char *name,
     rc = oa_serialize_int(oa, "len", &b->len);
     if (rc < 0)
         return rc;
+    // this means a buffer of NUll 
+    // with size of -1. This is 
+    // waht we use in java serialization for NULL
+    if (b->len == -1) {
+      return rc;
+    }
     if ((priv->len - priv->off) < b->len) {
         rc = resize_buffer(priv, priv->len + b->len);
         if (rc < 0)
@@ -234,6 +240,11 @@ int ia_deserialize_buffer(struct iarchive *ia, const char *name,
     if ((priv->len - priv->off) < b->len) {
         return -E2BIG;
     }
+    // set the buffer to null
+    if (b->len == -1) {
+       b->buff = NULL;
+       return rc;
+    }
     b->buff = malloc(b->len);
     if (!b->buff) {
         return -ENOMEM;

+ 7 - 1
src/c/src/zookeeper.c

@@ -1629,7 +1629,13 @@ int zookeeper_process(zhandle_t *zh, int events)
                             len = sc->u.data.buff_len;
                         }
                         sc->u.data.buff_len = len;
-                        memcpy(sc->u.data.buffer, res.data.buff, len);
+                        // check if len is negative 
+                        // just of NULL which is -1 int 
+                        if (len == -1) {
+                            sc->u.data.buffer = NULL;
+                        } else {
+                            memcpy(sc->u.data.buffer, res.data.buff, len);
+                        }
                         sc->u.data.stat = res.stat;
                         deallocate_GetDataResponse(&res);
                     }

+ 21 - 0
src/c/tests/TestClient.cc

@@ -157,6 +157,7 @@ class Zookeeper_simpleSystem : public CPPUNIT_NS::TestFixture
     CPPUNIT_TEST_SUITE(Zookeeper_simpleSystem);
     CPPUNIT_TEST(testAsyncWatcherAutoReset);
 #ifdef THREADED
+    CPPUNIT_TEST(testNullData);
     CPPUNIT_TEST(testPathValidation);
     CPPUNIT_TEST(testPing);
     CPPUNIT_TEST(testAcl);
@@ -402,6 +403,26 @@ public:
         CPPUNIT_ASSERT_EQUAL((int)ZOK, rc);
     }
 
+    void testNullData() {
+        watchctx_t ctx;
+        zhandle_t *zk = createClient(&ctx);
+        CPPUNIT_ASSERT(zk);
+        int rc = 0;
+        rc = zoo_create(zk, "/mahadev", NULL, -1, 
+                        &ZOO_OPEN_ACL_UNSAFE, 0, 0, 0);
+        CPPUNIT_ASSERT_EQUAL((int) ZOK, rc);
+        char buffer[512];
+        struct Stat stat;
+        int len = 512;
+        rc = zoo_wget(zk, "/mahadev", NULL, NULL, buffer, &len, &stat);
+        CPPUNIT_ASSERT_EQUAL( -1, len);
+        CPPUNIT_ASSERT_EQUAL((int) ZOK, rc);
+        rc = zoo_set(zk, "/mahadev", NULL, -1, -1);
+        CPPUNIT_ASSERT_EQUAL((int) ZOK, rc);
+        rc = zoo_wget(zk, "/mahadev", NULL, NULL, buffer, &len, &stat);
+        CPPUNIT_ASSERT_EQUAL( -1, len);
+        CPPUNIT_ASSERT_EQUAL((int) ZOK, rc);
+    }
 
     void testPathValidation() {
         watchctx_t ctx;