Skip to content

Commit 985c708

Browse files
InterLinked1jcolp
authored andcommitted
pbx_functions.c: Manually update ast_str strlen.
When ast_func_read2 is used to read a function using its read function (as opposed to a native ast_str read2 function), the result is copied directly by the function into the ast_str buffer. As a result, the ast_str length remains initialized to 0, which is a bug because this is not the real string length. This can cascade and have issues elsewhere, such as when reading substrings of functions that only register read as opposed to read2 callbacks. In this case, since reading ast_str_strlen returns 0, the returned substring is empty as opposed to the actual substring. This has caused the ast_str family of functions to behave inconsistently and erroneously, in contrast to the pbx_variables substitution functions which work correctly. This fixes this issue by manually updating the ast_str length when the result is copied directly into the ast_str buffer. Additionally, an assertion and a unit test that previously exposed these issues are added, now that the issue is fixed. ASTERISK-29966 #close Change-Id: I4e2dba41410f9d4dff61c995d2ca27718248e07f
1 parent 30022e0 commit 985c708

File tree

2 files changed

+74
-0
lines changed

2 files changed

+74
-0
lines changed

main/pbx_functions.c

+1
Original file line numberDiff line numberDiff line change
@@ -678,6 +678,7 @@ int ast_func_read2(struct ast_channel *chan, const char *function, struct ast_st
678678
ast_str_make_space(str, maxsize);
679679
}
680680
res = acfptr->read(chan, copy, args, ast_str_buffer(*str), maxsize);
681+
ast_str_update(*str); /* Manually set the string length */
681682
}
682683
if (acfptr->mod && u) {
683684
__ast_module_user_remove(acfptr->mod, u);

main/pbx_variables.c

+73
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
#include "asterisk/paths.h"
4141
#include "asterisk/pbx.h"
4242
#include "asterisk/stasis_channels.h"
43+
#include "asterisk/test.h"
4344
#include "pbx_private.h"
4445

4546
/*** DOCUMENTATION
@@ -189,6 +190,8 @@ static const char *ast_str_substring(struct ast_str *value, int offset, int leng
189190

190191
lr = ast_str_strlen(value); /* compute length after copy, so we never go out of the workspace */
191192

193+
ast_assert(lr == strlen(ast_str_buffer(value))); /* ast_str_strlen should always agree with strlen */
194+
192195
/* Quick check if no need to do anything */
193196
if (offset == 0 && length >= lr) /* take the whole string */
194197
return ast_str_buffer(value);
@@ -1292,6 +1295,74 @@ void pbx_builtin_clear_globals(void)
12921295
ast_rwlock_unlock(&globalslock);
12931296
}
12941297

1298+
#ifdef TEST_FRAMEWORK
1299+
AST_TEST_DEFINE(test_variable_substrings)
1300+
{
1301+
int i, res = AST_TEST_PASS;
1302+
struct ast_channel *chan; /* dummy channel */
1303+
struct ast_str *str; /* fancy string for holding comparing value */
1304+
1305+
const char *test_strings[][5] = {
1306+
{"somevaluehere", "CALLERID(num):0:25", "somevaluehere"},
1307+
{"somevaluehere", "CALLERID(num):0:5", "somev"},
1308+
{"somevaluehere", "CALLERID(num):4:5", "value"},
1309+
{"somevaluehere", "CALLERID(num):0:-4", "somevalue"},
1310+
{"somevaluehere", "CALLERID(num):-4", "here"},
1311+
};
1312+
1313+
switch (cmd) {
1314+
case TEST_INIT:
1315+
info->name = "variable_substrings";
1316+
info->category = "/main/pbx/";
1317+
info->summary = "Test variable substring resolution";
1318+
info->description = "Verify that variable substrings are calculated correctly";
1319+
return AST_TEST_NOT_RUN;
1320+
case TEST_EXECUTE:
1321+
break;
1322+
}
1323+
1324+
if (!(chan = ast_dummy_channel_alloc())) {
1325+
ast_test_status_update(test, "Unable to allocate dummy channel\n");
1326+
return AST_TEST_FAIL;
1327+
}
1328+
1329+
if (!(str = ast_str_create(64))) {
1330+
ast_test_status_update(test, "Unable to allocate dynamic string buffer\n");
1331+
ast_channel_release(chan);
1332+
return AST_TEST_FAIL;
1333+
}
1334+
1335+
for (i = 0; i < ARRAY_LEN(test_strings); i++) {
1336+
char substituted[512], tmp[512] = "";
1337+
1338+
ast_set_callerid(chan, test_strings[i][0], NULL, test_strings[i][0]);
1339+
1340+
snprintf(tmp, sizeof(tmp), "${%s}", test_strings[i][1]);
1341+
1342+
/* test ast_str_substitute_variables */
1343+
ast_str_substitute_variables(&str, 0, chan, tmp);
1344+
ast_debug(1, "Comparing STR %s with %s\n", ast_str_buffer(str), test_strings[i][2]);
1345+
if (strcmp(test_strings[i][2], ast_str_buffer(str))) {
1346+
ast_test_status_update(test, "Format string '%s' substituted to '%s' using str sub. Expected '%s'.\n", test_strings[i][0], ast_str_buffer(str), test_strings[i][2]);
1347+
res = AST_TEST_FAIL;
1348+
}
1349+
1350+
/* test pbx_substitute_variables_helper */
1351+
pbx_substitute_variables_helper(chan, tmp, substituted, sizeof(substituted) - 1);
1352+
ast_debug(1, "Comparing PBX %s with %s\n", substituted, test_strings[i][2]);
1353+
if (strcmp(test_strings[i][2], substituted)) {
1354+
ast_test_status_update(test, "Format string '%s' substituted to '%s' using pbx sub. Expected '%s'.\n", test_strings[i][0], substituted, test_strings[i][2]);
1355+
res = AST_TEST_FAIL;
1356+
}
1357+
}
1358+
ast_free(str);
1359+
1360+
ast_channel_release(chan);
1361+
1362+
return res;
1363+
}
1364+
#endif
1365+
12951366
static struct ast_cli_entry vars_cli[] = {
12961367
AST_CLI_DEFINE(handle_show_globals, "Show global dialplan variables"),
12971368
AST_CLI_DEFINE(handle_show_chanvar, "Show channel variables"),
@@ -1306,6 +1377,7 @@ static void unload_pbx_variables(void)
13061377
ast_unregister_application("Set");
13071378
ast_unregister_application("MSet");
13081379
pbx_builtin_clear_globals();
1380+
AST_TEST_UNREGISTER(test_variable_substrings);
13091381
}
13101382

13111383
int load_pbx_variables(void)
@@ -1316,6 +1388,7 @@ int load_pbx_variables(void)
13161388
res |= ast_register_application2("Set", pbx_builtin_setvar, NULL, NULL, NULL);
13171389
res |= ast_register_application2("MSet", pbx_builtin_setvar_multiple, NULL, NULL, NULL);
13181390
ast_register_cleanup(unload_pbx_variables);
1391+
AST_TEST_REGISTER(test_variable_substrings);
13191392

13201393
return res;
13211394
}

0 commit comments

Comments
 (0)