mirror of
https://github.com/signalwire/freeswitch.git
synced 2026-10-04 02:03:59 +00:00
The positive-offset branch of `${variable:offset}` expansion advanced
`sub_val` past the cloned heap buffer without bounds-checking `offset`
against `strlen(sub_val)`. Subsequent `strlen()` and `strcat()` then
read adjacent heap memory into the output buffer.
170 lines
5.0 KiB
C
170 lines
5.0 KiB
C
#include <switch.h>
|
|
#include <test/switch_test.h>
|
|
|
|
// #define BENCHMARK 1
|
|
|
|
FST_MINCORE_BEGIN("./conf")
|
|
|
|
FST_SUITE_BEGIN(switch_event)
|
|
|
|
FST_SETUP_BEGIN()
|
|
{
|
|
}
|
|
FST_SETUP_END()
|
|
|
|
FST_TEARDOWN_BEGIN()
|
|
{
|
|
}
|
|
FST_TEARDOWN_END()
|
|
|
|
FST_TEST_BEGIN(benchmark)
|
|
{
|
|
switch_event_t *event = NULL;
|
|
switch_time_t start_ts, end_ts;
|
|
int loops = 10, x = 0;
|
|
switch_status_t status = SWITCH_STATUS_SUCCESS;
|
|
char **index = NULL;
|
|
uint64_t micro_total = 0;
|
|
double micro_per = 0;
|
|
double rate_per_sec = 0;
|
|
|
|
#ifdef BENCHMARK
|
|
switch_time_t small_start_ts, small_end_ts;
|
|
#endif
|
|
|
|
index = calloc(loops, sizeof(char *));
|
|
for ( x = 0; x < loops; x++) {
|
|
index[x] = switch_mprintf("%d", x);
|
|
}
|
|
|
|
/* START LOOPS */
|
|
start_ts = switch_time_now();
|
|
|
|
status = switch_event_create(&event, SWITCH_EVENT_MESSAGE);
|
|
fst_xcheck(status == SWITCH_STATUS_SUCCESS, "Failed to create event");
|
|
|
|
#ifndef BENCHMARK
|
|
for ( x = 0; x < loops; x++) {
|
|
status = switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, index[x], index[x]);
|
|
fst_xcheck(status == SWITCH_STATUS_SUCCESS, "Failed to add header to event");
|
|
}
|
|
#else
|
|
small_start_ts = switch_time_now();
|
|
for ( x = 0; x < loops; x++) {
|
|
if ( switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, index[x], index[x]) != SWITCH_STATUS_SUCCESS) {
|
|
fst_fail("Failed to add header to event");
|
|
}
|
|
}
|
|
small_end_ts = switch_time_now();
|
|
|
|
micro_total = small_end_ts - small_start_ts;
|
|
micro_per = micro_total / (double) loops;
|
|
rate_per_sec = 1000000 / micro_per;
|
|
printf("switch_event add_header: Total %" SWITCH_UINT64_T_FMT "us / %d loops, %.2f us per loop, %.0f loops per second\n",
|
|
micro_total, loops, micro_per, rate_per_sec);
|
|
#endif
|
|
|
|
|
|
#ifndef BENCHMARK
|
|
for ( x = 0; x < loops; x++) {
|
|
fst_check_string_equals(switch_event_get_header(event, index[x]), index[x]);
|
|
}
|
|
#else
|
|
small_start_ts = switch_time_now();
|
|
for ( x = 0; x < loops; x++) {
|
|
if ( !switch_event_get_header(event, index[x])) {
|
|
fst_fail("Failed to lookup event header value");
|
|
}
|
|
}
|
|
small_end_ts = switch_time_now();
|
|
|
|
micro_total = small_end_ts - small_start_ts;
|
|
micro_per = micro_total / (double) loops;
|
|
rate_per_sec = 1000000 / micro_per;
|
|
printf("switch_event get_header: Total %" SWITCH_UINT64_T_FMT "us / %d loops, %.2f us per loop, %.0f loops per second\n",
|
|
micro_total, loops, micro_per, rate_per_sec);
|
|
#endif
|
|
|
|
switch_event_destroy(&event);
|
|
/* END LOOPS */
|
|
|
|
end_ts = switch_time_now();
|
|
|
|
for ( x = 0; x < loops; x++) {
|
|
free(index[x]);
|
|
}
|
|
free(index);
|
|
|
|
micro_total = end_ts - start_ts;
|
|
micro_per = micro_total / (double) loops;
|
|
rate_per_sec = 1000000 / micro_per;
|
|
printf("switch_event Total %" SWITCH_UINT64_T_FMT "us / %d loops, %.2f us per loop, %.0f loops per second\n",
|
|
micro_total, loops, micro_per, rate_per_sec);
|
|
|
|
}
|
|
FST_TEST_END()
|
|
|
|
FST_TEST_BEGIN(expand_headers_offset)
|
|
{
|
|
/* Covers the ${var:offset[:length]} slicing branches in
|
|
* switch_event_expand_headers_check(). */
|
|
static const struct {
|
|
const char *expr;
|
|
const char *expected;
|
|
const char *note;
|
|
} cases[] = {
|
|
/* offset == 0: no clone (outer offset||ooffset guard is false). */
|
|
{ "${foo:0}", "ABC", "offset=0 identity, no clone" },
|
|
{ "${empty:0}", "", "offset=0 on empty value" },
|
|
/* ooffset alone forces the clone, front offset is a no-op. */
|
|
{ "${foo:0:2}", "AB", "offset=0 with ooffset" },
|
|
/* Positive offset within range. */
|
|
{ "${foo:1}", "BC", "positive in-range" },
|
|
{ "${foo:3}", "", "offset == strlen boundary" },
|
|
{ "${foo:99}", "", "offset > strlen yields empty" },
|
|
{ "${empty:5}", "", "offset > strlen on empty value" },
|
|
/* Combined offset:length form. */
|
|
{ "${foo:1:1}", "B", "offset:length in range" },
|
|
{ "${foo:0:3}", "ABC", "ooffset == strlen, strict < gate skips trim" },
|
|
{ "${foo:99:2}", "", "offset > strlen with ooffset, gate no-ops" },
|
|
/* Negative offsets. */
|
|
{ "${foo:-1}", "C", "negative offset in range" },
|
|
{ "${foo:-3}", "ABC", "abs(offset) == strlen, <= gate boundary" },
|
|
{ "${foo:-99}", "ABC", "abs(offset) > strlen, gate falls through" },
|
|
};
|
|
switch_event_t *event = NULL;
|
|
switch_status_t status;
|
|
size_t i;
|
|
|
|
status = switch_event_create(&event, SWITCH_EVENT_MESSAGE);
|
|
fst_xcheck(status == SWITCH_STATUS_SUCCESS, "Failed to create event");
|
|
|
|
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "foo", "ABC");
|
|
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "empty", "");
|
|
|
|
for (i = 0; i < sizeof(cases) / sizeof(cases[0]); i++) {
|
|
char msg[160];
|
|
char *out = switch_event_expand_headers(event, cases[i].expr);
|
|
|
|
switch_snprintf(msg, sizeof(msg), "%s: %s -> expected '%s', got '%s'",
|
|
cases[i].note, cases[i].expr, cases[i].expected,
|
|
out ? out : "(null)");
|
|
|
|
fst_xcheck(out && !strcmp(out, cases[i].expected), msg);
|
|
|
|
if (out != cases[i].expr) {
|
|
switch_safe_free(out);
|
|
}
|
|
}
|
|
|
|
switch_event_destroy(&event);
|
|
}
|
|
FST_TEST_END()
|
|
|
|
FST_SUITE_END()
|
|
|
|
FST_MINCORE_END()
|
|
|
|
|
|
|