> > +static apr_status_t apr_json_decode_array(apr_json_scanner_t * self, > + apr_array_header_t ** retval) > +{ > + apr_status_t status = APR_SUCCESS; > + apr_pool_t *link_pool = NULL; > + json_link_t *head = NULL, *tail = NULL; > + apr_size_t count = 0; > + > + if ((status = apr_pool_create(&link_pool, self->pool))) > + return status;
Since the other apr_json_decode_*() functions are not thread-safe (and shouldn't be), couldn't we (re)use a single self->ptemp here (cleared before leaving)? The locking potentially done by apr_pool_create() looks unnecessary, or at least a single subpool for the mutually recursive calls to apr_json_decode_*() would be enough. > + > + if (self->p >= self->e) { > + status = APR_EOF; > + goto out; > + } Before creating the subpool above maybe? > + > + self->level--; > + if (self->level < 0) { > + return APR_EINVAL; > + } Ditto (here moreover the subpool leaks). Also possibly don't change the level if it's already <= 0? > + > + self->p++; /* toss of the leading [ */ > + > + for (;;) { > + apr_json_value_t *element; > + json_link_t *new_node; > + > + if (self->p == self->e) { > + status = APR_EOF; > + goto out; > + } > + > + if (*self->p == ']') { > + self->p++; > + break; > + } > + > + if (APR_SUCCESS != (status = apr_json_decode_value(self, &element))) > { > + goto out; > + } > + > + new_node = apr_pcalloc(link_pool, sizeof(json_link_t)); > + new_node->value = element; > + if (tail) { > + tail->next = new_node; > + } > + else { > + head = new_node; > + } > + tail = new_node; > + count++; > + > + if (self->p == self->e) { > + status = APR_EOF; > + goto out; > + } > + > + if (*self->p == ',') { > + self->p++; > + } > + else if (*self->p != ']') { > + status = APR_BADCH; > + goto out; > + } > + } > + > + { > + json_link_t *node; > + apr_array_header_t *array = apr_array_make(self->pool, count, > sizeof(apr_json_value_t *)); > + for (node = head; node; node = node->next) { > + *((apr_json_value_t **) (apr_array_push(array))) = node->value; > + } > + *retval = array; > + } Hmm, finally we may not need to count the entries in a first loop (hence any subpool), couldn't we let the array auto-grow by itself in the loop and do validation + add in a single pass? > + > + self->level++; > + > +out: > + if (link_pool) { > + apr_pool_destroy(link_pool); > + } > + return status; > +} > + > +static apr_status_t apr_json_decode_object(apr_json_scanner_t * self, > + apr_json_object_t ** retval) > +{ > + apr_status_t status = APR_SUCCESS; > + > + apr_json_object_t *object = apr_json_object_create(self->pool); > + > + if (self->p >= self->e) { > + return APR_EOF; > + } > + > + self->level--; > + if (self->level < 0) { > + return APR_EINVAL; > + } Same here: if (self->level <= 0) return APR_EINVAL; self->level--; > > + self->p++; /* toss of the leading { */ > + > + for (;;) { > + apr_json_value_t *key; > + apr_json_value_t *value; > + > + if (self->p == self->e) { > + status = APR_EOF; > + goto out; > + } > + > + if (*self->p == '}') { > + self->p++; > + break; > + } > + > + if ((status = apr_json_decode_value(self, &key))) > + goto out; Maybe apr_json_decode_string() where we'd require/validate the leading/trailing quotes? > + > + if (key->type != APR_JSON_STRING) { > + status = APR_BADCH; > + goto out; > + } > + > + if (self->p == self->e) { > + status = APR_EOF; > + goto out; > + } > + > + if (*self->p != ':') { > + status = APR_BADCH; > + goto out; > + } > + > + self->p++; /* eat the ':' */ > + > + if (self->p == self->e) { > + status = APR_EOF; > + goto out; > + } > + > + if ((status = apr_json_decode_value(self, &value))) > + goto out; > + > + apr_json_object_set(object, key, value, self->pool); > + > + if (self->p == self->e) { > + status = APR_EOF; > + goto out; > + } > + > + if (*self->p == ',') { > + self->p++; > + } > + else if (*self->p != '}') { > + status = APR_BADCH; > + goto out; > + } > + } > + > + self->level++; > + > + *retval = object; > +out: > + return status; > +}