{"thread":{"id":"54041","subject":"[PATCH 0/3] Extend and add a little more generalization to the mem_pool API","startedAt":"2020-08-14T03:02:20Z","lastAt":"2020-08-18T19:27:08Z","messageCount":17,"participants":["Elijah Newren via GitGitGadget","Matheus Tavares Bernardino","Junio C Hamano","Eric Sunshine","René Scharfe"],"isPatch":true,"patchVersion":1,"patchTotal":3},"messages":[{"id":"403617","messageId":"pull.830.git.git.1597374135.gitgitgadget@gmail.com","threadId":"54041","inReplyTo":null,"subject":"[PATCH 0/3] Extend and add a little more generalization to the mem_pool API","fromName":"Elijah Newren via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2020-08-14T03:02:12Z","receivedAt":"2020-08-14T03:02:20Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"In my new merge algorithm, I made use of the mem_pool API in a few\nplaces...but I also needed to add a few more functions. More importantly,\nthough, I couldn't reuse the existing API as-is since I want to be able to\ndiscard the memory (after each recursive merge) and then continue adding to\nthe pool, something the existing API was not amenable to. Instead of writing\nanother competing API, since there is only one other user, I just modified\nthe existing callsites to use the more generic calling structure that I\nneeded.\n\nUnfortunately, Matheus' parallel-checkout RFC series (not yet in next or\nseen as far as I can tell) adds a few more mem_pool callers, so this series\nconflicts with his (semantically). I can rebuild mine on top of his, or,\nsince his is longer and would probably advance more slowly, it may make\nsense to have his series be based on this one. If so, I'm happy to help him\nupdate his to depend on this series. Let me know preferences.\n\nElijah Newren (3):\n  mem-pool: add convenience functions for xstrdup and xstrndup\n  mem-pool: use more standard initialization and finalization\n  mem-pool: use consistent pool variable name\n\n fast-import.c | 12 ++-------\n mem-pool.c    | 75 ++++++++++++++++++++++++++++++++-------------------\n mem-pool.h    | 14 +++++++---\n read-cache.c  | 21 +++++++++------\n split-index.c |  6 +++--\n 5 files changed, 76 insertions(+), 52 deletions(-)\n\n\nbase-commit: 7814e8a05a59c0cf5fb186661d1551c75d1299b5\nPublished-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-830%2Fnewren%2Fmem_pool_api-v1\nFetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-830/newren/mem_pool_api-v1\nPull-Request: https://github.com/git/git/pull/830\n-- \ngitgitgadget\n"},{"id":"403618","messageId":"eae8b2923f7834f3b1d030f6eb4dc093b94da91b.1597374135.git.gitgitgadget@gmail.com","threadId":"54041","inReplyTo":"pull.830.git.git.1597374135.gitgitgadget@gmail.com","subject":"[PATCH 1/3] mem-pool: add convenience functions for xstrdup and xstrndup","fromName":"Elijah Newren via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2020-08-14T03:02:13Z","receivedAt":"2020-08-14T03:02:21Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"From: Elijah Newren <newren@gmail.com>\n\nfast-import had a special mem_pool_xstrdup() convenience function that I\nwant to be able to use from the new merge algorithm I am writing.  Move\nit from fast-import to mem-pool, and also add a mem_pool_xstrndup()\nwhile at it that I also want to use.\n\nSigned-off-by: Elijah Newren <newren@gmail.com>\n---\n fast-import.c | 12 ++----------\n mem-pool.c    | 23 +++++++++++++++++++++++\n mem-pool.h    |  6 ++++++\n 3 files changed, 31 insertions(+), 10 deletions(-)\n\ndiff --git a/fast-import.c b/fast-import.c\nindex ce47794db6..dd5b563950 100644\n--- a/fast-import.c\n+++ b/fast-import.c\n@@ -526,14 +526,6 @@ static unsigned int hc_str(const char *s, size_t len)\n \treturn r;\n }\n \n-static char *pool_strdup(const char *s)\n-{\n-\tsize_t len = strlen(s) + 1;\n-\tchar *r = mem_pool_alloc(&fi_mem_pool, len);\n-\tmemcpy(r, s, len);\n-\treturn r;\n-}\n-\n static void insert_mark(struct mark_set *s, uintmax_t idnum, struct object_entry *oe)\n {\n \twhile ((idnum >> s->shift) >= 1024) {\n@@ -615,7 +607,7 @@ static struct branch *new_branch(const char *name)\n \t\tdie(\"Branch name doesn't conform to GIT standards: %s\", name);\n \n \tb = mem_pool_calloc(&fi_mem_pool, 1, sizeof(struct branch));\n-\tb->name = pool_strdup(name);\n+\tb->name = mem_pool_xstrdup(&fi_mem_pool, name);\n \tb->table_next_branch = branch_table[hc];\n \tb->branch_tree.versions[0].mode = S_IFDIR;\n \tb->branch_tree.versions[1].mode = S_IFDIR;\n@@ -2806,7 +2798,7 @@ static void parse_new_tag(const char *arg)\n \n \tt = mem_pool_alloc(&fi_mem_pool, sizeof(struct tag));\n \tmemset(t, 0, sizeof(struct tag));\n-\tt->name = pool_strdup(arg);\n+\tt->name = mem_pool_xstrdup(&fi_mem_pool, arg);\n \tif (last_tag)\n \t\tlast_tag->next_tag = t;\n \telse\ndiff --git a/mem-pool.c b/mem-pool.c\nindex a2841a4a9a..3a8c54d9df 100644\n--- a/mem-pool.c\n+++ b/mem-pool.c\n@@ -102,6 +102,29 @@ void *mem_pool_calloc(struct mem_pool *mem_pool, size_t count, size_t size)\n \treturn r;\n }\n \n+char *mem_pool_xstrdup(struct mem_pool *pool, const char *str)\n+{\n+\tsize_t len = strlen(str) + 1;\n+\tchar *ret = mem_pool_alloc(pool, len);\n+\n+\tif (!ret)\n+\t\tdie(\"Out of memory, mem_pool_xstrdup failed\");\n+\n+\treturn memcpy(ret, str, len);\n+}\n+\n+char *mem_pool_xstrndup(struct mem_pool *pool, const char *str, size_t len)\n+{\n+\tsize_t minlen = strnlen(str, len);\n+\tchar *ret = mem_pool_alloc(pool, minlen+1);\n+\n+\tif (!ret)\n+\t\tdie(\"Out of memory, mem_pool_xstrndup failed\");\n+\n+\tret[minlen] = '\\0';\n+\treturn memcpy(ret, str, minlen);\n+}\n+\n int mem_pool_contains(struct mem_pool *mem_pool, void *mem)\n {\n \tstruct mp_block *p;\ndiff --git a/mem-pool.h b/mem-pool.h\nindex 999d3c3a52..fcaa2d462b 100644\n--- a/mem-pool.h\n+++ b/mem-pool.h\n@@ -41,6 +41,12 @@ void *mem_pool_alloc(struct mem_pool *pool, size_t len);\n  */\n void *mem_pool_calloc(struct mem_pool *pool, size_t count, size_t size);\n \n+/*\n+ * Allocate memory from the memory pool and copy str into it.\n+ */\n+char *mem_pool_xstrdup(struct mem_pool *pool, const char *str);\n+char *mem_pool_xstrndup(struct mem_pool *pool, const char *str, size_t len);\n+\n /*\n  * Move the memory associated with the 'src' pool to the 'dst' pool. The 'src'\n  * pool will be empty and not contain any memory. It still needs to be free'd\n-- \ngitgitgadget\n\n"},{"id":"403619","messageId":"62c2479fe6068f31c3cae1b1a13d67527121a15b.1597374135.git.gitgitgadget@gmail.com","threadId":"54041","inReplyTo":"pull.830.git.git.1597374135.gitgitgadget@gmail.com","subject":"[PATCH 3/3] mem-pool: use consistent pool variable name","fromName":"Elijah Newren via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2020-08-14T03:02:15Z","receivedAt":"2020-08-14T03:02:23Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"From: Elijah Newren <newren@gmail.com>\n\nAbout half the function declarations in mem-pool.h used 'struct mem_pool\n*pool', while the other half used 'struct mem_pool *mem_pool'.  Make the\ncode a bit more consistent by just using 'pool' in preference to\n'mem_pool' everywhere.\n\nNo behavioral changes included; this is just a mechanical rename (though\na line or two was rewrapped as well).\n\nSigned-off-by: Elijah Newren <newren@gmail.com>\n---\n mem-pool.c | 50 ++++++++++++++++++++++++++------------------------\n mem-pool.h |  6 +++---\n 2 files changed, 29 insertions(+), 27 deletions(-)\n\ndiff --git a/mem-pool.c b/mem-pool.c\nindex b7d789823e..08039ed069 100644\n--- a/mem-pool.c\n+++ b/mem-pool.c\n@@ -12,11 +12,13 @@\n  * `insert_after`. If `insert_after` is NULL, then insert block at the\n  * head of the linked list.\n  */\n-static struct mp_block *mem_pool_alloc_block(struct mem_pool *mem_pool, size_t block_alloc, struct mp_block *insert_after)\n+static struct mp_block *mem_pool_alloc_block(struct mem_pool *pool,\n+\t\t\t\t\t     size_t block_alloc,\n+\t\t\t\t\t     struct mp_block *insert_after)\n {\n \tstruct mp_block *p;\n \n-\tmem_pool->pool_alloc += sizeof(struct mp_block) + block_alloc;\n+\tpool->pool_alloc += sizeof(struct mp_block) + block_alloc;\n \tp = xmalloc(st_add(sizeof(struct mp_block), block_alloc));\n \n \tp->next_free = (char *)p->space;\n@@ -26,28 +28,28 @@ static struct mp_block *mem_pool_alloc_block(struct mem_pool *mem_pool, size_t b\n \t\tp->next_block = insert_after->next_block;\n \t\tinsert_after->next_block = p;\n \t} else {\n-\t\tp->next_block = mem_pool->mp_block;\n-\t\tmem_pool->mp_block = p;\n+\t\tp->next_block = pool->mp_block;\n+\t\tpool->mp_block = p;\n \t}\n \n \treturn p;\n }\n \n-void mem_pool_init(struct mem_pool *mem_pool, size_t initial_size)\n+void mem_pool_init(struct mem_pool *pool, size_t initial_size)\n {\n-\tmem_pool->mp_block = NULL;\n-\tmem_pool->pool_alloc = 0;\n-\tmem_pool->block_alloc = BLOCK_GROWTH_SIZE;\n+\tpool->mp_block = NULL;\n+\tpool->pool_alloc = 0;\n+\tpool->block_alloc = BLOCK_GROWTH_SIZE;\n \n \tif (initial_size > 0)\n-\t\tmem_pool_alloc_block(mem_pool, initial_size, NULL);\n+\t\tmem_pool_alloc_block(pool, initial_size, NULL);\n }\n \n-void mem_pool_discard(struct mem_pool *mem_pool, int invalidate_memory)\n+void mem_pool_discard(struct mem_pool *pool, int invalidate_memory)\n {\n \tstruct mp_block *block, *block_to_free;\n \n-\tblock = mem_pool->mp_block;\n+\tblock = pool->mp_block;\n \twhile (block)\n \t{\n \t\tblock_to_free = block;\n@@ -59,11 +61,11 @@ void mem_pool_discard(struct mem_pool *mem_pool, int invalidate_memory)\n \t\tfree(block_to_free);\n \t}\n \n-\tmem_pool->mp_block = NULL;\n-\tmem_pool->pool_alloc = 0;\n+\tpool->mp_block = NULL;\n+\tpool->pool_alloc = 0;\n }\n \n-void *mem_pool_alloc(struct mem_pool *mem_pool, size_t len)\n+void *mem_pool_alloc(struct mem_pool *pool, size_t len)\n {\n \tstruct mp_block *p = NULL;\n \tvoid *r;\n@@ -72,15 +74,15 @@ void *mem_pool_alloc(struct mem_pool *mem_pool, size_t len)\n \tif (len & (sizeof(uintmax_t) - 1))\n \t\tlen += sizeof(uintmax_t) - (len & (sizeof(uintmax_t) - 1));\n \n-\tif (mem_pool->mp_block &&\n-\t    mem_pool->mp_block->end - mem_pool->mp_block->next_free >= len)\n-\t\tp = mem_pool->mp_block;\n+\tif (pool->mp_block &&\n+\t    pool->mp_block->end - pool->mp_block->next_free >= len)\n+\t\tp = pool->mp_block;\n \n \tif (!p) {\n-\t\tif (len >= (mem_pool->block_alloc / 2))\n-\t\t\treturn mem_pool_alloc_block(mem_pool, len, mem_pool->mp_block);\n+\t\tif (len >= (pool->block_alloc / 2))\n+\t\t\treturn mem_pool_alloc_block(pool, len, pool->mp_block);\n \n-\t\tp = mem_pool_alloc_block(mem_pool, mem_pool->block_alloc, NULL);\n+\t\tp = mem_pool_alloc_block(pool, pool->block_alloc, NULL);\n \t}\n \n \tr = p->next_free;\n@@ -88,10 +90,10 @@ void *mem_pool_alloc(struct mem_pool *mem_pool, size_t len)\n \treturn r;\n }\n \n-void *mem_pool_calloc(struct mem_pool *mem_pool, size_t count, size_t size)\n+void *mem_pool_calloc(struct mem_pool *pool, size_t count, size_t size)\n {\n \tsize_t len = st_mult(count, size);\n-\tvoid *r = mem_pool_alloc(mem_pool, len);\n+\tvoid *r = mem_pool_alloc(pool, len);\n \tmemset(r, 0, len);\n \treturn r;\n }\n@@ -119,12 +121,12 @@ char *mem_pool_xstrndup(struct mem_pool *pool, const char *str, size_t len)\n \treturn memcpy(ret, str, minlen);\n }\n \n-int mem_pool_contains(struct mem_pool *mem_pool, void *mem)\n+int mem_pool_contains(struct mem_pool *pool, void *mem)\n {\n \tstruct mp_block *p;\n \n \t/* Check if memory is allocated in a block */\n-\tfor (p = mem_pool->mp_block; p; p = p->next_block)\n+\tfor (p = pool->mp_block; p; p = p->next_block)\n \t\tif ((mem >= ((void *)p->space)) &&\n \t\t    (mem < ((void *)p->end)))\n \t\t\treturn 1;\ndiff --git a/mem-pool.h b/mem-pool.h\nindex 30b7a8c03b..022b3097e9 100644\n--- a/mem-pool.h\n+++ b/mem-pool.h\n@@ -24,12 +24,12 @@ struct mem_pool {\n /*\n  * Initialize mem_pool with specified initial size.\n  */\n-void mem_pool_init(struct mem_pool *mem_pool, size_t initial_size);\n+void mem_pool_init(struct mem_pool *pool, size_t initial_size);\n \n /*\n  * Discard all the memory the memory pool is responsible for.\n  */\n-void mem_pool_discard(struct mem_pool *mem_pool, int invalidate_memory);\n+void mem_pool_discard(struct mem_pool *pool, int invalidate_memory);\n \n /*\n  * Alloc memory from the mem_pool.\n@@ -58,6 +58,6 @@ void mem_pool_combine(struct mem_pool *dst, struct mem_pool *src);\n  * Check if a memory pointed at by 'mem' is part of the range of\n  * memory managed by the specified mem_pool.\n  */\n-int mem_pool_contains(struct mem_pool *mem_pool, void *mem);\n+int mem_pool_contains(struct mem_pool *pool, void *mem);\n \n #endif\n-- \ngitgitgadget\n"},{"id":"403620","messageId":"f13a52055cd975d457e0593cbabb70897e78024b.1597374135.git.gitgitgadget@gmail.com","threadId":"54041","inReplyTo":"pull.830.git.git.1597374135.gitgitgadget@gmail.com","subject":"[PATCH 2/3] mem-pool: use more standard initialization and finalization","fromName":"Elijah Newren via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2020-08-14T03:02:14Z","receivedAt":"2020-08-14T03:02:23Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"From: Elijah Newren <newren@gmail.com>\n\nA typical memory type, such as strbuf, hashmap, or string_list can be\nstored on the stack or embedded within another structure.  mem_pool\ncannot be, because of how mem_pool_init() and mem_pool_discard() are\nwritten.  mem_pool_init() does essentially the following (simplified\nfor purposes of explanation here):\n\n    void mem_pool_init(struct mem_pool **pool...)\n    {\n        *pool = xcalloc(1, sizeof(*pool));\n\nIt seems weird to require that mem_pools can only be accessed through a\npointer.  It also seems slightly dangerous: unlike strbuf_release() or\nstrbuf_reset() or string_list_clear(), all of which put the data\nstructure into a state where it can be re-used after the call,\nmem_pool_discard(pool) will leave pool pointing at free'd memory.\nread-cache (and split-index) are the only current users of mem_pools,\nand they haven't fallen into a use-after-free mistake here, but it seems\nlikely to be problematic for future users especially since several of\nthe current callers of mem_pool_init() will only call it when the\nmem_pool* is not already allocated (i.e. is NULL).\n\nThis type of mechanism also prevents finding synchronization\npoints where one can free existing memory and then resume more\noperations.  It would be natural at such points to run something like\n    mem_pool_discard(pool...);\nand, if necessary,\n    mem_pool_init(&pool...);\nand then carry on continuing to use the pool.  However, this fails badly\nif several objects had a copy of the value of pool from before these\ncommands; in such a case, those objects won't get the updated value of\npool that mem_pool_init() overwrites pool with and they'll all instead\nbe reading and writing from free'd memory.\n\nModify mem_pool_init()/mem_pool_discard() to behave more like\n   strbuf_init()/strbuf_release()\nor\n   string_list_init()/string_list_clear()\nIn particular: (1) make mem_pool_init() just take a mem_pool* and have\nit only worry about allocating struct mp_blocks, not the struct mem_pool\nitself, (2) make mem_pool_discard() free the memory that the pool was\nresponsible for, but leave it in a state where it can be used to\nallocate more memory afterward (without the need to call mem_pool_init()\nagain).\n\nSigned-off-by: Elijah Newren <newren@gmail.com>\n---\n mem-pool.c    | 20 +++++++-------------\n mem-pool.h    |  4 ++--\n read-cache.c  | 21 +++++++++++++--------\n split-index.c |  6 ++++--\n 4 files changed, 26 insertions(+), 25 deletions(-)\n\ndiff --git a/mem-pool.c b/mem-pool.c\nindex 3a8c54d9df..b7d789823e 100644\n--- a/mem-pool.c\n+++ b/mem-pool.c\n@@ -33,21 +33,14 @@ static struct mp_block *mem_pool_alloc_block(struct mem_pool *mem_pool, size_t b\n \treturn p;\n }\n \n-void mem_pool_init(struct mem_pool **mem_pool, size_t initial_size)\n+void mem_pool_init(struct mem_pool *mem_pool, size_t initial_size)\n {\n-\tstruct mem_pool *pool;\n-\n-\tif (*mem_pool)\n-\t\treturn;\n-\n-\tpool = xcalloc(1, sizeof(*pool));\n-\n-\tpool->block_alloc = BLOCK_GROWTH_SIZE;\n+\tmem_pool->mp_block = NULL;\n+\tmem_pool->pool_alloc = 0;\n+\tmem_pool->block_alloc = BLOCK_GROWTH_SIZE;\n \n \tif (initial_size > 0)\n-\t\tmem_pool_alloc_block(pool, initial_size, NULL);\n-\n-\t*mem_pool = pool;\n+\t\tmem_pool_alloc_block(mem_pool, initial_size, NULL);\n }\n \n void mem_pool_discard(struct mem_pool *mem_pool, int invalidate_memory)\n@@ -66,7 +59,8 @@ void mem_pool_discard(struct mem_pool *mem_pool, int invalidate_memory)\n \t\tfree(block_to_free);\n \t}\n \n-\tfree(mem_pool);\n+\tmem_pool->mp_block = NULL;\n+\tmem_pool->pool_alloc = 0;\n }\n \n void *mem_pool_alloc(struct mem_pool *mem_pool, size_t len)\ndiff --git a/mem-pool.h b/mem-pool.h\nindex fcaa2d462b..30b7a8c03b 100644\n--- a/mem-pool.h\n+++ b/mem-pool.h\n@@ -24,10 +24,10 @@ struct mem_pool {\n /*\n  * Initialize mem_pool with specified initial size.\n  */\n-void mem_pool_init(struct mem_pool **mem_pool, size_t initial_size);\n+void mem_pool_init(struct mem_pool *mem_pool, size_t initial_size);\n \n /*\n- * Discard a memory pool and free all the memory it is responsible for.\n+ * Discard all the memory the memory pool is responsible for.\n  */\n void mem_pool_discard(struct mem_pool *mem_pool, int invalidate_memory);\n \ndiff --git a/read-cache.c b/read-cache.c\nindex 8ed1c29b54..fa291cdbee 100644\n--- a/read-cache.c\n+++ b/read-cache.c\n@@ -89,8 +89,10 @@ static struct mem_pool *find_mem_pool(struct index_state *istate)\n \telse\n \t\tpool_ptr = &istate->ce_mem_pool;\n \n-\tif (!*pool_ptr)\n-\t\tmem_pool_init(pool_ptr, 0);\n+\tif (!*pool_ptr) {\n+\t\t*pool_ptr = xmalloc(sizeof(**pool_ptr));\n+\t\tmem_pool_init(*pool_ptr, 0);\n+\t}\n \n \treturn *pool_ptr;\n }\n@@ -2006,11 +2008,12 @@ static unsigned long load_all_cache_entries(struct index_state *istate,\n {\n \tunsigned long consumed;\n \n+\tistate->ce_mem_pool = xmalloc(sizeof(*istate->ce_mem_pool));\n \tif (istate->version == 4) {\n-\t\tmem_pool_init(&istate->ce_mem_pool,\n+\t\tmem_pool_init(istate->ce_mem_pool,\n \t\t\t\testimate_cache_size_from_compressed(istate->cache_nr));\n \t} else {\n-\t\tmem_pool_init(&istate->ce_mem_pool,\n+\t\tmem_pool_init(istate->ce_mem_pool,\n \t\t\t\testimate_cache_size(mmap_size, istate->cache_nr));\n \t}\n \n@@ -2070,7 +2073,8 @@ static unsigned long load_cache_entries_threaded(struct index_state *istate, con\n \tif (istate->name_hash_initialized)\n \t\tBUG(\"the name hash isn't thread safe\");\n \n-\tmem_pool_init(&istate->ce_mem_pool, 0);\n+\tistate->ce_mem_pool = xmalloc(sizeof(*istate->ce_mem_pool));\n+\tmem_pool_init(istate->ce_mem_pool, 0);\n \n \t/* ensure we have no more threads than we have blocks to process */\n \tif (nr_threads > ieot->nr)\n@@ -2097,11 +2101,12 @@ static unsigned long load_cache_entries_threaded(struct index_state *istate, con\n \t\tnr = 0;\n \t\tfor (j = p->ieot_start; j < p->ieot_start + p->ieot_blocks; j++)\n \t\t\tnr += p->ieot->entries[j].nr;\n+\t\tistate->ce_mem_pool = xmalloc(sizeof(*istate->ce_mem_pool));\n \t\tif (istate->version == 4) {\n-\t\t\tmem_pool_init(&p->ce_mem_pool,\n+\t\t\tmem_pool_init(p->ce_mem_pool,\n \t\t\t\testimate_cache_size_from_compressed(nr));\n \t\t} else {\n-\t\t\tmem_pool_init(&p->ce_mem_pool,\n+\t\t\tmem_pool_init(p->ce_mem_pool,\n \t\t\t\testimate_cache_size(mmap_size, nr));\n \t\t}\n \n@@ -2358,7 +2363,7 @@ int discard_index(struct index_state *istate)\n \n \tif (istate->ce_mem_pool) {\n \t\tmem_pool_discard(istate->ce_mem_pool, should_validate_cache_entries());\n-\t\tistate->ce_mem_pool = NULL;\n+\t\tFREE_AND_NULL(istate->ce_mem_pool);\n \t}\n \n \treturn 0;\ndiff --git a/split-index.c b/split-index.c\nindex e6154e4ea9..c0e8ad670d 100644\n--- a/split-index.c\n+++ b/split-index.c\n@@ -79,8 +79,10 @@ void move_cache_to_base_index(struct index_state *istate)\n \tif (si->base &&\n \t\tsi->base->ce_mem_pool) {\n \n-\t\tif (!istate->ce_mem_pool)\n-\t\t\tmem_pool_init(&istate->ce_mem_pool, 0);\n+\t\tif (!istate->ce_mem_pool) {\n+\t\t\tistate->ce_mem_pool = xmalloc(sizeof(struct mem_pool));\n+\t\t\tmem_pool_init(istate->ce_mem_pool, 0);\n+\t\t}\n \n \t\tmem_pool_combine(istate->ce_mem_pool, istate->split_index->base->ce_mem_pool);\n \t}\n-- \ngitgitgadget\n\n"},{"id":"403621","messageId":"CAHd-oW4quRLLD0qz22facBJPzmn_zVoN-Ze=rP2yvTp=HJONFQ@mail.gmail.com","threadId":"54041","inReplyTo":"pull.830.git.git.1597374135.gitgitgadget@gmail.com","subject":"Re: [PATCH 0/3] Extend and add a little more generalization to the mem_pool API","fromName":"Matheus Tavares Bernardino","fromEmail":"matheus.bernardino@usp.br","sentAt":"2020-08-14T03:51:18Z","receivedAt":"2020-08-14T03:51:33Z","isPatch":true,"sender":{"key":"matheus.tavb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12701583?v=4"},"body":"Hi, Elijah\n\nOn Fri, Aug 14, 2020 at 12:02 AM Elijah Newren via GitGitGadget\n<gitgitgadget@gmail.com> wrote:\n>\n> Unfortunately, Matheus' parallel-checkout RFC series (not yet in next or\n> seen as far as I can tell) adds a few more mem_pool callers, so this series\n> conflicts with his (semantically). I can rebuild mine on top of his, or,\n> since his is longer and would probably advance more slowly, it may make\n> sense to have his series be based on this one. If so, I'm happy to help him\n> update his to depend on this series. Let me know preferences.\n\nThanks for the heads up. Yeah, let me rebuild my series on top of\nyours. From a quick look at your patches, I think it should be quite\nstraightforward to rebase my changes.\n"},{"id":"403622","messageId":"xmqqpn7tzvtf.fsf@gitster.c.googlers.com","threadId":"54041","inReplyTo":"f13a52055cd975d457e0593cbabb70897e78024b.1597374135.git.gitgitgadget@gmail.com","subject":"Re: [PATCH 2/3] mem-pool: use more standard initialization and finalization","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2020-08-14T04:38:04Z","receivedAt":"2020-08-14T04:38:12Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"Elijah Newren via GitGitGadget\" <gitgitgadget@gmail.com> writes:\n\n> written.  mem_pool_init() does essentially the following (simplified\n> for purposes of explanation here):\n>\n>     void mem_pool_init(struct mem_pool **pool...)\n>     {\n>         *pool = xcalloc(1, sizeof(*pool));\n>\n> It seems weird to require that mem_pools can only be accessed through a\n> pointer.\n\nYup, if the _init() were to also allocate, I would expect it to be\nmore like\n\n\tstruct mem_pool *mem_pool_create(...)\n\t{\n\t\tstruct mem_pool *pool = xcalloc(1, sizeof(*pool));\n\t\t...\n\t\treturn pool;\n\t}\n\nIt also is OK to let the caller pass uninitialized region of memory,\nwhich is how we usually arrange _init() to work.  It seems that that\nis the approach this patch takes.\n\n> -void mem_pool_init(struct mem_pool **mem_pool, size_t initial_size)\n> +void mem_pool_init(struct mem_pool *mem_pool, size_t initial_size)\n>  {\n> -\tstruct mem_pool *pool;\n> -\n> -\tif (*mem_pool)\n> -\t\treturn;\n> -\n> -\tpool = xcalloc(1, sizeof(*pool));\n> -\n> -\tpool->block_alloc = BLOCK_GROWTH_SIZE;\n> +\tmem_pool->mp_block = NULL;\n> +\tmem_pool->pool_alloc = 0;\n> +\tmem_pool->block_alloc = BLOCK_GROWTH_SIZE;\n>  \n>  \tif (initial_size > 0)\n> -\t\tmem_pool_alloc_block(pool, initial_size, NULL);\n> -\n> -\t*mem_pool = pool;\n> +\t\tmem_pool_alloc_block(mem_pool, initial_size, NULL);\n\nIt used to be that this function both knew and took control of all\nthe bits in *pool memory by using xcalloc().  Any field the function\nassigned to of course got explicitly the value the function wanted\nit to have, and all other fields were left to 0.\n\nIt may happen to be still the case (i.e. the assignments we see in\nthis function cover all the fields defined), but don't we need some\nprovision to make sure it will hold to be true in the future?\n\nStarting it with \"memset(pool, 0, sizeof(*pool)\" would be one way.\n\nYou'd standardize to s/mem_pool/pool/ in [3/3]; shouldn't this be\nwritten with pool to begin with, instead of reintroducing mem_pool\nthat is of different type from the original?\n\n> -\tif (!*pool_ptr)\n> -\t\tmem_pool_init(pool_ptr, 0);\n> +\tif (!*pool_ptr) {\n> +\t\t*pool_ptr = xmalloc(sizeof(**pool_ptr));\n> +\t\tmem_pool_init(*pool_ptr, 0);\n\nThis one gives an uninitialized chunk of memory to the _init(); an\nexample of the caller that the earlier comment may matter.\n\n> +\tistate->ce_mem_pool = xmalloc(sizeof(*istate->ce_mem_pool));\n>  \tif (istate->version == 4) {\n> -\t\tmem_pool_init(&istate->ce_mem_pool,\n> +\t\tmem_pool_init(istate->ce_mem_pool,\n>  \t\t\t\testimate_cache_size_from_compressed(istate->cache_nr));\n>  \t} else {\n> -\t\tmem_pool_init(&istate->ce_mem_pool,\n> +\t\tmem_pool_init(istate->ce_mem_pool,\n>  \t\t\t\testimate_cache_size(mmap_size, istate->cache_nr));\n>  \t}\n\nLikewise.\n\nThanks.\n"},{"id":"403623","messageId":"CAPig+cQamHAUc9gV=pRAVYfxJKCwiMj=y6nqoN8w2kg6CtOT9Q@mail.gmail.com","threadId":"54041","inReplyTo":"eae8b2923f7834f3b1d030f6eb4dc093b94da91b.1597374135.git.gitgitgadget@gmail.com","subject":"Re: [PATCH 1/3] mem-pool: add convenience functions for xstrdup and xstrndup","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2020-08-14T04:42:19Z","receivedAt":"2020-08-14T04:42:33Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Thu, Aug 13, 2020 at 11:02 PM Elijah Newren via GitGitGadget\n<gitgitgadget@gmail.com> wrote:\n> fast-import had a special mem_pool_xstrdup() convenience function that I\n> want to be able to use from the new merge algorithm I am writing.  Move\n> it from fast-import to mem-pool, and also add a mem_pool_xstrndup()\n> while at it that I also want to use.\n>\n> Signed-off-by: Elijah Newren <newren@gmail.com>\n> ---\n> diff --git a/mem-pool.c b/mem-pool.c\n> @@ -102,6 +102,29 @@ void *mem_pool_calloc(struct mem_pool *mem_pool, size_t count, size_t size)\n> +char *mem_pool_xstrdup(struct mem_pool *pool, const char *str)\n> +{\n> +       size_t len = strlen(str) + 1;\n> +       char *ret = mem_pool_alloc(pool, len);\n> +\n> +       if (!ret)\n> +               die(\"Out of memory, mem_pool_xstrdup failed\");\n\nNit: Not worth a re-roll, but I was wondering if it would make sense\nto allow these to be localized (and follow current convention of not\ncapitalizing):\n\n    die(_(\"mem_pool_xstrdup: out of memory\"));\n\n> +       return memcpy(ret, str, len);\n> +}\n> +\n> +char *mem_pool_xstrndup(struct mem_pool *pool, const char *str, size_t len)\n> +{\n> +       size_t minlen = strnlen(str, len);\n> +       char *ret = mem_pool_alloc(pool, minlen+1);\n> +\n> +       if (!ret)\n> +               die(\"Out of memory, mem_pool_xstrndup failed\");\n\nDitto.\n\n> +\n> +       ret[minlen] = '\\0';\n> +       return memcpy(ret, str, minlen);\n> +}\n"},{"id":"403628","messageId":"pull.830.v2.git.git.1597384820.gitgitgadget@gmail.com","threadId":"54041","inReplyTo":"pull.830.git.git.1597374135.gitgitgadget@gmail.com","subject":"[PATCH v2 0/3] Extend and add a little more generalization to the mem_pool API","fromName":"Elijah Newren via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2020-08-14T06:00:17Z","receivedAt":"2020-08-14T06:00:25Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"In my new merge algorithm, I made use of the mem_pool API in a few\nplaces...but I also needed to add a few more functions and also needed to\nmake the API a bit more general.\n\nChanges since v1:\n\n * Made the error message tweaks suggested by Eric\n * Although mem_pool_init() intialized all members manually, add a memset()\n   to 0 for future-proofing, as suggested by Junio.\n * Use 'pool' instead of 'mem_pool' in patch 2 so that patch 3 doesn't have\n   to change as much (as suggested by Junio).\n\nAlso, Matheus said he'd rebase his parallel-checkout RFC series (next yet in\nnext or seen) on top of mine to avoid the semantic conflict.\n\nElijah Newren (3):\n  mem-pool: add convenience functions for xstrdup and xstrndup\n  mem-pool: use more standard initialization and finalization\n  mem-pool: use consistent pool variable name\n\n fast-import.c | 12 ++-------\n mem-pool.c    | 74 ++++++++++++++++++++++++++++++++-------------------\n mem-pool.h    | 14 +++++++---\n read-cache.c  | 21 +++++++++------\n split-index.c |  6 +++--\n 5 files changed, 75 insertions(+), 52 deletions(-)\n\n\nbase-commit: 7814e8a05a59c0cf5fb186661d1551c75d1299b5\nPublished-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-830%2Fnewren%2Fmem_pool_api-v2\nFetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-830/newren/mem_pool_api-v2\nPull-Request: https://github.com/git/git/pull/830\n\nRange-diff vs v1:\n\n 1:  eae8b2923f ! 1:  6d679c5b46 mem-pool: add convenience functions for xstrdup and xstrndup\n     @@ mem-pool.c: void *mem_pool_calloc(struct mem_pool *mem_pool, size_t count, size_\n      +\tchar *ret = mem_pool_alloc(pool, len);\n      +\n      +\tif (!ret)\n     -+\t\tdie(\"Out of memory, mem_pool_xstrdup failed\");\n     ++\t\tdie(_(\"mem_pool_xstrdup: out of memory\"));\n      +\n      +\treturn memcpy(ret, str, len);\n      +}\n     @@ mem-pool.c: void *mem_pool_calloc(struct mem_pool *mem_pool, size_t count, size_\n      +\tchar *ret = mem_pool_alloc(pool, minlen+1);\n      +\n      +\tif (!ret)\n     -+\t\tdie(\"Out of memory, mem_pool_xstrndup failed\");\n     ++\t\tdie(_(\"mem_pool_xstrndup: out of memory\"));\n      +\n      +\tret[minlen] = '\\0';\n      +\treturn memcpy(ret, str, minlen);\n 2:  f13a52055c ! 2:  e04ba96b22 mem-pool: use more standard initialization and finalization\n     @@ mem-pool.c: static struct mp_block *mem_pool_alloc_block(struct mem_pool *mem_po\n       }\n       \n      -void mem_pool_init(struct mem_pool **mem_pool, size_t initial_size)\n     -+void mem_pool_init(struct mem_pool *mem_pool, size_t initial_size)\n     ++void mem_pool_init(struct mem_pool *pool, size_t initial_size)\n       {\n      -\tstruct mem_pool *pool;\n      -\n     @@ mem-pool.c: static struct mp_block *mem_pool_alloc_block(struct mem_pool *mem_po\n      -\n      -\tpool = xcalloc(1, sizeof(*pool));\n      -\n     --\tpool->block_alloc = BLOCK_GROWTH_SIZE;\n     -+\tmem_pool->mp_block = NULL;\n     -+\tmem_pool->pool_alloc = 0;\n     -+\tmem_pool->block_alloc = BLOCK_GROWTH_SIZE;\n     ++\tmemset(pool, 0, sizeof(*pool));\n     + \tpool->block_alloc = BLOCK_GROWTH_SIZE;\n       \n       \tif (initial_size > 0)\n     --\t\tmem_pool_alloc_block(pool, initial_size, NULL);\n     + \t\tmem_pool_alloc_block(pool, initial_size, NULL);\n      -\n      -\t*mem_pool = pool;\n     -+\t\tmem_pool_alloc_block(mem_pool, initial_size, NULL);\n       }\n       \n       void mem_pool_discard(struct mem_pool *mem_pool, int invalidate_memory)\n     @@ mem-pool.h: struct mem_pool {\n        * Initialize mem_pool with specified initial size.\n        */\n      -void mem_pool_init(struct mem_pool **mem_pool, size_t initial_size);\n     -+void mem_pool_init(struct mem_pool *mem_pool, size_t initial_size);\n     ++void mem_pool_init(struct mem_pool *pool, size_t initial_size);\n       \n       /*\n      - * Discard a memory pool and free all the memory it is responsible for.\n 3:  62c2479fe6 ! 3:  616402c64e mem-pool: use consistent pool variable name\n     @@ mem-pool.c: static struct mp_block *mem_pool_alloc_block(struct mem_pool *mem_po\n       \t}\n       \n       \treturn p;\n     - }\n     - \n     --void mem_pool_init(struct mem_pool *mem_pool, size_t initial_size)\n     -+void mem_pool_init(struct mem_pool *pool, size_t initial_size)\n     - {\n     --\tmem_pool->mp_block = NULL;\n     --\tmem_pool->pool_alloc = 0;\n     --\tmem_pool->block_alloc = BLOCK_GROWTH_SIZE;\n     -+\tpool->mp_block = NULL;\n     -+\tpool->pool_alloc = 0;\n     -+\tpool->block_alloc = BLOCK_GROWTH_SIZE;\n     - \n     - \tif (initial_size > 0)\n     --\t\tmem_pool_alloc_block(mem_pool, initial_size, NULL);\n     -+\t\tmem_pool_alloc_block(pool, initial_size, NULL);\n     +@@ mem-pool.c: void mem_pool_init(struct mem_pool *pool, size_t initial_size)\n     + \t\tmem_pool_alloc_block(pool, initial_size, NULL);\n       }\n       \n      -void mem_pool_discard(struct mem_pool *mem_pool, int invalidate_memory)\n     @@ mem-pool.c: char *mem_pool_xstrndup(struct mem_pool *pool, const char *str, size\n       \t\t\treturn 1;\n      \n       ## mem-pool.h ##\n     -@@ mem-pool.h: struct mem_pool {\n     - /*\n     -  * Initialize mem_pool with specified initial size.\n     -  */\n     --void mem_pool_init(struct mem_pool *mem_pool, size_t initial_size);\n     -+void mem_pool_init(struct mem_pool *pool, size_t initial_size);\n     - \n     +@@ mem-pool.h: void mem_pool_init(struct mem_pool *pool, size_t initial_size);\n       /*\n        * Discard all the memory the memory pool is responsible for.\n        */\n\n-- \ngitgitgadget\n"},{"id":"403629","messageId":"6d679c5b46541208f5fa714174555ff0dc756b9a.1597384820.git.gitgitgadget@gmail.com","threadId":"54041","inReplyTo":"pull.830.v2.git.git.1597384820.gitgitgadget@gmail.com","subject":"[PATCH v2 1/3] mem-pool: add convenience functions for xstrdup and xstrndup","fromName":"Elijah Newren via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2020-08-14T06:00:18Z","receivedAt":"2020-08-14T06:00:26Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"From: Elijah Newren <newren@gmail.com>\n\nfast-import had a special mem_pool_xstrdup() convenience function that I\nwant to be able to use from the new merge algorithm I am writing.  Move\nit from fast-import to mem-pool, and also add a mem_pool_xstrndup()\nwhile at it that I also want to use.\n\nSigned-off-by: Elijah Newren <newren@gmail.com>\n---\n fast-import.c | 12 ++----------\n mem-pool.c    | 23 +++++++++++++++++++++++\n mem-pool.h    |  6 ++++++\n 3 files changed, 31 insertions(+), 10 deletions(-)\n\ndiff --git a/fast-import.c b/fast-import.c\nindex ce47794db6..dd5b563950 100644\n--- a/fast-import.c\n+++ b/fast-import.c\n@@ -526,14 +526,6 @@ static unsigned int hc_str(const char *s, size_t len)\n \treturn r;\n }\n \n-static char *pool_strdup(const char *s)\n-{\n-\tsize_t len = strlen(s) + 1;\n-\tchar *r = mem_pool_alloc(&fi_mem_pool, len);\n-\tmemcpy(r, s, len);\n-\treturn r;\n-}\n-\n static void insert_mark(struct mark_set *s, uintmax_t idnum, struct object_entry *oe)\n {\n \twhile ((idnum >> s->shift) >= 1024) {\n@@ -615,7 +607,7 @@ static struct branch *new_branch(const char *name)\n \t\tdie(\"Branch name doesn't conform to GIT standards: %s\", name);\n \n \tb = mem_pool_calloc(&fi_mem_pool, 1, sizeof(struct branch));\n-\tb->name = pool_strdup(name);\n+\tb->name = mem_pool_xstrdup(&fi_mem_pool, name);\n \tb->table_next_branch = branch_table[hc];\n \tb->branch_tree.versions[0].mode = S_IFDIR;\n \tb->branch_tree.versions[1].mode = S_IFDIR;\n@@ -2806,7 +2798,7 @@ static void parse_new_tag(const char *arg)\n \n \tt = mem_pool_alloc(&fi_mem_pool, sizeof(struct tag));\n \tmemset(t, 0, sizeof(struct tag));\n-\tt->name = pool_strdup(arg);\n+\tt->name = mem_pool_xstrdup(&fi_mem_pool, arg);\n \tif (last_tag)\n \t\tlast_tag->next_tag = t;\n \telse\ndiff --git a/mem-pool.c b/mem-pool.c\nindex a2841a4a9a..33fda1c411 100644\n--- a/mem-pool.c\n+++ b/mem-pool.c\n@@ -102,6 +102,29 @@ void *mem_pool_calloc(struct mem_pool *mem_pool, size_t count, size_t size)\n \treturn r;\n }\n \n+char *mem_pool_xstrdup(struct mem_pool *pool, const char *str)\n+{\n+\tsize_t len = strlen(str) + 1;\n+\tchar *ret = mem_pool_alloc(pool, len);\n+\n+\tif (!ret)\n+\t\tdie(_(\"mem_pool_xstrdup: out of memory\"));\n+\n+\treturn memcpy(ret, str, len);\n+}\n+\n+char *mem_pool_xstrndup(struct mem_pool *pool, const char *str, size_t len)\n+{\n+\tsize_t minlen = strnlen(str, len);\n+\tchar *ret = mem_pool_alloc(pool, minlen+1);\n+\n+\tif (!ret)\n+\t\tdie(_(\"mem_pool_xstrndup: out of memory\"));\n+\n+\tret[minlen] = '\\0';\n+\treturn memcpy(ret, str, minlen);\n+}\n+\n int mem_pool_contains(struct mem_pool *mem_pool, void *mem)\n {\n \tstruct mp_block *p;\ndiff --git a/mem-pool.h b/mem-pool.h\nindex 999d3c3a52..fcaa2d462b 100644\n--- a/mem-pool.h\n+++ b/mem-pool.h\n@@ -41,6 +41,12 @@ void *mem_pool_alloc(struct mem_pool *pool, size_t len);\n  */\n void *mem_pool_calloc(struct mem_pool *pool, size_t count, size_t size);\n \n+/*\n+ * Allocate memory from the memory pool and copy str into it.\n+ */\n+char *mem_pool_xstrdup(struct mem_pool *pool, const char *str);\n+char *mem_pool_xstrndup(struct mem_pool *pool, const char *str, size_t len);\n+\n /*\n  * Move the memory associated with the 'src' pool to the 'dst' pool. The 'src'\n  * pool will be empty and not contain any memory. It still needs to be free'd\n-- \ngitgitgadget\n\n"},{"id":"403630","messageId":"e04ba96b227583875b2034325adfc7f5331d736f.1597384820.git.gitgitgadget@gmail.com","threadId":"54041","inReplyTo":"pull.830.v2.git.git.1597384820.gitgitgadget@gmail.com","subject":"[PATCH v2 2/3] mem-pool: use more standard initialization and finalization","fromName":"Elijah Newren via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2020-08-14T06:00:19Z","receivedAt":"2020-08-14T06:00:28Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"From: Elijah Newren <newren@gmail.com>\n\nA typical memory type, such as strbuf, hashmap, or string_list can be\nstored on the stack or embedded within another structure.  mem_pool\ncannot be, because of how mem_pool_init() and mem_pool_discard() are\nwritten.  mem_pool_init() does essentially the following (simplified\nfor purposes of explanation here):\n\n    void mem_pool_init(struct mem_pool **pool...)\n    {\n        *pool = xcalloc(1, sizeof(*pool));\n\nIt seems weird to require that mem_pools can only be accessed through a\npointer.  It also seems slightly dangerous: unlike strbuf_release() or\nstrbuf_reset() or string_list_clear(), all of which put the data\nstructure into a state where it can be re-used after the call,\nmem_pool_discard(pool) will leave pool pointing at free'd memory.\nread-cache (and split-index) are the only current users of mem_pools,\nand they haven't fallen into a use-after-free mistake here, but it seems\nlikely to be problematic for future users especially since several of\nthe current callers of mem_pool_init() will only call it when the\nmem_pool* is not already allocated (i.e. is NULL).\n\nThis type of mechanism also prevents finding synchronization\npoints where one can free existing memory and then resume more\noperations.  It would be natural at such points to run something like\n    mem_pool_discard(pool...);\nand, if necessary,\n    mem_pool_init(&pool...);\nand then carry on continuing to use the pool.  However, this fails badly\nif several objects had a copy of the value of pool from before these\ncommands; in such a case, those objects won't get the updated value of\npool that mem_pool_init() overwrites pool with and they'll all instead\nbe reading and writing from free'd memory.\n\nModify mem_pool_init()/mem_pool_discard() to behave more like\n   strbuf_init()/strbuf_release()\nor\n   string_list_init()/string_list_clear()\nIn particular: (1) make mem_pool_init() just take a mem_pool* and have\nit only worry about allocating struct mp_blocks, not the struct mem_pool\nitself, (2) make mem_pool_discard() free the memory that the pool was\nresponsible for, but leave it in a state where it can be used to\nallocate more memory afterward (without the need to call mem_pool_init()\nagain).\n\nSigned-off-by: Elijah Newren <newren@gmail.com>\n---\n mem-pool.c    | 15 ++++-----------\n mem-pool.h    |  4 ++--\n read-cache.c  | 21 +++++++++++++--------\n split-index.c |  6 ++++--\n 4 files changed, 23 insertions(+), 23 deletions(-)\n\ndiff --git a/mem-pool.c b/mem-pool.c\nindex 33fda1c411..305bcd3542 100644\n--- a/mem-pool.c\n+++ b/mem-pool.c\n@@ -33,21 +33,13 @@ static struct mp_block *mem_pool_alloc_block(struct mem_pool *mem_pool, size_t b\n \treturn p;\n }\n \n-void mem_pool_init(struct mem_pool **mem_pool, size_t initial_size)\n+void mem_pool_init(struct mem_pool *pool, size_t initial_size)\n {\n-\tstruct mem_pool *pool;\n-\n-\tif (*mem_pool)\n-\t\treturn;\n-\n-\tpool = xcalloc(1, sizeof(*pool));\n-\n+\tmemset(pool, 0, sizeof(*pool));\n \tpool->block_alloc = BLOCK_GROWTH_SIZE;\n \n \tif (initial_size > 0)\n \t\tmem_pool_alloc_block(pool, initial_size, NULL);\n-\n-\t*mem_pool = pool;\n }\n \n void mem_pool_discard(struct mem_pool *mem_pool, int invalidate_memory)\n@@ -66,7 +58,8 @@ void mem_pool_discard(struct mem_pool *mem_pool, int invalidate_memory)\n \t\tfree(block_to_free);\n \t}\n \n-\tfree(mem_pool);\n+\tmem_pool->mp_block = NULL;\n+\tmem_pool->pool_alloc = 0;\n }\n \n void *mem_pool_alloc(struct mem_pool *mem_pool, size_t len)\ndiff --git a/mem-pool.h b/mem-pool.h\nindex fcaa2d462b..a55ee4bc38 100644\n--- a/mem-pool.h\n+++ b/mem-pool.h\n@@ -24,10 +24,10 @@ struct mem_pool {\n /*\n  * Initialize mem_pool with specified initial size.\n  */\n-void mem_pool_init(struct mem_pool **mem_pool, size_t initial_size);\n+void mem_pool_init(struct mem_pool *pool, size_t initial_size);\n \n /*\n- * Discard a memory pool and free all the memory it is responsible for.\n+ * Discard all the memory the memory pool is responsible for.\n  */\n void mem_pool_discard(struct mem_pool *mem_pool, int invalidate_memory);\n \ndiff --git a/read-cache.c b/read-cache.c\nindex 8ed1c29b54..fa291cdbee 100644\n--- a/read-cache.c\n+++ b/read-cache.c\n@@ -89,8 +89,10 @@ static struct mem_pool *find_mem_pool(struct index_state *istate)\n \telse\n \t\tpool_ptr = &istate->ce_mem_pool;\n \n-\tif (!*pool_ptr)\n-\t\tmem_pool_init(pool_ptr, 0);\n+\tif (!*pool_ptr) {\n+\t\t*pool_ptr = xmalloc(sizeof(**pool_ptr));\n+\t\tmem_pool_init(*pool_ptr, 0);\n+\t}\n \n \treturn *pool_ptr;\n }\n@@ -2006,11 +2008,12 @@ static unsigned long load_all_cache_entries(struct index_state *istate,\n {\n \tunsigned long consumed;\n \n+\tistate->ce_mem_pool = xmalloc(sizeof(*istate->ce_mem_pool));\n \tif (istate->version == 4) {\n-\t\tmem_pool_init(&istate->ce_mem_pool,\n+\t\tmem_pool_init(istate->ce_mem_pool,\n \t\t\t\testimate_cache_size_from_compressed(istate->cache_nr));\n \t} else {\n-\t\tmem_pool_init(&istate->ce_mem_pool,\n+\t\tmem_pool_init(istate->ce_mem_pool,\n \t\t\t\testimate_cache_size(mmap_size, istate->cache_nr));\n \t}\n \n@@ -2070,7 +2073,8 @@ static unsigned long load_cache_entries_threaded(struct index_state *istate, con\n \tif (istate->name_hash_initialized)\n \t\tBUG(\"the name hash isn't thread safe\");\n \n-\tmem_pool_init(&istate->ce_mem_pool, 0);\n+\tistate->ce_mem_pool = xmalloc(sizeof(*istate->ce_mem_pool));\n+\tmem_pool_init(istate->ce_mem_pool, 0);\n \n \t/* ensure we have no more threads than we have blocks to process */\n \tif (nr_threads > ieot->nr)\n@@ -2097,11 +2101,12 @@ static unsigned long load_cache_entries_threaded(struct index_state *istate, con\n \t\tnr = 0;\n \t\tfor (j = p->ieot_start; j < p->ieot_start + p->ieot_blocks; j++)\n \t\t\tnr += p->ieot->entries[j].nr;\n+\t\tistate->ce_mem_pool = xmalloc(sizeof(*istate->ce_mem_pool));\n \t\tif (istate->version == 4) {\n-\t\t\tmem_pool_init(&p->ce_mem_pool,\n+\t\t\tmem_pool_init(p->ce_mem_pool,\n \t\t\t\testimate_cache_size_from_compressed(nr));\n \t\t} else {\n-\t\t\tmem_pool_init(&p->ce_mem_pool,\n+\t\t\tmem_pool_init(p->ce_mem_pool,\n \t\t\t\testimate_cache_size(mmap_size, nr));\n \t\t}\n \n@@ -2358,7 +2363,7 @@ int discard_index(struct index_state *istate)\n \n \tif (istate->ce_mem_pool) {\n \t\tmem_pool_discard(istate->ce_mem_pool, should_validate_cache_entries());\n-\t\tistate->ce_mem_pool = NULL;\n+\t\tFREE_AND_NULL(istate->ce_mem_pool);\n \t}\n \n \treturn 0;\ndiff --git a/split-index.c b/split-index.c\nindex e6154e4ea9..c0e8ad670d 100644\n--- a/split-index.c\n+++ b/split-index.c\n@@ -79,8 +79,10 @@ void move_cache_to_base_index(struct index_state *istate)\n \tif (si->base &&\n \t\tsi->base->ce_mem_pool) {\n \n-\t\tif (!istate->ce_mem_pool)\n-\t\t\tmem_pool_init(&istate->ce_mem_pool, 0);\n+\t\tif (!istate->ce_mem_pool) {\n+\t\t\tistate->ce_mem_pool = xmalloc(sizeof(struct mem_pool));\n+\t\t\tmem_pool_init(istate->ce_mem_pool, 0);\n+\t\t}\n \n \t\tmem_pool_combine(istate->ce_mem_pool, istate->split_index->base->ce_mem_pool);\n \t}\n-- \ngitgitgadget\n\n"},{"id":"403631","messageId":"616402c64e1e01f88e962cf88f4ed1307d986a04.1597384820.git.gitgitgadget@gmail.com","threadId":"54041","inReplyTo":"pull.830.v2.git.git.1597384820.gitgitgadget@gmail.com","subject":"[PATCH v2 3/3] mem-pool: use consistent pool variable name","fromName":"Elijah Newren via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2020-08-14T06:00:20Z","receivedAt":"2020-08-14T06:00:29Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"From: Elijah Newren <newren@gmail.com>\n\nAbout half the function declarations in mem-pool.h used 'struct mem_pool\n*pool', while the other half used 'struct mem_pool *mem_pool'.  Make the\ncode a bit more consistent by just using 'pool' in preference to\n'mem_pool' everywhere.\n\nNo behavioral changes included; this is just a mechanical rename (though\na line or two was rewrapped as well).\n\nSigned-off-by: Elijah Newren <newren@gmail.com>\n---\n mem-pool.c | 40 +++++++++++++++++++++-------------------\n mem-pool.h |  4 ++--\n 2 files changed, 23 insertions(+), 21 deletions(-)\n\ndiff --git a/mem-pool.c b/mem-pool.c\nindex 305bcd3542..593605fce2 100644\n--- a/mem-pool.c\n+++ b/mem-pool.c\n@@ -12,11 +12,13 @@\n  * `insert_after`. If `insert_after` is NULL, then insert block at the\n  * head of the linked list.\n  */\n-static struct mp_block *mem_pool_alloc_block(struct mem_pool *mem_pool, size_t block_alloc, struct mp_block *insert_after)\n+static struct mp_block *mem_pool_alloc_block(struct mem_pool *pool,\n+\t\t\t\t\t     size_t block_alloc,\n+\t\t\t\t\t     struct mp_block *insert_after)\n {\n \tstruct mp_block *p;\n \n-\tmem_pool->pool_alloc += sizeof(struct mp_block) + block_alloc;\n+\tpool->pool_alloc += sizeof(struct mp_block) + block_alloc;\n \tp = xmalloc(st_add(sizeof(struct mp_block), block_alloc));\n \n \tp->next_free = (char *)p->space;\n@@ -26,8 +28,8 @@ static struct mp_block *mem_pool_alloc_block(struct mem_pool *mem_pool, size_t b\n \t\tp->next_block = insert_after->next_block;\n \t\tinsert_after->next_block = p;\n \t} else {\n-\t\tp->next_block = mem_pool->mp_block;\n-\t\tmem_pool->mp_block = p;\n+\t\tp->next_block = pool->mp_block;\n+\t\tpool->mp_block = p;\n \t}\n \n \treturn p;\n@@ -42,11 +44,11 @@ void mem_pool_init(struct mem_pool *pool, size_t initial_size)\n \t\tmem_pool_alloc_block(pool, initial_size, NULL);\n }\n \n-void mem_pool_discard(struct mem_pool *mem_pool, int invalidate_memory)\n+void mem_pool_discard(struct mem_pool *pool, int invalidate_memory)\n {\n \tstruct mp_block *block, *block_to_free;\n \n-\tblock = mem_pool->mp_block;\n+\tblock = pool->mp_block;\n \twhile (block)\n \t{\n \t\tblock_to_free = block;\n@@ -58,11 +60,11 @@ void mem_pool_discard(struct mem_pool *mem_pool, int invalidate_memory)\n \t\tfree(block_to_free);\n \t}\n \n-\tmem_pool->mp_block = NULL;\n-\tmem_pool->pool_alloc = 0;\n+\tpool->mp_block = NULL;\n+\tpool->pool_alloc = 0;\n }\n \n-void *mem_pool_alloc(struct mem_pool *mem_pool, size_t len)\n+void *mem_pool_alloc(struct mem_pool *pool, size_t len)\n {\n \tstruct mp_block *p = NULL;\n \tvoid *r;\n@@ -71,15 +73,15 @@ void *mem_pool_alloc(struct mem_pool *mem_pool, size_t len)\n \tif (len & (sizeof(uintmax_t) - 1))\n \t\tlen += sizeof(uintmax_t) - (len & (sizeof(uintmax_t) - 1));\n \n-\tif (mem_pool->mp_block &&\n-\t    mem_pool->mp_block->end - mem_pool->mp_block->next_free >= len)\n-\t\tp = mem_pool->mp_block;\n+\tif (pool->mp_block &&\n+\t    pool->mp_block->end - pool->mp_block->next_free >= len)\n+\t\tp = pool->mp_block;\n \n \tif (!p) {\n-\t\tif (len >= (mem_pool->block_alloc / 2))\n-\t\t\treturn mem_pool_alloc_block(mem_pool, len, mem_pool->mp_block);\n+\t\tif (len >= (pool->block_alloc / 2))\n+\t\t\treturn mem_pool_alloc_block(pool, len, pool->mp_block);\n \n-\t\tp = mem_pool_alloc_block(mem_pool, mem_pool->block_alloc, NULL);\n+\t\tp = mem_pool_alloc_block(pool, pool->block_alloc, NULL);\n \t}\n \n \tr = p->next_free;\n@@ -87,10 +89,10 @@ void *mem_pool_alloc(struct mem_pool *mem_pool, size_t len)\n \treturn r;\n }\n \n-void *mem_pool_calloc(struct mem_pool *mem_pool, size_t count, size_t size)\n+void *mem_pool_calloc(struct mem_pool *pool, size_t count, size_t size)\n {\n \tsize_t len = st_mult(count, size);\n-\tvoid *r = mem_pool_alloc(mem_pool, len);\n+\tvoid *r = mem_pool_alloc(pool, len);\n \tmemset(r, 0, len);\n \treturn r;\n }\n@@ -118,12 +120,12 @@ char *mem_pool_xstrndup(struct mem_pool *pool, const char *str, size_t len)\n \treturn memcpy(ret, str, minlen);\n }\n \n-int mem_pool_contains(struct mem_pool *mem_pool, void *mem)\n+int mem_pool_contains(struct mem_pool *pool, void *mem)\n {\n \tstruct mp_block *p;\n \n \t/* Check if memory is allocated in a block */\n-\tfor (p = mem_pool->mp_block; p; p = p->next_block)\n+\tfor (p = pool->mp_block; p; p = p->next_block)\n \t\tif ((mem >= ((void *)p->space)) &&\n \t\t    (mem < ((void *)p->end)))\n \t\t\treturn 1;\ndiff --git a/mem-pool.h b/mem-pool.h\nindex a55ee4bc38..022b3097e9 100644\n--- a/mem-pool.h\n+++ b/mem-pool.h\n@@ -29,7 +29,7 @@ void mem_pool_init(struct mem_pool *pool, size_t initial_size);\n /*\n  * Discard all the memory the memory pool is responsible for.\n  */\n-void mem_pool_discard(struct mem_pool *mem_pool, int invalidate_memory);\n+void mem_pool_discard(struct mem_pool *pool, int invalidate_memory);\n \n /*\n  * Alloc memory from the mem_pool.\n@@ -58,6 +58,6 @@ void mem_pool_combine(struct mem_pool *dst, struct mem_pool *src);\n  * Check if a memory pointed at by 'mem' is part of the range of\n  * memory managed by the specified mem_pool.\n  */\n-int mem_pool_contains(struct mem_pool *mem_pool, void *mem);\n+int mem_pool_contains(struct mem_pool *pool, void *mem);\n \n #endif\n-- \ngitgitgadget\n"},{"id":"403633","messageId":"e7ef099b-5d96-ff67-5d4e-b6fa306adb38@web.de","threadId":"54041","inReplyTo":"6d679c5b46541208f5fa714174555ff0dc756b9a.1597384820.git.gitgitgadget@gmail.com","subject":"Re: [PATCH v2 1/3] mem-pool: add convenience functions for xstrdup and xstrndup","fromName":"René Scharfe","fromEmail":"l.s.r@web.de","sentAt":"2020-08-14T08:21:22Z","receivedAt":"2020-08-14T08:21:33Z","isPatch":true,"sender":{"key":"l.s.r@web.de","avatar":"https://avatars.githubusercontent.com/u/26122331?v=4"},"body":"Am 14.08.20 um 08:00 schrieb Elijah Newren via GitGitGadget:\n> From: Elijah Newren <newren@gmail.com>\n>\n> fast-import had a special mem_pool_xstrdup() convenience function that I\n> want to be able to use from the new merge algorithm I am writing.  Move\n> it from fast-import to mem-pool, and also add a mem_pool_xstrndup()\n> while at it that I also want to use.\n>\n> Signed-off-by: Elijah Newren <newren@gmail.com>\n> ---\n>  fast-import.c | 12 ++----------\n>  mem-pool.c    | 23 +++++++++++++++++++++++\n>  mem-pool.h    |  6 ++++++\n>  3 files changed, 31 insertions(+), 10 deletions(-)\n>\n> diff --git a/fast-import.c b/fast-import.c\n> index ce47794db6..dd5b563950 100644\n> --- a/fast-import.c\n> +++ b/fast-import.c\n> @@ -526,14 +526,6 @@ static unsigned int hc_str(const char *s, size_t len)\n>  \treturn r;\n>  }\n>\n> -static char *pool_strdup(const char *s)\n> -{\n> -\tsize_t len = strlen(s) + 1;\n> -\tchar *r = mem_pool_alloc(&fi_mem_pool, len);\n> -\tmemcpy(r, s, len);\n> -\treturn r;\n> -}\n\nNote: No \"x\" in the name and it doesn't handle mem_pool_alloc()\nreturning NULL.\n\n> -\n>  static void insert_mark(struct mark_set *s, uintmax_t idnum, struct object_entry *oe)\n>  {\n>  \twhile ((idnum >> s->shift) >= 1024) {\n> @@ -615,7 +607,7 @@ static struct branch *new_branch(const char *name)\n>  \t\tdie(\"Branch name doesn't conform to GIT standards: %s\", name);\n>\n>  \tb = mem_pool_calloc(&fi_mem_pool, 1, sizeof(struct branch));\n> -\tb->name = pool_strdup(name);\n> +\tb->name = mem_pool_xstrdup(&fi_mem_pool, name);\n>  \tb->table_next_branch = branch_table[hc];\n>  \tb->branch_tree.versions[0].mode = S_IFDIR;\n>  \tb->branch_tree.versions[1].mode = S_IFDIR;\n> @@ -2806,7 +2798,7 @@ static void parse_new_tag(const char *arg)\n>\n>  \tt = mem_pool_alloc(&fi_mem_pool, sizeof(struct tag));\n>  \tmemset(t, 0, sizeof(struct tag));\n> -\tt->name = pool_strdup(arg);\n> +\tt->name = mem_pool_xstrdup(&fi_mem_pool, arg);\n>  \tif (last_tag)\n>  \t\tlast_tag->next_tag = t;\n>  \telse\n> diff --git a/mem-pool.c b/mem-pool.c\n> index a2841a4a9a..33fda1c411 100644\n> --- a/mem-pool.c\n> +++ b/mem-pool.c\n> @@ -102,6 +102,29 @@ void *mem_pool_calloc(struct mem_pool *mem_pool, size_t count, size_t size)\n>  \treturn r;\n>  }\n>\n> +char *mem_pool_xstrdup(struct mem_pool *pool, const char *str)\n> +{\n> +\tsize_t len = strlen(str) + 1;\n> +\tchar *ret = mem_pool_alloc(pool, len);\n> +\n> +\tif (!ret)\n> +\t\tdie(_(\"mem_pool_xstrdup: out of memory\"));\n\nCan mem_pool_alloc() actually return NULL?  It will rather die because\nit uses xmalloc(), right?  So that check is unnecessary.\n\nAnd since \"mem_pool_\" already implies that these functions won't return\nif an allocation fails, no extra \"x\" is needed in their name.\n\n> +\n> +\treturn memcpy(ret, str, len);\n> +}\n> +\n> +char *mem_pool_xstrndup(struct mem_pool *pool, const char *str, size_t len)\n> +{\n> +\tsize_t minlen = strnlen(str, len);\n\nHmm, this would be our first caller of strnlen().  wrapper.c::xstrndup()\nuses memchr() instead.  It was added in 2008, and strnlen() is in\nPOSIX.1-2008, so back then it made sense.  Perhaps there are still\nsystems out there without one?\n\n> +\tchar *ret = mem_pool_alloc(pool, minlen+1);\n> +\n> +\tif (!ret)\n> +\t\tdie(_(\"mem_pool_xstrndup: out of memory\"));\n\nThe same comments as on mem_pool_xstrdup() apply here.\n\n> +\n> +\tret[minlen] = '\\0';\n> +\treturn memcpy(ret, str, minlen);\n> +}\n> +\n>  int mem_pool_contains(struct mem_pool *mem_pool, void *mem)\n>  {\n>  \tstruct mp_block *p;\n> diff --git a/mem-pool.h b/mem-pool.h\n> index 999d3c3a52..fcaa2d462b 100644\n> --- a/mem-pool.h\n> +++ b/mem-pool.h\n> @@ -41,6 +41,12 @@ void *mem_pool_alloc(struct mem_pool *pool, size_t len);\n>   */\n>  void *mem_pool_calloc(struct mem_pool *pool, size_t count, size_t size);\n>\n> +/*\n> + * Allocate memory from the memory pool and copy str into it.\n> + */\n> +char *mem_pool_xstrdup(struct mem_pool *pool, const char *str);\n> +char *mem_pool_xstrndup(struct mem_pool *pool, const char *str, size_t len);\n> +\n>  /*\n>   * Move the memory associated with the 'src' pool to the 'dst' pool. The 'src'\n>   * pool will be empty and not contain any memory. It still needs to be free'd\n>\n\n"},{"id":"403760","messageId":"09976779c3b4dc47e44bb70034119548b9f51391.1597513078.git.gitgitgadget@gmail.com","threadId":"54041","inReplyTo":"pull.830.v3.git.git.1597513078.gitgitgadget@gmail.com","subject":"[PATCH v3 3/3] mem-pool: use consistent pool variable name","fromName":"Elijah Newren via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2020-08-15T17:37:57Z","receivedAt":"2020-08-15T22:00:10Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"From: Elijah Newren <newren@gmail.com>\n\nAbout half the function declarations in mem-pool.h used 'struct mem_pool\n*pool', while the other half used 'struct mem_pool *mem_pool'.  Make the\ncode a bit more consistent by just using 'pool' in preference to\n'mem_pool' everywhere.\n\nNo behavioral changes included; this is just a mechanical rename (though\na line or two was rewrapped as well).\n\nSigned-off-by: Elijah Newren <newren@gmail.com>\n---\n mem-pool.c | 40 +++++++++++++++++++++-------------------\n mem-pool.h |  4 ++--\n 2 files changed, 23 insertions(+), 21 deletions(-)\n\ndiff --git a/mem-pool.c b/mem-pool.c\nindex 7659919ab2..8401761dda 100644\n--- a/mem-pool.c\n+++ b/mem-pool.c\n@@ -12,11 +12,13 @@\n  * `insert_after`. If `insert_after` is NULL, then insert block at the\n  * head of the linked list.\n  */\n-static struct mp_block *mem_pool_alloc_block(struct mem_pool *mem_pool, size_t block_alloc, struct mp_block *insert_after)\n+static struct mp_block *mem_pool_alloc_block(struct mem_pool *pool,\n+\t\t\t\t\t     size_t block_alloc,\n+\t\t\t\t\t     struct mp_block *insert_after)\n {\n \tstruct mp_block *p;\n \n-\tmem_pool->pool_alloc += sizeof(struct mp_block) + block_alloc;\n+\tpool->pool_alloc += sizeof(struct mp_block) + block_alloc;\n \tp = xmalloc(st_add(sizeof(struct mp_block), block_alloc));\n \n \tp->next_free = (char *)p->space;\n@@ -26,8 +28,8 @@ static struct mp_block *mem_pool_alloc_block(struct mem_pool *mem_pool, size_t b\n \t\tp->next_block = insert_after->next_block;\n \t\tinsert_after->next_block = p;\n \t} else {\n-\t\tp->next_block = mem_pool->mp_block;\n-\t\tmem_pool->mp_block = p;\n+\t\tp->next_block = pool->mp_block;\n+\t\tpool->mp_block = p;\n \t}\n \n \treturn p;\n@@ -42,11 +44,11 @@ void mem_pool_init(struct mem_pool *pool, size_t initial_size)\n \t\tmem_pool_alloc_block(pool, initial_size, NULL);\n }\n \n-void mem_pool_discard(struct mem_pool *mem_pool, int invalidate_memory)\n+void mem_pool_discard(struct mem_pool *pool, int invalidate_memory)\n {\n \tstruct mp_block *block, *block_to_free;\n \n-\tblock = mem_pool->mp_block;\n+\tblock = pool->mp_block;\n \twhile (block)\n \t{\n \t\tblock_to_free = block;\n@@ -58,11 +60,11 @@ void mem_pool_discard(struct mem_pool *mem_pool, int invalidate_memory)\n \t\tfree(block_to_free);\n \t}\n \n-\tmem_pool->mp_block = NULL;\n-\tmem_pool->pool_alloc = 0;\n+\tpool->mp_block = NULL;\n+\tpool->pool_alloc = 0;\n }\n \n-void *mem_pool_alloc(struct mem_pool *mem_pool, size_t len)\n+void *mem_pool_alloc(struct mem_pool *pool, size_t len)\n {\n \tstruct mp_block *p = NULL;\n \tvoid *r;\n@@ -71,15 +73,15 @@ void *mem_pool_alloc(struct mem_pool *mem_pool, size_t len)\n \tif (len & (sizeof(uintmax_t) - 1))\n \t\tlen += sizeof(uintmax_t) - (len & (sizeof(uintmax_t) - 1));\n \n-\tif (mem_pool->mp_block &&\n-\t    mem_pool->mp_block->end - mem_pool->mp_block->next_free >= len)\n-\t\tp = mem_pool->mp_block;\n+\tif (pool->mp_block &&\n+\t    pool->mp_block->end - pool->mp_block->next_free >= len)\n+\t\tp = pool->mp_block;\n \n \tif (!p) {\n-\t\tif (len >= (mem_pool->block_alloc / 2))\n-\t\t\treturn mem_pool_alloc_block(mem_pool, len, mem_pool->mp_block);\n+\t\tif (len >= (pool->block_alloc / 2))\n+\t\t\treturn mem_pool_alloc_block(pool, len, pool->mp_block);\n \n-\t\tp = mem_pool_alloc_block(mem_pool, mem_pool->block_alloc, NULL);\n+\t\tp = mem_pool_alloc_block(pool, pool->block_alloc, NULL);\n \t}\n \n \tr = p->next_free;\n@@ -87,10 +89,10 @@ void *mem_pool_alloc(struct mem_pool *mem_pool, size_t len)\n \treturn r;\n }\n \n-void *mem_pool_calloc(struct mem_pool *mem_pool, size_t count, size_t size)\n+void *mem_pool_calloc(struct mem_pool *pool, size_t count, size_t size)\n {\n \tsize_t len = st_mult(count, size);\n-\tvoid *r = mem_pool_alloc(mem_pool, len);\n+\tvoid *r = mem_pool_alloc(pool, len);\n \tmemset(r, 0, len);\n \treturn r;\n }\n@@ -113,12 +115,12 @@ char *mem_pool_strndup(struct mem_pool *pool, const char *str, size_t len)\n \treturn memcpy(ret, str, actual_len);\n }\n \n-int mem_pool_contains(struct mem_pool *mem_pool, void *mem)\n+int mem_pool_contains(struct mem_pool *pool, void *mem)\n {\n \tstruct mp_block *p;\n \n \t/* Check if memory is allocated in a block */\n-\tfor (p = mem_pool->mp_block; p; p = p->next_block)\n+\tfor (p = pool->mp_block; p; p = p->next_block)\n \t\tif ((mem >= ((void *)p->space)) &&\n \t\t    (mem < ((void *)p->end)))\n \t\t\treturn 1;\ndiff --git a/mem-pool.h b/mem-pool.h\nindex 870161ab44..fe7507f022 100644\n--- a/mem-pool.h\n+++ b/mem-pool.h\n@@ -29,7 +29,7 @@ void mem_pool_init(struct mem_pool *pool, size_t initial_size);\n /*\n  * Discard all the memory the memory pool is responsible for.\n  */\n-void mem_pool_discard(struct mem_pool *mem_pool, int invalidate_memory);\n+void mem_pool_discard(struct mem_pool *pool, int invalidate_memory);\n \n /*\n  * Alloc memory from the mem_pool.\n@@ -58,6 +58,6 @@ void mem_pool_combine(struct mem_pool *dst, struct mem_pool *src);\n  * Check if a memory pointed at by 'mem' is part of the range of\n  * memory managed by the specified mem_pool.\n  */\n-int mem_pool_contains(struct mem_pool *mem_pool, void *mem);\n+int mem_pool_contains(struct mem_pool *pool, void *mem);\n \n #endif\n-- \ngitgitgadget\n"},{"id":"403766","messageId":"65f334f5cfe7dd99e74d48f2b16b61ae84182c9d.1597513078.git.gitgitgadget@gmail.com","threadId":"54041","inReplyTo":"pull.830.v3.git.git.1597513078.gitgitgadget@gmail.com","subject":"[PATCH v3 2/3] mem-pool: use more standard initialization and finalization","fromName":"Elijah Newren via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2020-08-15T17:37:56Z","receivedAt":"2020-08-15T22:02:30Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"From: Elijah Newren <newren@gmail.com>\n\nA typical memory type, such as strbuf, hashmap, or string_list can be\nstored on the stack or embedded within another structure.  mem_pool\ncannot be, because of how mem_pool_init() and mem_pool_discard() are\nwritten.  mem_pool_init() does essentially the following (simplified\nfor purposes of explanation here):\n\n    void mem_pool_init(struct mem_pool **pool...)\n    {\n        *pool = xcalloc(1, sizeof(*pool));\n\nIt seems weird to require that mem_pools can only be accessed through a\npointer.  It also seems slightly dangerous: unlike strbuf_release() or\nstrbuf_reset() or string_list_clear(), all of which put the data\nstructure into a state where it can be re-used after the call,\nmem_pool_discard(pool) will leave pool pointing at free'd memory.\nread-cache (and split-index) are the only current users of mem_pools,\nand they haven't fallen into a use-after-free mistake here, but it seems\nlikely to be problematic for future users especially since several of\nthe current callers of mem_pool_init() will only call it when the\nmem_pool* is not already allocated (i.e. is NULL).\n\nThis type of mechanism also prevents finding synchronization\npoints where one can free existing memory and then resume more\noperations.  It would be natural at such points to run something like\n    mem_pool_discard(pool...);\nand, if necessary,\n    mem_pool_init(&pool...);\nand then carry on continuing to use the pool.  However, this fails badly\nif several objects had a copy of the value of pool from before these\ncommands; in such a case, those objects won't get the updated value of\npool that mem_pool_init() overwrites pool with and they'll all instead\nbe reading and writing from free'd memory.\n\nModify mem_pool_init()/mem_pool_discard() to behave more like\n   strbuf_init()/strbuf_release()\nor\n   string_list_init()/string_list_clear()\nIn particular: (1) make mem_pool_init() just take a mem_pool* and have\nit only worry about allocating struct mp_blocks, not the struct mem_pool\nitself, (2) make mem_pool_discard() free the memory that the pool was\nresponsible for, but leave it in a state where it can be used to\nallocate more memory afterward (without the need to call mem_pool_init()\nagain).\n\nSigned-off-by: Elijah Newren <newren@gmail.com>\n---\n mem-pool.c    | 15 ++++-----------\n mem-pool.h    |  4 ++--\n read-cache.c  | 21 +++++++++++++--------\n split-index.c |  6 ++++--\n 4 files changed, 23 insertions(+), 23 deletions(-)\n\ndiff --git a/mem-pool.c b/mem-pool.c\nindex 020b51e0c5..7659919ab2 100644\n--- a/mem-pool.c\n+++ b/mem-pool.c\n@@ -33,21 +33,13 @@ static struct mp_block *mem_pool_alloc_block(struct mem_pool *mem_pool, size_t b\n \treturn p;\n }\n \n-void mem_pool_init(struct mem_pool **mem_pool, size_t initial_size)\n+void mem_pool_init(struct mem_pool *pool, size_t initial_size)\n {\n-\tstruct mem_pool *pool;\n-\n-\tif (*mem_pool)\n-\t\treturn;\n-\n-\tpool = xcalloc(1, sizeof(*pool));\n-\n+\tmemset(pool, 0, sizeof(*pool));\n \tpool->block_alloc = BLOCK_GROWTH_SIZE;\n \n \tif (initial_size > 0)\n \t\tmem_pool_alloc_block(pool, initial_size, NULL);\n-\n-\t*mem_pool = pool;\n }\n \n void mem_pool_discard(struct mem_pool *mem_pool, int invalidate_memory)\n@@ -66,7 +58,8 @@ void mem_pool_discard(struct mem_pool *mem_pool, int invalidate_memory)\n \t\tfree(block_to_free);\n \t}\n \n-\tfree(mem_pool);\n+\tmem_pool->mp_block = NULL;\n+\tmem_pool->pool_alloc = 0;\n }\n \n void *mem_pool_alloc(struct mem_pool *mem_pool, size_t len)\ndiff --git a/mem-pool.h b/mem-pool.h\nindex ca062c9070..870161ab44 100644\n--- a/mem-pool.h\n+++ b/mem-pool.h\n@@ -24,10 +24,10 @@ struct mem_pool {\n /*\n  * Initialize mem_pool with specified initial size.\n  */\n-void mem_pool_init(struct mem_pool **mem_pool, size_t initial_size);\n+void mem_pool_init(struct mem_pool *pool, size_t initial_size);\n \n /*\n- * Discard a memory pool and free all the memory it is responsible for.\n+ * Discard all the memory the memory pool is responsible for.\n  */\n void mem_pool_discard(struct mem_pool *mem_pool, int invalidate_memory);\n \ndiff --git a/read-cache.c b/read-cache.c\nindex 8ed1c29b54..fa291cdbee 100644\n--- a/read-cache.c\n+++ b/read-cache.c\n@@ -89,8 +89,10 @@ static struct mem_pool *find_mem_pool(struct index_state *istate)\n \telse\n \t\tpool_ptr = &istate->ce_mem_pool;\n \n-\tif (!*pool_ptr)\n-\t\tmem_pool_init(pool_ptr, 0);\n+\tif (!*pool_ptr) {\n+\t\t*pool_ptr = xmalloc(sizeof(**pool_ptr));\n+\t\tmem_pool_init(*pool_ptr, 0);\n+\t}\n \n \treturn *pool_ptr;\n }\n@@ -2006,11 +2008,12 @@ static unsigned long load_all_cache_entries(struct index_state *istate,\n {\n \tunsigned long consumed;\n \n+\tistate->ce_mem_pool = xmalloc(sizeof(*istate->ce_mem_pool));\n \tif (istate->version == 4) {\n-\t\tmem_pool_init(&istate->ce_mem_pool,\n+\t\tmem_pool_init(istate->ce_mem_pool,\n \t\t\t\testimate_cache_size_from_compressed(istate->cache_nr));\n \t} else {\n-\t\tmem_pool_init(&istate->ce_mem_pool,\n+\t\tmem_pool_init(istate->ce_mem_pool,\n \t\t\t\testimate_cache_size(mmap_size, istate->cache_nr));\n \t}\n \n@@ -2070,7 +2073,8 @@ static unsigned long load_cache_entries_threaded(struct index_state *istate, con\n \tif (istate->name_hash_initialized)\n \t\tBUG(\"the name hash isn't thread safe\");\n \n-\tmem_pool_init(&istate->ce_mem_pool, 0);\n+\tistate->ce_mem_pool = xmalloc(sizeof(*istate->ce_mem_pool));\n+\tmem_pool_init(istate->ce_mem_pool, 0);\n \n \t/* ensure we have no more threads than we have blocks to process */\n \tif (nr_threads > ieot->nr)\n@@ -2097,11 +2101,12 @@ static unsigned long load_cache_entries_threaded(struct index_state *istate, con\n \t\tnr = 0;\n \t\tfor (j = p->ieot_start; j < p->ieot_start + p->ieot_blocks; j++)\n \t\t\tnr += p->ieot->entries[j].nr;\n+\t\tistate->ce_mem_pool = xmalloc(sizeof(*istate->ce_mem_pool));\n \t\tif (istate->version == 4) {\n-\t\t\tmem_pool_init(&p->ce_mem_pool,\n+\t\t\tmem_pool_init(p->ce_mem_pool,\n \t\t\t\testimate_cache_size_from_compressed(nr));\n \t\t} else {\n-\t\t\tmem_pool_init(&p->ce_mem_pool,\n+\t\t\tmem_pool_init(p->ce_mem_pool,\n \t\t\t\testimate_cache_size(mmap_size, nr));\n \t\t}\n \n@@ -2358,7 +2363,7 @@ int discard_index(struct index_state *istate)\n \n \tif (istate->ce_mem_pool) {\n \t\tmem_pool_discard(istate->ce_mem_pool, should_validate_cache_entries());\n-\t\tistate->ce_mem_pool = NULL;\n+\t\tFREE_AND_NULL(istate->ce_mem_pool);\n \t}\n \n \treturn 0;\ndiff --git a/split-index.c b/split-index.c\nindex e6154e4ea9..c0e8ad670d 100644\n--- a/split-index.c\n+++ b/split-index.c\n@@ -79,8 +79,10 @@ void move_cache_to_base_index(struct index_state *istate)\n \tif (si->base &&\n \t\tsi->base->ce_mem_pool) {\n \n-\t\tif (!istate->ce_mem_pool)\n-\t\t\tmem_pool_init(&istate->ce_mem_pool, 0);\n+\t\tif (!istate->ce_mem_pool) {\n+\t\t\tistate->ce_mem_pool = xmalloc(sizeof(struct mem_pool));\n+\t\t\tmem_pool_init(istate->ce_mem_pool, 0);\n+\t\t}\n \n \t\tmem_pool_combine(istate->ce_mem_pool, istate->split_index->base->ce_mem_pool);\n \t}\n-- \ngitgitgadget\n\n"},{"id":"403771","messageId":"e7f6bf8a8ce441dcbfcf36b4043c23066464573a.1597513078.git.gitgitgadget@gmail.com","threadId":"54041","inReplyTo":"pull.830.v3.git.git.1597513078.gitgitgadget@gmail.com","subject":"[PATCH v3 1/3] mem-pool: add convenience functions for strdup and strndup","fromName":"Elijah Newren via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2020-08-15T17:37:55Z","receivedAt":"2020-08-15T22:04:38Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"From: Elijah Newren <newren@gmail.com>\n\nfast-import had a special mem_pool_strdup() convenience function that I\nwant to be able to use from the new merge algorithm I am writing.  Move\nit from fast-import to mem-pool, and also add a mem_pool_strndup()\nwhile at it that I also want to use.\n\nSigned-off-by: Elijah Newren <newren@gmail.com>\n---\n fast-import.c | 12 ++----------\n mem-pool.c    | 18 ++++++++++++++++++\n mem-pool.h    |  6 ++++++\n 3 files changed, 26 insertions(+), 10 deletions(-)\n\ndiff --git a/fast-import.c b/fast-import.c\nindex ce47794db6..c45fe7474c 100644\n--- a/fast-import.c\n+++ b/fast-import.c\n@@ -526,14 +526,6 @@ static unsigned int hc_str(const char *s, size_t len)\n \treturn r;\n }\n \n-static char *pool_strdup(const char *s)\n-{\n-\tsize_t len = strlen(s) + 1;\n-\tchar *r = mem_pool_alloc(&fi_mem_pool, len);\n-\tmemcpy(r, s, len);\n-\treturn r;\n-}\n-\n static void insert_mark(struct mark_set *s, uintmax_t idnum, struct object_entry *oe)\n {\n \twhile ((idnum >> s->shift) >= 1024) {\n@@ -615,7 +607,7 @@ static struct branch *new_branch(const char *name)\n \t\tdie(\"Branch name doesn't conform to GIT standards: %s\", name);\n \n \tb = mem_pool_calloc(&fi_mem_pool, 1, sizeof(struct branch));\n-\tb->name = pool_strdup(name);\n+\tb->name = mem_pool_strdup(&fi_mem_pool, name);\n \tb->table_next_branch = branch_table[hc];\n \tb->branch_tree.versions[0].mode = S_IFDIR;\n \tb->branch_tree.versions[1].mode = S_IFDIR;\n@@ -2806,7 +2798,7 @@ static void parse_new_tag(const char *arg)\n \n \tt = mem_pool_alloc(&fi_mem_pool, sizeof(struct tag));\n \tmemset(t, 0, sizeof(struct tag));\n-\tt->name = pool_strdup(arg);\n+\tt->name = mem_pool_strdup(&fi_mem_pool, arg);\n \tif (last_tag)\n \t\tlast_tag->next_tag = t;\n \telse\ndiff --git a/mem-pool.c b/mem-pool.c\nindex a2841a4a9a..020b51e0c5 100644\n--- a/mem-pool.c\n+++ b/mem-pool.c\n@@ -102,6 +102,24 @@ void *mem_pool_calloc(struct mem_pool *mem_pool, size_t count, size_t size)\n \treturn r;\n }\n \n+char *mem_pool_strdup(struct mem_pool *pool, const char *str)\n+{\n+\tsize_t len = strlen(str) + 1;\n+\tchar *ret = mem_pool_alloc(pool, len);\n+\n+\treturn memcpy(ret, str, len);\n+}\n+\n+char *mem_pool_strndup(struct mem_pool *pool, const char *str, size_t len)\n+{\n+\tchar *p = memchr(str, '\\0', len);\n+\tsize_t actual_len = (p ? p - str : len);\n+\tchar *ret = mem_pool_alloc(pool, actual_len+1);\n+\n+\tret[actual_len] = '\\0';\n+\treturn memcpy(ret, str, actual_len);\n+}\n+\n int mem_pool_contains(struct mem_pool *mem_pool, void *mem)\n {\n \tstruct mp_block *p;\ndiff --git a/mem-pool.h b/mem-pool.h\nindex 999d3c3a52..ca062c9070 100644\n--- a/mem-pool.h\n+++ b/mem-pool.h\n@@ -41,6 +41,12 @@ void *mem_pool_alloc(struct mem_pool *pool, size_t len);\n  */\n void *mem_pool_calloc(struct mem_pool *pool, size_t count, size_t size);\n \n+/*\n+ * Allocate memory from the memory pool and copy str into it.\n+ */\n+char *mem_pool_strdup(struct mem_pool *pool, const char *str);\n+char *mem_pool_strndup(struct mem_pool *pool, const char *str, size_t len);\n+\n /*\n  * Move the memory associated with the 'src' pool to the 'dst' pool. The 'src'\n  * pool will be empty and not contain any memory. It still needs to be free'd\n-- \ngitgitgadget\n\n"},{"id":"403777","messageId":"pull.830.v3.git.git.1597513078.gitgitgadget@gmail.com","threadId":"54041","inReplyTo":"pull.830.v2.git.git.1597384820.gitgitgadget@gmail.com","subject":"[PATCH v3 0/3] Extend and add a little more generalization to the mem_pool API","fromName":"Elijah Newren via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2020-08-15T17:37:54Z","receivedAt":"2020-08-15T22:07:32Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"In my new merge algorithm, I made use of the mem_pool API in a few\nplaces...but I also needed to add a few more functions and also needed to\nmake the API a bit more general.\n\nChanges since v2:\n\n * Remove 'x' from mem_pool_xstr[n]?dup() names and remove check for NULL\n   since mem_pool_alloc() already handles that (via xmalloc), as suggested\n   by René\n * Rewrite mem_pool_strndup() to not rely on strnlen(), since that may be\n   too new from some systems (comes from POSIX 2008 ). Also pointed out by\n   René\n\nElijah Newren (3):\n  mem-pool: add convenience functions for strdup and strndup\n  mem-pool: use more standard initialization and finalization\n  mem-pool: use consistent pool variable name\n\n fast-import.c | 12 ++-------\n mem-pool.c    | 69 ++++++++++++++++++++++++++++++---------------------\n mem-pool.h    | 14 ++++++++---\n read-cache.c  | 21 ++++++++++------\n split-index.c |  6 +++--\n 5 files changed, 70 insertions(+), 52 deletions(-)\n\n\nbase-commit: 7814e8a05a59c0cf5fb186661d1551c75d1299b5\nPublished-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-830%2Fnewren%2Fmem_pool_api-v3\nFetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-830/newren/mem_pool_api-v3\nPull-Request: https://github.com/git/git/pull/830\n\nRange-diff vs v2:\n\n 1:  6d679c5b46 ! 1:  e7f6bf8a8c mem-pool: add convenience functions for xstrdup and xstrndup\n     @@ Metadata\n      Author: Elijah Newren <newren@gmail.com>\n      \n       ## Commit message ##\n     -    mem-pool: add convenience functions for xstrdup and xstrndup\n     +    mem-pool: add convenience functions for strdup and strndup\n      \n     -    fast-import had a special mem_pool_xstrdup() convenience function that I\n     +    fast-import had a special mem_pool_strdup() convenience function that I\n          want to be able to use from the new merge algorithm I am writing.  Move\n     -    it from fast-import to mem-pool, and also add a mem_pool_xstrndup()\n     +    it from fast-import to mem-pool, and also add a mem_pool_strndup()\n          while at it that I also want to use.\n      \n          Signed-off-by: Elijah Newren <newren@gmail.com>\n     @@ fast-import.c: static struct branch *new_branch(const char *name)\n       \n       \tb = mem_pool_calloc(&fi_mem_pool, 1, sizeof(struct branch));\n      -\tb->name = pool_strdup(name);\n     -+\tb->name = mem_pool_xstrdup(&fi_mem_pool, name);\n     ++\tb->name = mem_pool_strdup(&fi_mem_pool, name);\n       \tb->table_next_branch = branch_table[hc];\n       \tb->branch_tree.versions[0].mode = S_IFDIR;\n       \tb->branch_tree.versions[1].mode = S_IFDIR;\n     @@ fast-import.c: static void parse_new_tag(const char *arg)\n       \tt = mem_pool_alloc(&fi_mem_pool, sizeof(struct tag));\n       \tmemset(t, 0, sizeof(struct tag));\n      -\tt->name = pool_strdup(arg);\n     -+\tt->name = mem_pool_xstrdup(&fi_mem_pool, arg);\n     ++\tt->name = mem_pool_strdup(&fi_mem_pool, arg);\n       \tif (last_tag)\n       \t\tlast_tag->next_tag = t;\n       \telse\n     @@ mem-pool.c: void *mem_pool_calloc(struct mem_pool *mem_pool, size_t count, size_\n       \treturn r;\n       }\n       \n     -+char *mem_pool_xstrdup(struct mem_pool *pool, const char *str)\n     ++char *mem_pool_strdup(struct mem_pool *pool, const char *str)\n      +{\n      +\tsize_t len = strlen(str) + 1;\n      +\tchar *ret = mem_pool_alloc(pool, len);\n      +\n     -+\tif (!ret)\n     -+\t\tdie(_(\"mem_pool_xstrdup: out of memory\"));\n     -+\n      +\treturn memcpy(ret, str, len);\n      +}\n      +\n     -+char *mem_pool_xstrndup(struct mem_pool *pool, const char *str, size_t len)\n     ++char *mem_pool_strndup(struct mem_pool *pool, const char *str, size_t len)\n      +{\n     -+\tsize_t minlen = strnlen(str, len);\n     -+\tchar *ret = mem_pool_alloc(pool, minlen+1);\n     -+\n     -+\tif (!ret)\n     -+\t\tdie(_(\"mem_pool_xstrndup: out of memory\"));\n     ++\tchar *p = memchr(str, '\\0', len);\n     ++\tsize_t actual_len = (p ? p - str : len);\n     ++\tchar *ret = mem_pool_alloc(pool, actual_len+1);\n      +\n     -+\tret[minlen] = '\\0';\n     -+\treturn memcpy(ret, str, minlen);\n     ++\tret[actual_len] = '\\0';\n     ++\treturn memcpy(ret, str, actual_len);\n      +}\n      +\n       int mem_pool_contains(struct mem_pool *mem_pool, void *mem)\n     @@ mem-pool.h: void *mem_pool_alloc(struct mem_pool *pool, size_t len);\n      +/*\n      + * Allocate memory from the memory pool and copy str into it.\n      + */\n     -+char *mem_pool_xstrdup(struct mem_pool *pool, const char *str);\n     -+char *mem_pool_xstrndup(struct mem_pool *pool, const char *str, size_t len);\n     ++char *mem_pool_strdup(struct mem_pool *pool, const char *str);\n     ++char *mem_pool_strndup(struct mem_pool *pool, const char *str, size_t len);\n      +\n       /*\n        * Move the memory associated with the 'src' pool to the 'dst' pool. The 'src'\n 2:  e04ba96b22 = 2:  65f334f5cf mem-pool: use more standard initialization and finalization\n 3:  616402c64e ! 3:  09976779c3 mem-pool: use consistent pool variable name\n     @@ mem-pool.c: void *mem_pool_alloc(struct mem_pool *mem_pool, size_t len)\n       \tmemset(r, 0, len);\n       \treturn r;\n       }\n     -@@ mem-pool.c: char *mem_pool_xstrndup(struct mem_pool *pool, const char *str, size_t len)\n     - \treturn memcpy(ret, str, minlen);\n     +@@ mem-pool.c: char *mem_pool_strndup(struct mem_pool *pool, const char *str, size_t len)\n     + \treturn memcpy(ret, str, actual_len);\n       }\n       \n      -int mem_pool_contains(struct mem_pool *mem_pool, void *mem)\n\n-- \ngitgitgadget\n"},{"id":"403964","messageId":"xmqqsgcjycu3.fsf@gitster.c.googlers.com","threadId":"54041","inReplyTo":"pull.830.v3.git.git.1597513078.gitgitgadget@gmail.com","subject":"Re: [PATCH v3 0/3] Extend and add a little more generalization to the mem_pool API","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2020-08-18T19:27:00Z","receivedAt":"2020-08-18T19:27:08Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"Elijah Newren via GitGitGadget\" <gitgitgadget@gmail.com> writes:\n\n> In my new merge algorithm, I made use of the mem_pool API in a few\n> places...but I also needed to add a few more functions and also needed to\n> make the API a bit more general.\n>\n> Changes since v2:\n>\n>  * Remove 'x' from mem_pool_xstr[n]?dup() names and remove check for NULL\n>    since mem_pool_alloc() already handles that (via xmalloc), as suggested\n>    by René\n>  * Rewrite mem_pool_strndup() to not rely on strnlen(), since that may be\n>    too new from some systems (comes from POSIX 2008 ). Also pointed out by\n>    René\n\nThanks; will queue.\n\n"}]}