diff options
author | Walter Doekes <walter+asterisk@wjd.nu> | 2014-02-12 08:25:02 +0000 |
---|---|---|
committer | Walter Doekes <walter+asterisk@wjd.nu> | 2014-02-12 08:25:02 +0000 |
commit | 55ee292d454df4346c5edeac57b8955752be7b10 (patch) | |
tree | db79c0a47afd44ab643e5a8dbb4df3a0362a59f1 /main/config.c | |
parent | 6bdf2c4eab6524f85fa2245b9d796f5f4c46911a (diff) |
realtime: Fix ast_update2_realtime() on raspberry pi.
The old code depended on undefined va_arg behaviour: calling a function
twice with the same va_list parameter and expecting it to continue where
it left off. The changed code behaves like the manpage says it should.
Also added a bunch of early returns to trap errors (e.g. OOM) instead of
crashing.
The problem was found by Julian Lyndon-Smith. The deviant behaviour on
the raspberry PI also uncovered another bug (fixed in r407875) in the
res_config_pgsql.so driver.
Reported by: jmls
Tested by: jmls
Review: https://reviewboard.asterisk.org/r/3201/
........
Merged revisions 407968 from http://svn.asterisk.org/svn/asterisk/branches/12
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@407970 65c4cc65-6c06-0410-ace0-fbb531ad65f3
Diffstat (limited to 'main/config.c')
-rw-r--r-- | main/config.c | 79 |
1 files changed, 76 insertions, 3 deletions
diff --git a/main/config.c b/main/config.c index d10d6763c..446bac2df 100644 --- a/main/config.c +++ b/main/config.c @@ -2569,10 +2569,53 @@ struct ast_config *ast_config_load2(const char *filename, const char *who_asked, return result; } -static struct ast_variable *realtime_arguments_to_fields(va_list ap) +#define realtime_arguments_to_fields(ap) realtime_arguments_to_fields2(ap, 0) + +static struct ast_variable *realtime_arguments_to_fields2(va_list ap, int skip) { struct ast_variable *first, *fields = NULL; - const char *newparam = va_arg(ap, const char *), *newval = va_arg(ap, const char *); + const char *newparam; + const char *newval; + + /* + * Previously we would do: + * + * va_start(ap, last); + * x = realtime_arguments_to_fields(ap); + * y = realtime_arguments_to_fields(ap); + * va_end(ap); + * + * While this works on generic amd64 machines (2014), it doesn't on the + * raspberry PI. The va_arg() manpage says: + * + * If ap is passed to a function that uses va_arg(ap,type) then + * the value of ap is undefined after the return of that function. + * + * On the raspberry, ap seems to get reset after the call: the contents + * of y would be equal to the contents of x. + * + * So, instead we allow the caller to skip past earlier argument sets + * using the skip parameter: + * + * va_start(ap, last); + * x = realtime_arguments_to_fields(ap); + * va_end(ap); + * va_start(ap, last); + * y = realtime_arguments_to_fields2(ap, 1); + * va_end(ap); + */ + while (skip--) { + /* There must be at least one argument. */ + newparam = va_arg(ap, const char *); + newval = va_arg(ap, const char *); + while ((newparam = va_arg(ap, const char *))) { + newval = va_arg(ap, const char *); + } + } + + /* Load up the first vars. */ + newparam = va_arg(ap, const char *); + newval = va_arg(ap, const char *); if (!(first = ast_variable_new(newparam, newval, ""))) { return NULL; @@ -2680,6 +2723,10 @@ struct ast_variable *ast_load_realtime(const char *family, ...) fields = realtime_arguments_to_fields(ap); va_end(ap); + if (!fields) { + return NULL; + } + return ast_load_realtime_fields(family, fields); } @@ -2782,6 +2829,10 @@ struct ast_config *ast_load_realtime_multientry(const char *family, ...) fields = realtime_arguments_to_fields(ap); va_end(ap); + if (!fields) { + return NULL; + } + return ast_load_realtime_multientry_fields(family, fields); } @@ -2815,6 +2866,10 @@ int ast_update_realtime(const char *family, const char *keyfield, const char *lo fields = realtime_arguments_to_fields(ap); va_end(ap); + if (!fields) { + return -1; + } + return ast_update_realtime_fields(family, keyfield, lookup, fields); } @@ -2845,10 +2900,20 @@ int ast_update2_realtime(const char *family, ...) va_list ap; va_start(ap, family); + /* XXX: If we wanted to pass no lookup fields (select all), we'd be + * out of luck. realtime_arguments_to_fields expects at least one key + * value pair. */ lookup_fields = realtime_arguments_to_fields(ap); - update_fields = realtime_arguments_to_fields(ap); va_end(ap); + va_start(ap, family); + update_fields = realtime_arguments_to_fields2(ap, 1); + va_end(ap); + + if (!lookup_fields || !update_fields) { + return -1; + } + return ast_update2_realtime_fields(family, lookup_fields, update_fields); } @@ -2882,6 +2947,10 @@ int ast_store_realtime(const char *family, ...) fields = realtime_arguments_to_fields(ap); va_end(ap); + if (!fields) { + return -1; + } + return ast_store_realtime_fields(family, fields); } @@ -2914,6 +2983,10 @@ int ast_destroy_realtime(const char *family, const char *keyfield, const char *l fields = realtime_arguments_to_fields(ap); va_end(ap); + if (!fields) { + return -1; + } + return ast_destroy_realtime_fields(family, keyfield, lookup, fields); } |