summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--librpc/ndr/ndr_string.c71
1 files changed, 60 insertions, 11 deletions
diff --git a/librpc/ndr/ndr_string.c b/librpc/ndr/ndr_string.c
index 4fd2006be20..bddab9edd51 100644
--- a/librpc/ndr/ndr_string.c
+++ b/librpc/ndr/ndr_string.c
@@ -348,6 +348,44 @@ _PUBLIC_ uint32_t ndr_size_string(int ret, const char * const* string, int flags
return ret+strlen(*string)+1;
}
+static uint32_t guess_string_array_size(struct ndr_pull *ndr, int ndr_flags)
+{
+ /*
+ * Here we could do something clever like count the number of zeros in
+ * the ndr data, but it is probably sufficient to pick a lowish number
+ * (compared to the overhead of the talloc header) and let the
+ * expontential resizing deal with longer arrays.
+ */
+ return 5;
+}
+
+static enum ndr_err_code extend_string_array(struct ndr_pull *ndr,
+ const char ***_a,
+ uint32_t *count)
+{
+ const char **a = *_a;
+ uint32_t inc = *count / 4 + 3;
+ uint32_t alloc_size = *count + inc;
+
+ if (alloc_size < *count) {
+ /* overflow ! */
+ return NDR_ERR_ALLOC;
+ }
+ /*
+ * We allocate and zero two more bytes than we report back, so that
+ * the string array will always be NULL terminated.
+ */
+ a = talloc_realloc(ndr->current_mem_ctx, a,
+ const char *,
+ alloc_size);
+ NDR_ERR_HAVE_NO_MEMORY(a);
+
+ memset(a + *count, 0, inc * sizeof(a[0]));
+ *_a = a;
+ *count = alloc_size - 2;
+ return NDR_ERR_SUCCESS;
+}
+
/**
pull a general string array from the wire
*/
@@ -357,14 +395,19 @@ _PUBLIC_ enum ndr_err_code ndr_pull_string_array(struct ndr_pull *ndr, int ndr_f
uint32_t count;
unsigned flags = ndr->flags;
unsigned saved_flags = ndr->flags;
+ uint32_t alloc_size;
if (!(ndr_flags & NDR_SCALARS)) {
return NDR_ERR_SUCCESS;
}
+ alloc_size = guess_string_array_size(ndr, ndr_flags);
+ a = talloc_zero_array(ndr->current_mem_ctx, const char *, alloc_size + 2);
+ NDR_ERR_HAVE_NO_MEMORY(a);
+
switch (flags & (LIBNDR_FLAG_STR_NULLTERM|LIBNDR_FLAG_STR_NOTERM)) {
case LIBNDR_FLAG_STR_NULLTERM:
- /*
+ /*
* here the strings are null terminated
* but also the array is null terminated if LIBNDR_FLAG_REMAINING
* is specified
@@ -372,10 +415,11 @@ _PUBLIC_ enum ndr_err_code ndr_pull_string_array(struct ndr_pull *ndr, int ndr_f
for (count = 0;; count++) {
TALLOC_CTX *tmp_ctx;
const char *s = NULL;
- a = talloc_realloc(ndr->current_mem_ctx, a, const char *, count + 2);
- NDR_ERR_HAVE_NO_MEMORY(a);
- a[count] = NULL;
- a[count+1] = NULL;
+ if (count == alloc_size) {
+ NDR_CHECK(extend_string_array(ndr,
+ &a,
+ &alloc_size));
+ }
tmp_ctx = ndr->current_mem_ctx;
ndr->current_mem_ctx = a;
@@ -393,6 +437,8 @@ _PUBLIC_ enum ndr_err_code ndr_pull_string_array(struct ndr_pull *ndr, int ndr_f
a[count] = s;
}
}
+ a = talloc_realloc(ndr->current_mem_ctx, a, const char *, count + 1);
+ NDR_ERR_HAVE_NO_MEMORY(a);
*_a =a;
break;
@@ -404,7 +450,7 @@ _PUBLIC_ enum ndr_err_code ndr_pull_string_array(struct ndr_pull *ndr, int ndr_f
}
/*
* here the strings are not null terminated
- * but serarated by a null terminator
+ * but separated by a null terminator
*
* which means the same as:
* Every string is null terminated exept the last
@@ -422,10 +468,11 @@ _PUBLIC_ enum ndr_err_code ndr_pull_string_array(struct ndr_pull *ndr, int ndr_f
for (count = 0; ((ndr->data_size - ndr->offset) > 0); count++) {
TALLOC_CTX *tmp_ctx;
const char *s = NULL;
- a = talloc_realloc(ndr->current_mem_ctx, a, const char *, count + 2);
- NDR_ERR_HAVE_NO_MEMORY(a);
- a[count] = NULL;
- a[count+1] = NULL;
+ if (count == alloc_size) {
+ NDR_CHECK(extend_string_array(ndr,
+ &a,
+ &alloc_size));
+ }
tmp_ctx = ndr->current_mem_ctx;
ndr->current_mem_ctx = a;
@@ -434,7 +481,9 @@ _PUBLIC_ enum ndr_err_code ndr_pull_string_array(struct ndr_pull *ndr, int ndr_f
a[count] = s;
}
- *_a =a;
+ a = talloc_realloc(ndr->current_mem_ctx, a, const char *, count + 1);
+ NDR_ERR_HAVE_NO_MEMORY(a);
+ *_a = a;
break;
default: