save
authorOlivier Matz <zer0@droids-corp.org>
Sun, 26 Nov 2017 21:29:59 +0000 (22:29 +0100)
committerOlivier Matz <zer0@droids-corp.org>
Sun, 26 Nov 2017 21:29:59 +0000 (22:29 +0100)
lib/ecoli_init.h
lib/ecoli_keyval.c
lib/ecoli_malloc.c
lib/ecoli_malloc.h
lib/main-readline.c
lib/main.c
lib/test.sh

index 9166cdc..b70e4dc 100644 (file)
@@ -68,7 +68,8 @@ void ec_init_register(struct ec_init *test);
 /**
  * Initialize ecoli library
  *
- * Must be called before any other function.
+ * Must be called before any other function from libecoli, except
+ * ec_malloc_register().
  *
  * @return
  *   0 on success, -1 on error (errno is set).
index 9baba5f..dbc5522 100644 (file)
@@ -323,7 +323,7 @@ static int ec_keyval_testcase(void)
        EC_TEST_ASSERT(ec_keyval_len(keyval) == 0);
        ret = ec_keyval_set(keyval, "key1", "val1", NULL);
        EC_TEST_ASSERT_STR(ret == 0, "cannot set key");
-       ret = ec_keyval_set(keyval, "key2", ec_strdup("val2"), ec_free2);
+       ret = ec_keyval_set(keyval, "key2", ec_strdup("val2"), ec_free_func);
        EC_TEST_ASSERT_STR(ret == 0, "cannot set key");
        EC_TEST_ASSERT(ec_keyval_len(keyval) == 2);
 
@@ -336,7 +336,8 @@ static int ec_keyval_testcase(void)
 
        ret = ec_keyval_set(keyval, "key1", "another_val1", NULL);
        EC_TEST_ASSERT_STR(ret == 0, "cannot set key");
-       ret = ec_keyval_set(keyval, "key2", ec_strdup("another_val2"), ec_free2);
+       ret = ec_keyval_set(keyval, "key2", ec_strdup("another_val2"),
+                       ec_free_func);
        EC_TEST_ASSERT_STR(ret == 0, "cannot set key");
        EC_TEST_ASSERT(ec_keyval_len(keyval) == 2);
 
@@ -359,6 +360,13 @@ static int ec_keyval_testcase(void)
                ret = ec_keyval_set(keyval, buf, "val", NULL);
                EC_TEST_ASSERT_STR(ret == 0, "cannot set key");
        }
+
+       /* einval */
+       ret = ec_keyval_set(keyval, NULL, "val1", NULL);
+       EC_TEST_ASSERT(ret == -1);
+       val = ec_keyval_get(keyval, NULL);
+       EC_TEST_ASSERT(val == NULL);
+
        ec_keyval_free(keyval);
 
 
index 7c6f489..3113f0e 100644 (file)
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-
+#include <ecoli_init.h>
 #include <ecoli_malloc.h>
 
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
 
+static int init_done = 0;
+
 struct ec_malloc_handler ec_malloc_handler;
 
 int ec_malloc_register(ec_malloc_t usr_malloc, ec_free_t usr_free,
        ec_realloc_t usr_realloc)
 {
-       if (usr_malloc == NULL || usr_free == NULL || usr_realloc == NULL)
+       if (usr_malloc == NULL || usr_free == NULL || usr_realloc == NULL) {
+               errno = EINVAL;
+               return -1;
+       }
+
+       if (init_done) {
+               errno = EBUSY;
                return -1;
+       }
 
        ec_malloc_handler.malloc = usr_malloc;
        ec_malloc_handler.free = usr_free;
@@ -47,20 +56,12 @@ int ec_malloc_register(ec_malloc_t usr_malloc, ec_free_t usr_free,
        return 0;
 }
 
-void ec_malloc_unregister(void)
-{
-       /* XXX handlers must set errno on error */
-       ec_malloc_handler.malloc = NULL;
-       ec_malloc_handler.free = NULL;
-       ec_malloc_handler.realloc = NULL;
-}
-
 void *__ec_malloc(size_t size, const char *file, unsigned int line)
 {
        return ec_malloc_handler.malloc(size, file, line);
 }
 
-void *ec_malloc2(size_t size)
+void *ec_malloc_func(size_t size)
 {
        return __ec_malloc(size, __FILE__, __LINE__);
 }
@@ -70,7 +71,7 @@ void __ec_free(void *ptr, const char *file, unsigned int line)
        ec_malloc_handler.free(ptr, file, line);
 }
 
-void ec_free2(void *ptr)
+void ec_free_func(void *ptr)
 {
        __ec_free(ptr, __FILE__, __LINE__);
 }
@@ -129,3 +130,16 @@ char *__ec_strndup(const char *s, size_t n, const char *file, unsigned int line)
 
        return s2;
 }
+
+static int ec_malloc_init_func(void)
+{
+       init_done = 1;
+       return 0;
+}
+
+static struct ec_init ec_malloc_init = {
+       .init = ec_malloc_init_func,
+       .priority = 50,
+};
+
+EC_INIT_REGISTER(ec_malloc_init);
index 76b63e0..748601a 100644 (file)
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+/**
+ * Interface to configure the allocator used by libecoli.
+ * By default, the standard allocation functions from libc are used.
+ */
+
 #ifndef ECOLI_MALLOC_
 #define ECOLI_MALLOC_
 
 #include <stdlib.h>
 #include <string.h>
 
+/**
+ * Function type of malloc, passed to ec_malloc_register().
+ *
+ * The API is the same than malloc(), excepted the file and line
+ * arguments.
+ *
+ * @param size
+ *   The size of the memory area to allocate.
+ * @param file
+ *   The path to the file that invoked the malloc.
+ * @param line
+ *   The line in the file that invoked the malloc.
+ * @return
+ *   A pointer to the allocated memory area, or NULL on error (errno
+ *   is set).
+ */
 typedef void *(*ec_malloc_t)(size_t size, const char *file, unsigned int line);
+
+/**
+ * Function type of free, passed to ec_malloc_register().
+ *
+ * The API is the same than free(), excepted the file and line
+ * arguments.
+ *
+ * @param ptr
+ *   The pointer to the memory area to be freed.
+ * @param file
+ *   The path to the file that invoked the malloc.
+ * @param line
+ *   The line in the file that invoked the malloc.
+ */
 typedef void (*ec_free_t)(void *ptr, const char *file, unsigned int line);
+
+/**
+ * Function type of realloc, passed to ec_malloc_register().
+ *
+ * The API is the same than realloc(), excepted the file and line
+ * arguments.
+ *
+ * @param ptr
+ *   The pointer to the memory area to be reallocated.
+ * @param file
+ *   The path to the file that invoked the malloc.
+ * @param line
+ *   The line in the file that invoked the malloc.
+ * @return
+ *   A pointer to the allocated memory area, or NULL on error (errno
+ *   is set).
+ */
 typedef void *(*ec_realloc_t)(void *ptr, size_t size, const char *file,
        unsigned int line);
 
