Skip to content

Commit

Permalink
Add a regression test for the memory leak.
Browse files Browse the repository at this point in the history
I verified that LeakSanitizer catches the leak during this test when the
fix is reverted.

This commit adds a test directory, `tests/regressions`, for misc.
regression tests that need a .c file and aren't easily testable via fsm,
re, etc. inputs.
  • Loading branch information
silentbicycle committed Nov 8, 2024
1 parent 7ebc1eb commit c9a240a
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 0 deletions.
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ SUBDIR += tests/pcre-repeat
SUBDIR += tests/pred
SUBDIR += tests/re_literal
SUBDIR += tests/re_strings
SUBDIR += tests/regressions
SUBDIR += tests/reverse
SUBDIR += tests/trim
SUBDIR += tests/union
Expand Down
20 changes: 20 additions & 0 deletions tests/regressions/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
.include "../../share/mk/top.mk"

TEST.tests/regressions != ls -1 tests/regressions/regressions*.c
TEST_SRCDIR.tests/regressions = tests/regressions
TEST_OUTDIR.tests/regressions = ${BUILD}/tests/regressions

.for n in ${TEST.tests/regressions:T:R:C/^regressions//}
INCDIR.${TEST_SRCDIR.tests/regressions}/regressions${n}.c += src/adt
.endfor

.for n in ${TEST.tests/regressions:T:R:C/^regressions//}
test:: ${TEST_OUTDIR.tests/regressions}/res${n}
SRC += ${TEST_SRCDIR.tests/regressions}/regressions${n}.c
CFLAGS.${TEST_SRCDIR.tests/regressions}/regressions${n}.c += -UNDEBUG

${TEST_OUTDIR.tests/regressions}/run${n}: ${TEST_OUTDIR.tests/regressions}/regressions${n}.o ${BUILD}/lib/libfsm.a ${BUILD}/lib/libre.a
${CC} ${CFLAGS} ${CFLAGS.${TEST_SRCDIR.tests/regressions}/regressions${n}.c} -o ${TEST_OUTDIR.tests/regressions}/run${n} ${TEST_OUTDIR.tests/regressions}/regressions${n}.o ${BUILD}/lib/libfsm.a ${BUILD}/lib/libre.a
${TEST_OUTDIR.tests/regressions}/res${n}: ${TEST_OUTDIR.tests/regressions}/run${n}
( ${TEST_OUTDIR.tests/regressions}/run${n} 1>&2 && echo PASS || echo FAIL ) > ${TEST_OUTDIR.tests/regressions}/res${n}
.endfor
69 changes: 69 additions & 0 deletions tests/regressions/regressions_determinise_state_limit_leak.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>

#include <assert.h>

#include <re/re.h>
#include <fsm/fsm.h>
#include <fsm/bool.h>

static const char *strings[] = {
[0] = "apple",
[1] = "banana",
[2] = "carrot",
[3] = "durian",
[4] = "eggplant",
};
#define STRING_COUNT sizeof(strings)/sizeof(strings[0])

int main(void)
{
struct fsm *fsms[STRING_COUNT] = {0};

for (size_t i = 0; i < STRING_COUNT; i++) {
fsms[i] = re_comp(RE_PCRE, fsm_sgetc, &strings[i], NULL, 0, NULL);
assert(fsms[i] != NULL);
}

struct fsm *combined_fsm = fsm_union_array(STRING_COUNT, fsms, NULL);
assert(combined_fsm != NULL);

size_t state_limit_base = fsm_countstates(combined_fsm);
size_t max_state_limit = state_limit_base + 100;

bool hit_state_limit = false;

for (size_t state_limit = state_limit_base; state_limit < max_state_limit; state_limit += 10) {
struct fsm *cp = fsm_clone(combined_fsm);

const struct fsm_determinise_config det_config = {
.state_limit = state_limit,
};

/* Previously this would leak memory when hitting the STATE_LIMIT_REACHED
* early exit, because the edge sets for the DFA being constructed were
* not freed properly.
*
* The first time this should fail immediately because the state limit IS the starting size,
* but later on it should halt in the middle of construction. */
switch (fsm_determinise_with_config(cp, &det_config)) {
case FSM_DETERMINISE_WITH_CONFIG_OK:
fsm_free(cp);
break;
case FSM_DETERMINISE_WITH_CONFIG_STATE_LIMIT_REACHED:
hit_state_limit = true;
fsm_free(cp);
break;
case FSM_DETERMINISE_WITH_CONFIG_ERRNO:
assert(!"internal error");
return EXIT_FAILURE;
}
}

assert(hit_state_limit);

fsm_free(combined_fsm);
return EXIT_SUCCESS;
}

0 comments on commit c9a240a

Please sign in to comment.