From bcaafaeb04da1fdfd4abc71a28f8a298e43d514b Mon Sep 17 00:00:00 2001 From: Akuli Date: Sun, 3 Dec 2023 19:03:21 +0200 Subject: [PATCH] memory leak tests --- examples/memory_leak.jou | 11 +++++++++++ runtests.sh | 4 ++-- tests/should_succeed/compiler_cli.jou | 13 +++++++++++-- tests/should_succeed/linked_list.jou | 8 ++++++++ 4 files changed, 32 insertions(+), 4 deletions(-) create mode 100644 examples/memory_leak.jou diff --git a/examples/memory_leak.jou b/examples/memory_leak.jou new file mode 100644 index 00000000..84c25526 --- /dev/null +++ b/examples/memory_leak.jou @@ -0,0 +1,11 @@ +import "stdlib/io.jou" +import "stdlib/mem.jou" +import "stdlib/str.jou" + +def main() -> int: + foo: byte* = malloc(100) + strcpy(foo, "Hello") + strcpy(&foo[5], "World") + puts(foo) # Output: HelloWorld + + return 0 diff --git a/runtests.sh b/runtests.sh index 78e1ffb7..76bc64d7 100755 --- a/runtests.sh +++ b/runtests.sh @@ -148,7 +148,7 @@ function run_test() else # For non-aoc files we can valgrind the compiled Jou executables. # Aoc solutions can be really slow --> valgrind only the compilation. - if [ $valgrind = yes ]; then + if [ $valgrind = yes ] && [ $correct_exit_code == 0 ]; then command="$(printf "$command_template" "--valgrind $joufile")" else command="$(printf "$command_template" $joufile)" @@ -166,7 +166,7 @@ function run_test() # * the "test" is actually a GUI program in examples/ if ( ! [[ "$command_template" =~ -O0 ]] && [[ $joufile =~ ^tests/crash/ ]] ) \ || ( [[ "$command_template" =~ valgrind ]] && [ $correct_exit_code != 0 ] ) \ - || [ $joufile = examples/x11_window.jou ] + || [ $joufile = examples/x11_window.jou ] || [ $joufile = examples/memory_leak.jou ] then show_skip $joufile mv $diffpath $diffpath.skip diff --git a/tests/should_succeed/compiler_cli.jou b/tests/should_succeed/compiler_cli.jou index b242b7a2..89fed809 100644 --- a/tests/should_succeed/compiler_cli.jou +++ b/tests/should_succeed/compiler_cli.jou @@ -42,6 +42,7 @@ def main() -> int: # Output: -O0/-O1/-O2/-O3 set optimization level (0 = default, 3 = runs fastest) # Output: -v / --verbose display some progress information # Output: -vv display a lot of information about all compilation steps + # Output: --valgrind use valgrind when running the code # Output: --tokenize-only display only the output of the tokenizer, don't do anything else # Output: --parse-only display only the AST (parse tree), don't do anything else # Output: --linker-flags appended to the linker command, so you can use external libraries @@ -90,7 +91,15 @@ def main() -> int: # Compile a GUI program if not is_windows(): ret = system("./jou -o /dev/null --linker-flags \"-lX11\" examples/x11_window.jou") - if ret != 0: - printf("Compiling failed???\n") + assert ret == 0 + + # Compile a program with a memory leak. + # Output: 100 bytes in 1 blocks are definitely lost in loss record 1 of 1 + if is_windows() or system("which valgrind >/dev/null 2>/dev/null") != 0: + # valgrind not available --> produce some fake output to pass the test + puts("100 bytes in 1 blocks are definitely lost in loss record 1 of 1") + else: + ret = system("./jou --valgrind examples/memory_leak.jou 2>&1 | grep 'definitely lost' | cut -d' ' -f2-") + assert ret == 0 return 0 diff --git a/tests/should_succeed/linked_list.jou b/tests/should_succeed/linked_list.jou index f2e53322..2a305247 100644 --- a/tests/should_succeed/linked_list.jou +++ b/tests/should_succeed/linked_list.jou @@ -17,6 +17,12 @@ def prepend(list: Node**, value: byte) -> void: *new_first = Node{value = value, next = *list} *list = new_first +def free_list(list: Node*) -> void: + while list != NULL: + next = list->next + free(list) + list = next + def main() -> int: list: Node* = NULL prepend(&list, 'o') @@ -25,4 +31,6 @@ def main() -> int: prepend(&list, 'e') prepend(&list, 'h') list->print() # Output: hello + + free_list(list) return 0