Skip to content

Commit

Permalink
fsm_generate_matches: Add seed argument, random choice if non-zero.
Browse files Browse the repository at this point in the history
There isn't a flag to set the seed in fsm or re yet.

Update callers, add a 0 seed argument to default to the
existing behavior.

Also, no end states means nothing to do, so exit right away.
  • Loading branch information
silentbicycle committed Oct 11, 2024
1 parent bfeb7ce commit a61a9da
Show file tree
Hide file tree
Showing 7 changed files with 74 additions and 10 deletions.
6 changes: 5 additions & 1 deletion include/fsm/walk.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,10 @@ fsm_walk_edges(const struct fsm *fsm, void *opaque,
* functionally equivalent cases makes testing dramatically faster,
* but exploring every edge could be added later.
*
* If seed is zero then it will generate the first label in the label
* set, otherwise a label from the set will be chosen using rand()
* (favoring printable characters).
*
* Note: fsm is non-const because it calls fsm_trim on the FSM
* internally. This records the shortest distance from each state to an
* end state, which is used to prune branches that would not produce
Expand All @@ -114,7 +118,7 @@ fsm_generate_matches_cb(const struct fsm *fsm,
const char *input, size_t input_length,
fsm_state_t end_state, void *opaque);
int
fsm_generate_matches(struct fsm *fsm, size_t max_length,
fsm_generate_matches(struct fsm *fsm, size_t max_length, unsigned seed,
fsm_generate_matches_cb *cb, void *opaque);

/* Callback provided for the most basic use case for
Expand Down
2 changes: 1 addition & 1 deletion src/fsm/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -770,7 +770,7 @@ main(int argc, char *argv[])
}

if (generate_bounds > 0) {
r = fsm_generate_matches(fsm, generate_bounds, fsm_generate_cb_printf_escaped, &opt);
r = fsm_generate_matches(fsm, generate_bounds, 0, fsm_generate_cb_printf_escaped, &opt);
}

fsm_free(fsm);
Expand Down
69 changes: 64 additions & 5 deletions src/libfsm/gen.c
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ struct gen_ctx {
fsm_generate_matches_cb *cb;

bool done;
bool randomized;

size_t buf_ceil;
size_t buf_used;
Expand Down Expand Up @@ -139,17 +140,21 @@ static bool
grow_stack(struct gen_ctx *ctx);

int
fsm_generate_matches(struct fsm *fsm, size_t max_length,
fsm_generate_matches(struct fsm *fsm, size_t max_length, unsigned seed,
fsm_generate_matches_cb *cb, void *opaque)
{
if (max_length == 0) {
errno = EINVAL;
return 0;
}

if (!fsm_has(fsm, fsm_isend)) {
return 1; /* no end state -> nothing to do */
}

INIT_TIMERS();
TIME(&pre);
int res = gen_init_outer(fsm, max_length, cb, opaque, false, 0);
int res = gen_init_outer(fsm, max_length, cb, opaque, seed != 0, seed);
TIME(&post);

DIFF_MSEC("fsm_generate_matches", pre, post, NULL);
Expand Down Expand Up @@ -208,8 +213,9 @@ gen_init_outer(struct fsm *fsm, size_t max_length,

assert(fsm_all(fsm, fsm_isdfa)); /* DFA-only */

assert(!randomized); /* not yet supported */
(void)seed;
if (randomized) {
srand(seed);
}

#if LOG_GEN > 1
fprintf(stderr, "%s: %u states\n", __func__, fsm_countstates(fsm));
Expand All @@ -224,6 +230,7 @@ gen_init_outer(struct fsm *fsm, size_t max_length,
.max_length = max_length,
.cb = cb,
.opaque = opaque,
.randomized = randomized,
};

if (!gen_init(&ctx, fsm)) {
Expand Down Expand Up @@ -524,6 +531,55 @@ first_symbol(const uint64_t *symbols)
return 0;
}

static unsigned char
random_symbol(const uint64_t *symbols)
{
bool has_zero = false;
unsigned i = 0;

/* printable and non-printable character choices */
size_t choice_count = 0;
unsigned char choices[256];
size_t np_choice_count = 0;
unsigned char np_choices[256];

while (i < 256) {
const uint64_t w = symbols[i/64];
if ((i & 63) == 0 && w == 0) {
i += 64;
continue;
}
if (w & (1ULL << (i & 63))) {
if (i == 0) {
has_zero = true;
} else if (isprint(i)) {
choices[choice_count++] = (unsigned char)i;
} else {
np_choices[np_choice_count++] = (unsigned char)i;
}
}
i++;
}

if (choice_count > 0) {
const size_t c = rand() % choice_count;
return choices[c];
}

if (np_choice_count > 0) {
const size_t c = rand() % np_choice_count;
return np_choices[c];
}

/* Prefer anything besides 0x00 if present, since that will truncate the string. */
if (has_zero) {
return 0;
}

assert(!"empty set");
return 0;
}

#if DUMP_EDGES
static void
dump_edges(fsm_state_t state, struct edge_set *edges)
Expand All @@ -538,6 +594,7 @@ dump_edges(fsm_state_t state, struct edge_set *edges)
size_t i = 0;
while (edge_set_group_iter_next(&ei, &eg)) {
const unsigned char symbol = first_symbol(eg.symbols);
const unsigned char symbol = random_symbol(eg.symbols);
fprintf(stderr, "%s: %d -- %zu/%zu -- 0x%02x (%c) -> %d\n",
__func__, state, i, count,
symbol, isprint(symbol) ? symbol : '.', eg.to);
Expand Down Expand Up @@ -585,7 +642,9 @@ sfs_step_edges(struct gen_ctx *ctx, struct gen_stack_frame *sf)
struct edge_group_iter_info eg;

if (iter_next_transition(ctx, sf, &eg)) {
const unsigned char symbol = first_symbol(eg.symbols);
const unsigned char symbol = ctx->randomized
? random_symbol(eg.symbols)
: first_symbol(eg.symbols);
const fsm_state_t state = eg.to;

LOG(2, "sfs_step_edges: got edge 0x%x ('%c')\n",
Expand Down
2 changes: 1 addition & 1 deletion src/re/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -1047,7 +1047,7 @@ main(int argc, char *argv[])
}

if (generate_bounds > 0) {
if (!fsm_generate_matches(fsm, generate_bounds, fsm_generate_cb_printf_escaped, &opt)) {
if (!fsm_generate_matches(fsm, generate_bounds, 0, fsm_generate_cb_printf_escaped, &opt)) {
exit(EXIT_FAILURE);
}

Expand Down
1 change: 1 addition & 0 deletions tests/gen/gen1.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ int main(void) {
assert(fsm != NULL);

if (!fsm_generate_matches(fsm, MAX_EXP_MATCH + 1 /* for \0 */,
0,
gtest_matches_cb, &matches)) {
fprintf(stderr, "fsm_generate_matches: error\n");
exit(EXIT_FAILURE);
Expand Down
2 changes: 1 addition & 1 deletion tests/gen/gen2.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ int main(void) {
struct fsm *fsm = gtest_fsm_of_matches(&matches);
assert(fsm != NULL);

if (!fsm_generate_matches(fsm, MAX_EXP_MATCH + 1, gtest_matches_cb, &matches)) {
if (!fsm_generate_matches(fsm, MAX_EXP_MATCH + 1, 0, gtest_matches_cb, &matches)) {
fprintf(stderr, "fsm_generate_matches: error\n");
exit(EXIT_FAILURE);
}
Expand Down
2 changes: 1 addition & 1 deletion tests/gen/gen3.c
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ int main(void) {
struct fsm *fsm = build();
assert(fsm != NULL);

if (!fsm_generate_matches(fsm, 11, matches_cb, NULL)) {
if (!fsm_generate_matches(fsm, 11, 0, matches_cb, NULL)) {
fprintf(stderr, "fsm_generate_matches: error\n");
exit(EXIT_FAILURE);
}
Expand Down

0 comments on commit a61a9da

Please sign in to comment.