Reputation: 662
I want to implement a variadic function what gets custom type parameters, not like in the GNU's example:
https://www.gnu.org/software/libc/manual/html_node/Variadic-Example.html#Variadic-Example
In my logic I am handling nodes, define by this tpye:
typedef struct node_t {
char *key;
node_type_t type;
apr_array_header_t *arr_strings;
apr_array_header_t *arr_numbers;
} node_t;
Such a node stores infos in different APR arrays,based on a specific type (string, number) type defined in this way:
typedef enum node_type_t {
node_type_string,
node_type_number,
} node_type_t;
The function looks like this:
int add_node(apr_pool_t *p_pool, node_t *p_target_node, ...) {
int rv = 0;
va_list lmnts;
va_start(lmnts, p_target_node);
node_t *n = va_arg(lmnts, node_t *);
apr_array_header_t *tbl;
do {
switch(n->type) {
case node_type_string:
tbl = p_target_node->arr_strings;
break;
case node_type_number:
tbl = p_target_node->arr_numbers;
break;
default:
break;
}
printf("\t\t%d - %s\n", rv, n->key);
*(const node_t**)apr_array_push(tbl) = n;
rv++;
} while (n && ((n = va_arg(lmnts, node_t *)) != NULL) && apr_strnatcmp(n->key, p_target_node->key) != 0);
va_end(lmnts);
return rv;
}
It works for two node_t arguments but for more I get segmentation fault.
This is the complete code:
#include <stdarg.h>
#include <stdio.h>
#include <apr_general.h>
#include <apr_hash.h>
#include <apr_pools.h>
#include <apr_strings.h>
#include <apr_tables.h>
typedef enum node_type_t {
node_type_string,
node_type_number,
} node_type_t;
typedef struct node_t {
char *key;
node_type_t type;
apr_array_header_t *arr_strings;
apr_array_header_t *arr_numbers;
} node_t;
node_t *create_node(apr_pool_t *p_pool, char *p_key, node_type_t p_type) {
node_t *NODE = apr_palloc(p_pool, sizeof(node_t));
NODE->key = p_key;
NODE->type = p_type;
NODE->arr_strings = apr_array_make(p_pool, 0, sizeof(node_t*));
NODE->arr_numbers = apr_array_make(p_pool, 0, sizeof(node_t*));
return NODE;
}
int add_node(apr_pool_t *p_pool, node_t *p_target_node, ...) {
int rv = 0;
va_list lmnts;
va_start(lmnts, p_target_node);
node_t *n = va_arg(lmnts, node_t *);
apr_array_header_t *tbl;
do {
switch(n->type) {
case node_type_string:
tbl = p_target_node->arr_strings;
break;
case node_type_number:
tbl = p_target_node->arr_numbers;
break;
default:
break;
}
printf("\t\t%d - %s\n", rv, n->key);
*(const node_t**)apr_array_push(tbl) = n;
rv++;
} while (n && ((n = va_arg(lmnts, node_t *)) != NULL) && apr_strnatcmp(n->key, p_target_node->key) != 0);
va_end(lmnts);
return rv;
}
int add_node(apr_pool_t *p_pool, node_t *p_target_node, ...) {
int rv = 0;
va_list lmnts;
va_start(lmnts, p_target_node);
node_t *n = va_arg(lmnts, node_t *);
while((n = va_arg(lmnts, node_t *)) != NULL && apr_strnatcmp(n->key, p_target_node->key) != 0) {
printf("\t\t%d - %s\n", rv, n->key);
*(const node_t**)apr_array_push(p_target_node->arr_strings) = n;
rv++;
}
va_end(lmnts);
return rv;
}
int main(int argc, const char *argv[]) {
apr_status_t rv;
apr_pool_t *mp;
rv = apr_initialize();
if (rv != APR_SUCCESS) {
return -1;
}
apr_pool_create(&mp, NULL);
node_t *ROOT_NODE = create_node(mp, "THE_ROOT", node_type_string);
printf("\tROOT_NODE { key: '%s', type: %d, [%d, %d]}\n",
ROOT_NODE->key, ROOT_NODE->type,
ROOT_NODE->arr_strings->nelts, ROOT_NODE->arr_numbers->nelts);
node_t *NODE_A = create_node(mp, "A", node_type_string);
printf("\tNODE_A { key: '%s', type: %d, [%d, %d]}\n",
NODE_A->key, NODE_A->type,
NODE_A->arr_strings->nelts, NODE_A->arr_numbers->nelts);
node_t *NODE_B = create_node(mp, "B", node_type_number);
printf("\tNODE_B { key: '%s', type: %d, [%d, %d]}\n",
NODE_B->key, NODE_B->type,
NODE_B->arr_strings->nelts, NODE_B->arr_numbers->nelts);
node_t *NODE_C = create_node(mp, "C", node_type_string);
printf("\tNODE_C { key: '%s', type: %d, [%d, %d]}\n",
NODE_C->key, NODE_C->type,
NODE_C->arr_strings->nelts, NODE_C->arr_numbers->nelts);
add_node(mp, ROOT_NODE, NODE_A, NODE_B, NODE_C);
printf("\tn = %d, n = %d\n", ROOT_NODE->arr_strings->nelts, ROOT_NODE->arr_numbers->nelts);
apr_pool_destroy(mp);
apr_terminate();
return 0;
}
Upvotes: 1
Views: 398
Reputation: 122429
The problem I see is that your add_node()
seems to check for a NULL
argument to determine that the list of arguments is done, but you never pass a NULL
argument when you call it, so add_node
will continue reading non-existent "arguments" after it goes through all the ones you passed, accessing places in memory it's not supposed to, and causing all sorts of bad problems.
Upvotes: 1