+/**
+ * Register allocation functions.
+ *
+ * This function can be use to register another allocator
+ * to be used by libecoli. By default, ec_malloc(), ec_free() and
+ * ec_realloc() use the standard libc allocator. Another handler
+ * can be used for debug purposes or when running in a specific
+ * environment.
+ *
+ * This function must be called before ec_init().
+ *
+ * @param usr_malloc
+ *   A user-defined malloc function.
+ * @param usr_free
+ *   A user-defined free function.
+ * @param usr_realloc
+ *   A user-defined realloc function.
+ * @return
+ *   0 on success, or -1 on error (errno is set).
+ */
+int ec_malloc_register(ec_malloc_t usr_malloc, ec_free_t usr_free,
+       ec_realloc_t usr_realloc);
+
 struct ec_malloc_handler {
        ec_malloc_t malloc;
        ec_free_t free;
@@ -45,36 +120,44 @@ struct ec_malloc_handler {
 
 extern struct ec_malloc_handler ec_malloc_handler;
 
-int ec_malloc_register(ec_malloc_t usr_malloc, ec_free_t usr_free,
-       ec_realloc_t usr_realloc);
-void ec_malloc_unregister(void);
-
-/* internal */
-void *__ec_malloc(size_t size, const char *file, unsigned int line);
-void __ec_free(void *ptr, const char *file, unsigned int line);
-void *__ec_calloc(size_t nmemb, size_t size, const char *file,
-       unsigned int line);
-void *__ec_realloc(void *ptr, size_t size, const char *file, unsigned int line);
-char *__ec_strdup(const char *s, const char *file, unsigned int line);
-char *__ec_strndup(const char *s, size_t n, const char *file,
-       unsigned int line);
-
-/* XXX rename into ec_malloc, and change macro to uppercase */
-void *ec_malloc2(size_t size);
-void ec_free2(void *ptr);
-
-/* we use macros here to ensure the file/line stay correct when
- * debugging the standard malloc with valgrind */
-
-#define ec_malloc(sz) ({                                               \
+/**
+ * Allocate a memory area.
+ *
+ * Like malloc(), ec_malloc() allocates size bytes and returns a pointer
+ * to the allocated memory. The memory is not initialized. The memory is
+ * freed with ec_free().
+ *
+ * @param size
+ *   The size of the area to allocate in bytes.
+ * @return
+ *   The pointer to the allocated memory, or NULL on error (errno is set).
+ */
+#define ec_malloc(size) ({                                             \
        void *ret_;                                                     \
        if (ec_malloc_handler.malloc == NULL)                           \
-               ret_ = malloc(sz);                                      \
+               ret_ = malloc(size);                                    \
        else                                                            \
-               ret_ = __ec_malloc(sz, __FILE__, __LINE__);             \
+               ret_ = __ec_malloc(size, __FILE__, __LINE__);           \
        ret_;                                                           \
        })
 
+/**
+ * Ecoli malloc function.
+ *
+ * On use this function when the macro ec_malloc() cannot be used.
+ */
+void *ec_malloc_func(size_t size);
+
+/**
+ * Free a memory area.
+ *
+ * Like free(), ec_free() frees the area pointed by ptr, which must have
+ * been returned by a previous call to ec_malloc() or any other
+ * allocation function of this file.
+ *
+ * @param ptr
+ *   The pointer to the memory area.
+ */
 #define ec_free(ptr) ({                                                        \
        if (ec_malloc_handler.free == NULL)                             \
                free(ptr);                                              \
@@ -82,24 +165,63 @@ void ec_free2(void *ptr);
                __ec_free(ptr, __FILE__, __LINE__);                     \
        })
 
-#define ec_realloc(ptr, sz) ({                                         \
+/**
+ * Ecoli free function.
+ *
+ * On use this function when the macro ec_free() cannot be used.
+ */
+void ec_free_func(void *ptr);
+
+/**
+ * Resize an allocated memory area.
+ *
+ * @param ptr
+ *   The pointer to the previously allocated memory area, or NULL.
+ * @param size
+ *   The new size of the memory area.
+ * @return
+ *   A pointer to the newly allocated memory, or NULL if the request
+ *   fails. In that case, the original area is left untouched.
+ */
+#define ec_realloc(ptr, size) ({                                       \
        void *ret_;                                                     \
        if (ec_malloc_handler.realloc == NULL)                          \
-               ret_ = realloc(ptr, sz);                                \
+               ret_ = realloc(ptr, size);                              \
        else                                                            \
-               ret_ = __ec_realloc(ptr, sz, __FILE__, __LINE__);       \
+               ret_ = __ec_realloc(ptr, size, __FILE__, __LINE__);     \
        ret_;                                                           \
        })
 
-#define ec_calloc(n, sz) ({                                            \
+/**
+ * Allocate and initialize an array of elements.
+ *
+ * @param n
+ *   The number of elements.
+ * @param size
+ *   The size of each element.
+ * @return
+ *   The pointer to the allocated memory, or NULL on error (errno is set).
+ */
+#define ec_calloc(n, size) ({                                          \
        void *ret_;                                                     \
        if (ec_malloc_handler.malloc == NULL)                           \
-               ret_ = calloc(n, sz);                                   \
+               ret_ = calloc(n, size);                                 \
        else                                                            \
-               ret_ = __ec_calloc(n, sz, __FILE__, __LINE__);          \
+               ret_ = __ec_calloc(n, size, __FILE__, __LINE__);        \
        ret_;                                                           \
        })
 
+/**
+ * Duplicate a string.
+ *
+ * Memory for the new string is obtained with ec_malloc(), and can be
+ * freed with ec_free().
+ *
+ * @param s
+ *   The string to be duplicated.
+ * @return
+ *   The pointer to the duplicated string, or NULL on error (errno is set).
+ */
 #define ec_strdup(s) ({                                                        \
        void *ret_;                                                     \
        if (ec_malloc_handler.malloc == NULL)                           \
@@ -109,6 +231,20 @@ void ec_free2(void *ptr);
        ret_;                                                           \
        })
 
+/**
+ * Duplicate at most n bytes of a string.
+ *
+ * This function is similar to ec_strdup(), except that it copies at
+ * most n bytes.  If s is longer than n, only n bytes are copied, and a
+ * terminating null byte ('\0') is added.
+ *
+ * @param s
+ *   The string to be duplicated.
+ * @param n
+ *   The maximum length of the new string.
+ * @return
+ *   The pointer to the duplicated string, or NULL on error (errno is set).
+ */
 #define ec_strndup(s, n) ({                                            \
        void *ret_;                                                     \
        if (ec_malloc_handler.malloc == NULL)                           \
@@ -118,5 +254,15 @@ void ec_free2(void *ptr);
        ret_;                                                           \
        })
 
+/* internal */
+void *__ec_malloc(size_t size, const char *file, unsigned int line);
+void __ec_free(void *ptr, const char *file, unsigned int line);
+void *__ec_calloc(size_t nmemb, size_t size, const char *file,
+       unsigned int line);
+void *__ec_realloc(void *ptr, size_t size, const char *file, unsigned int line);
+char *__ec_strdup(const char *s, const char *file, unsigned int line);
+char *__ec_strndup(const char *s, size_t n, const char *file,
+       unsigned int line);
+
 
 #endif
index 80ef88d..87653f7 100644 (file)
@@ -260,7 +260,7 @@ static int create_commands(void)
        ec_keyval_set(ec_node_attrs(ec_node_find(cmd, "name")), "help",
                "the person to greet", NULL);
        ec_keyval_set(ec_node_attrs(ec_node_find(cmd, "count")), "help",
-               "how many times to greet", NULL);
+               "how many times to greet (0-10)", NULL);
        if (ec_node_or_add(cmdlist, cmd) < 0)
                goto fail;
 
index b44a47d..4a48d1e 100644 (file)
@@ -386,12 +386,6 @@ int main(int argc, char **argv)
 
        srandom(seed);
 
-       if (ec_init() < 0) {
-               fprintf(stderr, "cannot init ecoli: %s\n", strerror(errno));
-               return 1;
-       }
-       ec_log_fct_register(debug_log, NULL);
-
        /* register a new malloc to track memleaks */
        TAILQ_INIT(&debug_alloc_hdr_list);
        if (ec_malloc_register(debug_malloc, debug_free, debug_realloc) < 0) {
@@ -399,6 +393,12 @@ int main(int argc, char **argv)
                return 1;
        }
 
+       if (ec_init() < 0) {
+               fprintf(stderr, "cannot init ecoli: %s\n", strerror(errno));
+               return 1;
+       }
+       ec_log_fct_register(debug_log, NULL);
+
        ret = 0;
        if (argc <= 1) {
                ret = ec_test_all();
@@ -407,7 +407,6 @@ int main(int argc, char **argv)
                        ret |= ec_test_one(argv[i]);
        }
 
-       ec_malloc_unregister();
        leaks = debug_alloc_dump_leaks();
 
        if (alloc_fail_proba == 0 && ret != 0) {
index 3d97e77..9d78a68 100755 (executable)
@@ -4,7 +4,7 @@ set -e
 
 SEED=100
 while [ ${SEED} -gt 0 ]; do
-       CMD="./build/test --random-alloc-fail=1 --seed=${SEED}"
+       CMD="./build/test --random-alloc-fail=1 --seed=${SEED} $*"
        ${CMD} --log-level=0 || (
                echo "=== test failed, replay seed=${SEED} with logs ===" &&
                ${CMD} --log-level=6 ||