├── .gitignore ├── .syntastic_c_config ├── LICENSE ├── README.md ├── configure ├── editors └── vim │ ├── fdetect.vim │ └── syntax.vim ├── libx ├── assert.h ├── ctype.h ├── stddef.h ├── stdio.h ├── stdlib.h └── string.h ├── scripts └── tmpl.mk ├── src ├── ast │ ├── ast.c │ ├── block.c │ ├── breakpoint.c │ ├── command.c │ ├── expr │ │ ├── expr.c │ │ ├── shift.c │ │ └── verify.c │ ├── externdecl.c │ ├── function │ │ ├── arr.c │ │ └── function.c │ ├── gram.y │ ├── include │ │ ├── command.h │ │ ├── expr.h │ │ ├── function.h │ │ ├── intern.h │ │ ├── literals.h │ │ ├── stmt.h │ │ ├── topological.h │ │ └── type.h │ ├── lex.l │ ├── literals.c │ ├── stmt │ │ ├── iter.c │ │ ├── iter.h │ │ ├── jump.c │ │ ├── jump.h │ │ ├── stmt.c │ │ ├── stmt.h │ │ └── verify.c │ ├── topological.c │ ├── type │ │ └── type.c │ └── variable.c ├── ext │ └── ext.c ├── include │ ├── ast.h │ ├── breakpoint.h │ ├── ext.h │ ├── gram_util.h │ ├── lex.h │ ├── math.h │ ├── object.h │ ├── state.h │ ├── storage.h │ ├── util.h │ ├── value.h │ └── verifier.h ├── main.c ├── math │ └── math.c ├── object │ └── object.c ├── state │ ├── .gitignore │ ├── block.c │ ├── clump.c │ ├── constraint.c │ ├── heap.c │ ├── include │ │ ├── block.h │ │ ├── clump.h │ │ ├── constraint.h │ │ ├── heap.h │ │ ├── intern.h │ │ ├── location.h │ │ ├── program.h │ │ ├── stack.h │ │ └── static.h │ ├── location.c │ ├── program.c │ ├── stack.c │ ├── state.c │ └── static.c ├── util │ └── util.c ├── value │ ├── include │ │ ├── _limits.h │ │ ├── intern.h │ │ ├── number.h │ │ └── range.h │ ├── number.c │ ├── range.c │ └── value.c └── verifier │ ├── arr.c │ ├── include │ ├── arr.h │ ├── instruct.h │ ├── intern.h │ ├── mux.h │ ├── path.h │ └── segment.h │ ├── instruct.c │ ├── mux.c │ ├── path.c │ ├── rconst.c │ ├── segment.c │ ├── splitinstruct.c │ └── verifier.c └── tests ├── 0db ├── 00-basic │ ├── expected │ │ ├── 0 │ │ ├── 1 │ │ ├── 2 │ │ ├── 3 │ │ ├── 4 │ │ └── 5 │ ├── test.cfg │ └── test.x ├── run └── split.awk ├── 0v ├── 00-basic │ ├── 000-FAIL-naked-alloc.x │ ├── 000-FAIL-naked-alloc.x.EXPECTED │ ├── 010-FAIL-non-returned-alloc.x │ ├── 010-FAIL-non-returned-alloc.x.EXPECTED │ ├── 020-FAIL-annotation.x │ ├── 020-FAIL-annotation.x.EXPECTED │ ├── 030-alloc.x │ ├── 031-alloc-conditional-compile.x │ ├── 041-FAIL-false-alloc-void.x │ ├── 041-FAIL-false-alloc-void.x.EXPECTED │ ├── 050-two-variables.x │ ├── 060-FAIL-two-allocs.x │ ├── 060-FAIL-two-allocs.x.EXPECTED │ ├── 110-free-variable.x │ ├── 120-free-direct.x │ ├── 130-FAIL-double-free.x │ ├── 130-FAIL-double-free.x.EXPECTED │ ├── 140-FAIL-sync-free.x │ ├── 140-FAIL-sync-free.x.EXPECTED │ ├── 150-indirect-free.x │ ├── 160-one-free-one-alloc.x │ ├── 170-FAIL-double-free.x │ ├── 170-FAIL-double-free.x.EXPECTED │ ├── 180-FAIL-alloc-freed.x │ ├── 180-FAIL-alloc-freed.x.EXPECTED │ ├── 200-free-param.x │ ├── 300-FAIL-with-recursive-struct.x │ ├── 300-FAIL-with-recursive-struct.x.EXPECTED │ ├── 301-FAIL-with-recursive-struct.x │ ├── 301-FAIL-with-recursive-struct.x.EXPECTED │ ├── 400-out-of-order.x │ ├── 410-struct-out-of-order.x │ ├── 420-struct-out-of-order.x │ ├── 500-FAIL-side-effect.x │ ├── 510-side-effect.x │ └── 520-side-effect-rconst.x ├── 01-branches │ ├── 0100-body-trivial.x │ ├── 0101-body-trivial-else.x │ ├── 0102-body-trivial-else-if.x │ ├── 0103-body-abstract.x │ ├── 0200-conditional-allocation.x │ ├── 0201-conditional-allocation-else.x │ ├── 0300-conditional-allocation-body.x │ ├── 0301-FAIL-conditional-allocation-two.x │ ├── 0301-FAIL-conditional-allocation-two.x.EXPECTED │ ├── 0302-conditional-allocation-two.x │ ├── 0310-FAIL-conditional-allocation-body.x │ ├── 0310-FAIL-conditional-allocation-body.x.EXPECTED │ ├── 0320-FAIL-conditional-allocation-body.x │ ├── 0320-FAIL-conditional-allocation-body.x.EXPECTED │ ├── 0400-strcmp-conditional-allocation.x │ ├── 0500-strcmp-conditional-allocation-body.x │ ├── 0600-indirect.x │ ├── 0610-indirect-setup.x │ ├── 0700-indirect.x │ ├── 0800-indirect.x │ ├── 0900-subsequent.x │ ├── 0901-FAIL-subsequent.x │ ├── 0901-FAIL-subsequent.x.EXPECTED │ ├── 1000-chaining-functions.x │ ├── 1001-chaining-functions.x │ ├── 1002-chaining-functions.x │ └── 1300-nested-branch-return.x ├── 02-loops │ ├── 000-loop.x │ ├── 010-FAIL-loop-invariant.x │ ├── 010-FAIL-loop-invariant.x.EXPECTED │ ├── 020-FAIL-loop-conclusion.x │ ├── 020-FAIL-loop-conclusion.x.EXPECTED │ └── 100-variable-limit.x ├── 04-linking │ ├── 000-internal-prototype-abstract.x │ ├── 010-internal-two-matching-abstracts.x │ ├── 020-FAIL-internal-mismatch-abstracts.x │ ├── 020-FAIL-internal-mismatch-abstracts.x.EXPECTED │ ├── 030-FAIL-internal-missing-definition.x │ ├── 030-FAIL-internal-missing-definition.x.EXPECTED │ ├── 040-FAIL-multiple-definitions.x │ ├── 040-FAIL-multiple-definitions.x.EXPECTED │ └── 050-multiple-prototype.x ├── 05-pass-by-ptr │ └── 000-basic.x ├── 06-preconditions │ ├── 100-FAIL-need-alloced-lval.x │ ├── 100-FAIL-need-alloced-lval.x.EXPECTED │ ├── 110-FAIL-need-alloced-rval.x │ ├── 110-FAIL-need-alloced-rval.x.EXPECTED │ ├── 111-FAIL-need-alloced-rval.x │ ├── 111-FAIL-need-alloced-rval.x.EXPECTED │ ├── 112-FAIL-need-rval.x │ ├── 112-FAIL-need-rval.x.EXPECTED │ ├── 120-FAIL-need-clump-lval-freed-ptr.x │ ├── 120-FAIL-need-clump-lval-freed-ptr.x.EXPECTED │ ├── 130-FAIL-need-clump-lval-assigned-ptr.x │ ├── 130-FAIL-need-clump-lval-assigned-ptr.x.EXPECTED │ ├── 140-setup-null.x │ ├── 200-clump-no-leak.x │ ├── 201-clump-nested-not-leak.x │ ├── 210-composite.x │ ├── 220-FAIL-leak.x │ ├── 220-FAIL-leak.x.EXPECTED │ ├── 230-FAIL-side-effect-leak.x │ ├── 230-FAIL-side-effect-leak.x.EXPECTED │ ├── 231-still-referenced.x │ ├── 300-range-verification.x │ ├── 310-FAIL-range-verification.x │ ├── 310-FAIL-range-verification.x.EXPECTED │ ├── 320-FAIL-range-verification.x │ ├── 320-FAIL-range-verification.x.EXPECTED │ ├── 330-FAIL-range-verification.x │ ├── 330-FAIL-range-verification.x.EXPECTED │ ├── 400-array-nested-value.x │ ├── 410-FAIL-array-nested-value.x │ ├── 410-FAIL-array-nested-value.x.EXPECTED │ ├── 420-array-nested-object.x │ ├── 430-FAIL-array-nested-object.x │ ├── 430-FAIL-array-nested-object.x.EXPECTED │ ├── 440-array-value.x │ ├── 450-FAIL-array-value.x │ ├── 450-FAIL-array-value.x.EXPECTED │ ├── 500-shifted-array.x │ ├── 510-FAIL-shifted-array.x │ └── 510-FAIL-shifted-array.x.EXPECTED ├── 07-use-after-free │ ├── 001-read-and-write-arbitrary.x │ ├── 002-pass-in-lvalue.x │ ├── 003-pass-in-rvalue.x │ ├── 004-mix-multiple-levels.x │ ├── 005-conditions.x │ ├── 100-FAIL-lvalue-use-after-free.x │ ├── 100-FAIL-lvalue-use-after-free.x.EXPECTED │ ├── 101-FAIL-rvalue-use-after-free.x │ ├── 101-FAIL-rvalue-use-after-free.x.EXPECTED │ ├── 110-FAIL-freed-ptr-dangling-return.x │ ├── 110-FAIL-freed-ptr-dangling-return.x.EXPECTED │ ├── 112-FAIL-freed-ptr-dangling-false-claim.x │ ├── 112-FAIL-freed-ptr-dangling-false-claim.x.EXPECTED │ ├── 120-FAIL-freed-ptr-maybe-dangling-return.x │ ├── 120-FAIL-freed-ptr-maybe-dangling-return.x.EXPECTED │ ├── 200-FAIL-stack-frame-pop-dangling-return.x │ ├── 200-FAIL-stack-frame-pop-dangling-return.x.EXPECTED │ ├── 210-FAIL-stack-frame-pop-dangling-assign.x │ ├── 210-FAIL-stack-frame-pop-dangling-assign.x.EXPECTED │ ├── 300-FAIL-struct-free-ptr-dangling.x │ ├── 300-FAIL-struct-free-ptr-dangling.x.EXPECTED │ ├── 400-FAIL-conditions-in-setup.x │ └── 400-FAIL-conditions-in-setup.x.EXPECTED ├── 08-uninitialised-memory │ ├── 000-FAIL-uninitialised-memory-rval.x │ ├── 000-FAIL-uninitialised-memory-rval.x.EXPECTED │ ├── 001-FAIL-uninitialised-memory-rval.x │ ├── 001-FAIL-uninitialised-memory-rval.x.EXPECTED │ ├── 002-FAIL-uninitialised-memory-rval.x │ ├── 002-FAIL-uninitialised-memory-rval.x.EXPECTED │ ├── 003-FAIL-uninitialised-memory-rval.x │ ├── 003-FAIL-uninitialised-memory-rval.x.EXPECTED │ ├── 004-FAIL-uninitialised-memory-rval.x │ └── 004-FAIL-uninitialised-memory-rval.x.EXPECTED ├── 09-calls │ ├── 000-complex-call-expressions.x │ ├── 100-FAIL-unique-rconst.x │ ├── 100-FAIL-unique-rconst.x.EXPECTED │ ├── 110-unique-rconst.x │ ├── 120-FAIL-unique-rconst.x │ ├── 120-FAIL-unique-rconst.x.EXPECTED │ ├── 130-unique-rconst.x │ ├── 200-FAIL-wrong-range.x │ ├── 200-FAIL-wrong-range.x.EXPECTED │ ├── 300-call-branch.x │ ├── 400-FAIL-no-return-value.x │ └── 400-FAIL-no-return-value.x.EXPECTED ├── 10-bounds-cbci │ ├── 000-FAIL-constant.x │ ├── 000-FAIL-constant.x.EXPECTED │ ├── 010-FAIL-constant-malloc.x │ ├── 010-FAIL-constant-malloc.x.EXPECTED │ ├── 020-FAIL-2D-constant-malloc.x │ ├── 020-FAIL-2D-constant-malloc.x.EXPECTED │ ├── 100-1D-array.x │ ├── 200-2D-array.x │ ├── 201-2D-array-odd-but-true.x │ ├── 210-FAIL-2D-array.x │ ├── 210-FAIL-2D-array.x.EXPECTED │ └── 220-3D-array.x ├── 11-bounds-cbvi │ ├── 000-setup-constant-safe.x │ ├── 100-setup-range-trivial.x │ ├── 110-setup-range-trivial.x │ ├── 120-binary-index-split-constant-first.x │ ├── 121-FAIL-binary-index-split-constant-first.x │ ├── 121-FAIL-binary-index-split-constant-first.x.EXPECTED │ ├── 130-binary-index-split-rconst-first.x │ ├── 140-binary-value-split-constant-first.x │ ├── 150-binary-value-split-constant-first.x │ ├── 151-FAIL-binary-value-split-constant-first.x │ ├── 151-FAIL-binary-value-split-constant-first.x.EXPECTED │ ├── 200-FAIL-binary-binary-value-split.x │ ├── 200-FAIL-binary-binary-value-split.x.EXPECTED │ ├── 210-FAIL-overflow.x │ ├── 210-FAIL-overflow.x.EXPECTED │ ├── 220-less-than-restrict.x │ ├── 221-equal-restrict.x │ ├── 230-less-than-equal.x │ ├── 300-FAIL-basic.x │ ├── 300-FAIL-basic.x.EXPECTED │ ├── 310-FAIL-less-than-restrict.x │ ├── 310-FAIL-less-than-restrict.x.EXPECTED │ ├── 320-FAIL-less-than-equal-restrict.x │ ├── 320-FAIL-less-than-equal-restrict.x.EXPECTED │ └── 400-less-than-greater-than-restrict.x ├── 12-bounds-vbci │ ├── 000-FAIL-no-setup.x │ ├── 000-FAIL-no-setup.x.EXPECTED │ ├── 010-FAIL-off-by-one.x │ ├── 010-FAIL-off-by-one.x.EXPECTED │ ├── 020-within-bounds.x │ ├── 021-within-bounds.x │ ├── 030-within-bounds-minus-one.x │ ├── 031-within-bounds-minus-one-abstract-rconst.x │ ├── 040-within-bounds-minus-five.x │ ├── 100-caller-stack-variable.x │ ├── 110-caller-stack-variable.x │ ├── 120-FAIL-spec-requires-larger-block.x │ └── 120-FAIL-spec-requires-larger-block.x.EXPECTED ├── 20-declarators │ ├── 000-declaration-list.x │ └── 100-declaration-init.x ├── 30-topological │ ├── 000-valid-sort-empty.x │ ├── 000-valid-sort-empty.x.EXPECTED │ ├── 001-valid-sort-matrix.x │ ├── 001-valid-sort-matrix.x.EXPECTED │ ├── 002-valid-sort-parse.x │ ├── 002-valid-sort-parse.x.EXPECTED │ ├── 010-FAIL-cycle.x │ ├── 010-FAIL-cycle.x.EXPECTED │ ├── 020-FAIL-non-existant-funcname.x │ ├── 020-FAIL-non-existant-funcname.x.EXPECTED │ └── args ├── 31-topological-verification │ ├── 003-valid-sort-inorder-verification.x │ ├── 003-valid-sort-inorder-verification.x.EXPECTED │ └── args ├── 40-type-checking │ ├── 000-FAIL-void-return.x │ └── 000-FAIL-void-return.x.EXPECTED └── 99-program │ ├── .vimrc │ ├── 000-matrix.x │ └── 100-lex │ ├── gen.l │ └── parse.x ├── run └── wmw-www /.gitignore: -------------------------------------------------------------------------------- 1 | bin 2 | build 3 | *.o 4 | *.sw* 5 | *.gch 6 | *.dSYM 7 | a.out 8 | *.yy.c 9 | *.tab.[ch] 10 | *.output 11 | *-preproc.[c0] 12 | tags 13 | *.temp 14 | *.mk 15 | !scripts/tmpl.mk 16 | /Makefile 17 | -------------------------------------------------------------------------------- /.syntastic_c_config: -------------------------------------------------------------------------------- 1 | -I src/include 2 | -I build 3 | -pedantic 4 | -Werror 5 | -Wall 6 | -Wreturn-type 7 | -Wstrict-prototypes 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Xr0 – C But Safe 2 | 3 | Xr0 is a verifier for C that aims to guarantee the safety of C programs at 4 | compile time. It will eliminate common pitfalls such as use-after-frees, double 5 | frees, buffer out-of-bounds reads/writes, null pointer dereferences, uses of 6 | uninitialised memory, arithmetic overflows/underflows and all other instances of 7 | undefined behaviour in C. 8 | 9 | View the project website [here](https://xr0.dev). 10 | 11 | ## Getting started 12 | 13 | Check out the [tutorial](https://xr0.dev/learn) on the website. 14 | 15 | ## Contributing 16 | 17 | The best way to contribute to Xr0 is to use it for something. 18 | 19 | In that regard, we're forming a cohort for the first few users of Xr0. 20 | Participation in the cohort will come with support and prioritisation (within 21 | reason) of features in our roadmap as we work towards making Xr0 useful for 22 | everyone. 23 | And best of all, it'll be completely free. 24 | The only thing is there's two of us, so we'll have to keep the cohort fairly 25 | small. 26 | Reach out via email to 27 | [Claude](mailto:betz@xr0.dev) or 28 | [Amisi](mailto:a@xr0.dev) or DM us on the 29 | [Xr0 Discord](https://discord.com/invite/yfx69tbhxQ) if you're interested in this. 30 | 31 | We are currently not accepting pull requests due to the early stage of Xr0. 32 | However, if you have a serious proposal for how we can improve Xr0 you can 33 | [make an issue](https://github.com/xr0-org/xr0/issues/new) to explain it. 34 | 35 | ## License 36 | 37 | This project is distributed under the terms of the Apache 2.0 open source license. 38 | Please refer to [LICENSE](https://github.com/xr0-org/xr0/blob/master/LICENSE) 39 | for the full terms. 40 | -------------------------------------------------------------------------------- /configure: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | TMPL_MKFILE=scripts/tmpl.mk 4 | DEPS_MKFILE=scripts/deps.mk 5 | 6 | # This script generates the Makefile from $TMPL_MKFILE and $DEPS_MKFILE, 7 | # the latter of which contains the rules to build the various object files. 8 | # 9 | # $DEPS_MKFILE imposes the following module rules: 10 | # 11 | # 1. Every directory in `/src` and its descendant directories, including 12 | # `/src` itself, defines a module. 13 | # 14 | # 2. Every C file within a module can include headers from the 15 | # `[root]/include` directory (if it exists) where `[root]` is the module 16 | # root directory. E.g., `/src/main.c` and `/src/ast/expr.c` can both 17 | # include headers from `/src/include`, but `/src/ast/expr.c` can also 18 | # include from `/src/ast/include`. 19 | # 20 | # 3. Every C file is treated as its own translation unit. 21 | # 22 | # 4. Every `.c` and `.h` file in the directory is a Makefile-dependency of 23 | # every other such file. 24 | # 25 | # 5. In keeping with [0], the -I include directories are ordered 26 | # according to nearness to the file, so that if `x.h` is imported in 27 | # `/src/abc` and there is both `/src/include/x.h` and 28 | # `/src/abc/include/x.h` then the latter will be chosen. 29 | # 30 | # [0]: "Directories named in -I options shall be searched in the order 31 | # specified". 32 | # https://pubs.opengroup.org/onlinepubs/9699919799/utilities/c99.html 33 | 34 | set +x 35 | 36 | SRCDIR=src 37 | BUILDDIR=build 38 | 39 | # listincludes: output a list of the appropriate include directories from the 40 | # given path, in keeping with rule (2.) above 41 | function listincludes() { 42 | path=$1 43 | includedir=$path/include 44 | if [ -d $includedir ]; then 45 | echo $includedir 46 | fi 47 | parent=$(dirname $path) 48 | if [[ $parent != "." ]]; then 49 | listincludes $parent 50 | fi 51 | } 52 | 53 | INCLUDEDIRS=$(find $SRCDIR -type d -name "include") 54 | SRCDIRS=$(find $SRCDIR -type d ! -name "include") 55 | 56 | # hack in Lex/Yacc files 57 | PARSER_FILES="$SRCDIR/ast/lex.yy.c \ 58 | $SRCDIR/ast/gram.tab.c \ 59 | $SRCDIR/include/gram.tab.h" 60 | touch $PARSER_FILES 61 | 62 | exec > $DEPS_MKFILE 63 | 64 | printf "# Generated by $(pwd)/$(basename $0) at $(date "+%s")\n\n" 65 | 66 | # headers 67 | printf "HEADERS =" 68 | for dir in $INCLUDEDIRS; do 69 | for f in $(find $dir -maxdepth 1 -type f -name "*.h"); do 70 | printf " \\" # escape previous line 71 | printf "\n\t$f" 72 | done 73 | done 74 | printf "\n\n" 75 | 76 | # objects 77 | printf "OBJECTS =" 78 | for dir in $SRCDIRS; do 79 | build_dir=$(echo $dir | sed "s/^$SRCDIR/$BUILDDIR/") 80 | for f in $(find $dir -maxdepth 1 -type f -name "*.c"); do 81 | obj=$build_dir/$(basename $f | sed "s/.c$/.o/;") 82 | printf " \\" # escape previous line 83 | printf "\n\t$obj" 84 | done 85 | done 86 | printf "\n" 87 | 88 | # object build commands 89 | for dir in $SRCDIRS; do 90 | build_dir=$(echo $dir | sed "s/^$SRCDIR/$BUILDDIR/") 91 | printf "\n# $dir with build dir /$build_dir\n" 92 | includes=$(listincludes $dir) 93 | for f in $(find $dir -maxdepth 1 -type f -name "*.c"); do 94 | obj=$build_dir/$(basename $f | sed "s/.c$/.o/;") 95 | printf "$obj: $build_dir parser\n" 96 | printf "\t@printf \"CC\\\\t\$@\\\\n\"\n" 97 | printf "\t@\$(CC) \$(CFLAGS) -o \$@ -c $f " 98 | 99 | # the order of inclusions is important: see (5.) above. 100 | for inc in $includes; do 101 | printf -- '\\\n\t\t-I %s ' $inc 102 | done 103 | printf "\n" 104 | done 105 | done 106 | 107 | # build dirs 108 | printf "# build dirs\n" 109 | for dir in $SRCDIRS; do 110 | build_dir=$(echo $dir | sed "s/^$SRCDIR/$BUILDDIR/") 111 | printf "$build_dir:\n" 112 | printf "\t@mkdir -p \$@\n" 113 | done 114 | 115 | exec > /dev/tty 116 | 117 | # hack in parser files 118 | rm $PARSER_FILES 119 | 120 | cp $TMPL_MKFILE Makefile 121 | -------------------------------------------------------------------------------- /editors/vim/fdetect.vim: -------------------------------------------------------------------------------- 1 | au Bufread,BufNewFile *.x, set filetype=xr0 2 | 3 | au BufRead,BufNewFile *.h if search('axiom\|sfunc\|lemma', 'nw') | set filetype=xr0 | endif 4 | -------------------------------------------------------------------------------- /editors/vim/syntax.vim: -------------------------------------------------------------------------------- 1 | " Comment 2 | syntax region Comment start="/\*" end="\*/" 3 | 4 | " Constant 5 | syntax region String start=+"+ skip=+\\"+ end=+"+ 6 | syntax region Character start=+'+ skip=+\\'+ end=+'+ 7 | 8 | " Statement 9 | syntax keyword Constant NULL stdin stdout stderr 10 | syntax keyword Operator sizeof 11 | syntax keyword Keyword const exit 12 | syntax keyword Type unsigned int char double void bool size_t FILE 13 | syntax keyword Structure struct enum union 14 | syntax keyword Conditional if else for while switch break 15 | syntax keyword Include axiom malloc free realloc clump 16 | syntax keyword Label case default setup 17 | syntax keyword Boolean true false 18 | syntax keyword Exception return 19 | syntax keyword Typedef typedef 20 | 21 | " Type 22 | syntax keyword StorageClass auto static 23 | -------------------------------------------------------------------------------- /libx/assert.h: -------------------------------------------------------------------------------- 1 | #ifndef ASSERT_H 2 | #define ASSERT_H 3 | 4 | axiom void 5 | assert(int); 6 | 7 | #endif 8 | -------------------------------------------------------------------------------- /libx/ctype.h: -------------------------------------------------------------------------------- 1 | #ifndef CTYPE_H 2 | #define CTYPE_H 3 | 4 | axiom int 5 | isalpha(int c); 6 | 7 | axiom int 8 | isspace(char *); 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /libx/stddef.h: -------------------------------------------------------------------------------- 1 | #ifndef STDDEF_H 2 | #define STDDEF_H 3 | 4 | /* TODO: convert to unsigned */ 5 | typedef int size_t; 6 | 7 | #define NULL 0 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /libx/stdio.h: -------------------------------------------------------------------------------- 1 | #ifndef STDIO_H 2 | #define STDIO_H 3 | 4 | #include 5 | 6 | typedef int FILE; 7 | 8 | axiom int 9 | putc(int c); 10 | 11 | axiom int 12 | putchar(int c); 13 | 14 | axiom int 15 | fputs(char *s, FILE *stream); 16 | 17 | axiom int 18 | puts(char *s) ~ [ setup: s = .clump(1); ]; 19 | 20 | axiom FILE * 21 | fopen(char *pathname, char *mode); 22 | 23 | axiom int 24 | fseek(FILE *stream, int offset, int whence); /* TODO: convert offset to long */ 25 | 26 | #define SEEK_END 0 27 | #define SEEK_SET 0 28 | 29 | axiom int 30 | ftell(FILE *stream); 31 | 32 | axiom size_t 33 | fread(void *ptr, size_t size, size_t nmemb, FILE *stream); 34 | 35 | axiom int 36 | fclose(FILE *stream); 37 | 38 | /* XXX: provisionally rigid for preconditions example */ 39 | axiom char * 40 | sprintf(char *buf, char *format, int *arg) ~ [ *buf = [?]; ]; 41 | 42 | /* XXX: provisionally rigid for preconditions example */ 43 | axiom int 44 | scanf(char *format, int *arg) ~ [ 45 | /* since there's a sideeffect here for arg, we need to characterise it */ 46 | *arg = [?]; 47 | ]; 48 | 49 | #endif 50 | -------------------------------------------------------------------------------- /libx/stdlib.h: -------------------------------------------------------------------------------- 1 | #ifndef STDLIB_H 2 | #define STDLIB_H 3 | 4 | #include 5 | 6 | axiom void * 7 | malloc(int size) ~ [ 8 | setup: size = [0?]; 9 | return .malloc(size); 10 | ]; 11 | 12 | axiom void 13 | free(void *ptr) ~ [ 14 | setup: ptr = malloc(1); 15 | .free(ptr); 16 | ]; 17 | 18 | axiom void 19 | exit(int status); 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /libx/string.h: -------------------------------------------------------------------------------- 1 | #ifndef STRING_H 2 | #define STRING_H 3 | 4 | #include 5 | 6 | axiom char * 7 | strcpy(char *dest, char *src); 8 | 9 | axiom char * 10 | strncpy(char *dest, char *src, size_t n); 11 | 12 | axiom size_t 13 | strlen(char *s); 14 | 15 | axiom int 16 | strcmp(char *s1, char *s2); 17 | 18 | axiom int 19 | strncmp(char *s1, char *s2, size_t n); 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /scripts/tmpl.mk: -------------------------------------------------------------------------------- 1 | .POSIX: 2 | 3 | # commands 4 | CC = cc 5 | CFLAGS = -g -I src/include \ 6 | -std=gnu11 -pedantic -Wall -Werror \ 7 | -Wreturn-type \ 8 | -Wstrict-prototypes 9 | VALGRIND = valgrind --fullpath-after=`pwd`/src/ 10 | LEX = lex 11 | YACC = bison -yvd 12 | 13 | # dirs 14 | BIN_DIR = bin 15 | BUILD_DIR = build 16 | SRC_DIR = src 17 | TEST_DIR = tests 18 | 19 | DEPS_MK = scripts/deps.mk 20 | 21 | # executable 22 | XR0V = $(BIN_DIR)/0v 23 | 24 | main: $(XR0V) 25 | 26 | include $(DEPS_MK) 27 | 28 | $(XR0V): $(BIN_DIR) $(HEADERS) $(OBJECTS) parser 29 | @printf 'CC\t$@\n' 30 | @$(CC) $(CFLAGS) -o $@ $(OBJECTS) 31 | 32 | AST_DIR = $(SRC_DIR)/ast 33 | 34 | PARSER_JUNK = $(GRAM_TAB_H) $(GRAM_TAB_C) $(LEX_YY_C) $(AST_DIR)/gram.output 35 | GRAM_TAB_H = $(SRC_DIR)/include/gram.tab.h 36 | GRAM_TAB_C = $(AST_DIR)/gram.tab.c 37 | LEX_YY_C = $(AST_DIR)/lex.yy.c 38 | 39 | parser: $(LEX_YY_C) $(GRAM_TAB_H) $(GRAM_TAB_C) 40 | 41 | $(LEX_YY_C): $(AST_DIR)/lex.l 42 | @printf 'LEX\t$@\n' 43 | @$(LEX) -o $@ $(AST_DIR)/lex.l 44 | 45 | $(GRAM_TAB_C) $(GRAM_TAB_H): $(AST_DIR)/gram.y 46 | @printf 'YACC\t$@\n' 47 | @$(YACC) -o $(GRAM_TAB_C) $(AST_DIR)/gram.y 48 | @mv $(AST_DIR)/gram.tab.h $(GRAM_TAB_H) 49 | 50 | $(BIN_DIR): 51 | @mkdir -p $(BIN_DIR) 52 | 53 | # tests 54 | 55 | test: $(XR0V) $(TEST_DIR) 56 | @./tests/run 57 | 58 | check: $(RUNTEST) $(XR0V) 59 | $(VALGRIND) $(XR0V) -I libx $(filter-out $@,$(MAKECMDGOALS)) 60 | 61 | check-verbose: $(RUNTEST) $(XR0V) 62 | $(VALGRIND) --num-callers=30 \ 63 | $(XR0V) -v -I libx $(filter-out $@,$(MAKECMDGOALS)) 64 | 65 | debug: $(RUNTEST) $(XR0V) 66 | $(VALGRIND) $(XR0V) -d -I libx $(filter-out $@,$(MAKECMDGOALS)) 67 | 68 | lex: $(XR0V) 69 | $(VALGRIND) $(XR0V) -I libx $(TEST_DIR)/99-program/100-lex/parse.x 70 | 71 | PARSER = $(BUILD_DIR)/lex-gen 72 | 73 | lex-gen: 74 | @$(XR0C) $(TEST_DIR)/5-program/100-lex/parse.x > build/parse.c 75 | @c89 -g -o $(PARSER) $(BUILD_DIR)/parse.c 76 | @$(PARSER) > $(BUILD_DIR)/gen_firstchar 77 | @echo '%' > $(BUILD_DIR)/percent 78 | @diff $(BUILD_DIR)/gen_firstchar $(BUILD_DIR)/percent 79 | 80 | lex-leaks: $(XR0V) 81 | $(VALGRIND) --leak-check=full \ 82 | $(XR0V) -I libx $(TEST_DIR)/99-program/100-lex/parse.x 83 | 84 | lex-verbose: $(XR0V) 85 | $(VALGRIND) --num-callers=30 \ 86 | $(XR0V) -I libx -v $(TEST_DIR)/99-program/100-lex/parse.x 87 | 88 | matrix: $(XR0V) 89 | $(VALGRIND) $(XR0V) -I libx $(TEST_DIR)/99-program/000-matrix.x 90 | 91 | matrix-leaks: $(XR0V) 92 | $(VALGRIND) --leak-check=full \ 93 | $(XR0V) -I libx $(TEST_DIR)/99-program/000-matrix.x 94 | 95 | matrix-verbose: $(XR0V) 96 | $(VALGRIND) --num-callers=30 \ 97 | $(XR0V) -I libx $(TEST_DIR)/99-program/000-matrix.x 98 | 99 | 100 | clean: 101 | @rm -rf $(BUILD_DIR) $(BIN_DIR) $(PARSER_JUNK) $(DEPS_MK) Makefile 102 | -------------------------------------------------------------------------------- /src/ast/breakpoint.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "breakpoint.h" 8 | #include "util.h" 9 | #include "lex.h" 10 | 11 | #define MAX_BREAKPOINTS 100 12 | 13 | /* XXX: validation of filenames and lengths for breakpoints */ 14 | 15 | struct breakpoint { 16 | bool enabled; 17 | bool reached; 18 | // char *filename; 19 | int linenumber; 20 | }; 21 | 22 | struct breakpoint breakpoints[MAX_BREAKPOINTS]; 23 | int breakpoint_count = 0; 24 | 25 | static char * 26 | breakpoint_str(struct breakpoint); 27 | 28 | char * 29 | breakpoint_list(void) 30 | { 31 | struct strbuilder *b = strbuilder_create(); 32 | strbuilder_printf(b, "Num\tLine\n"); 33 | for (int i = 0; i < breakpoint_count; i++) { 34 | struct breakpoint bp = breakpoints[i]; 35 | strbuilder_printf(b, "%d\t%s\n", i, breakpoint_str(bp)); 36 | } 37 | return strbuilder_build(b); 38 | } 39 | 40 | static char * 41 | breakpoint_str(struct breakpoint bp) 42 | { 43 | if (bp.enabled) { 44 | struct strbuilder *b = strbuilder_create(); 45 | strbuilder_printf(b, "%d", bp.linenumber); 46 | return strbuilder_build(b); 47 | } 48 | return dynamic_str(""); 49 | } 50 | 51 | static int 52 | breakpoint_exists(struct breakpoint); 53 | 54 | struct error * 55 | breakpoint_set(char *filename, int linenumber) 56 | { 57 | struct breakpoint bp = (struct breakpoint) { 58 | .enabled = true, .linenumber = linenumber 59 | }; 60 | if (breakpoint_count > MAX_BREAKPOINTS) { 61 | return error_printf("Maximum number of breakpoints reached\n"); 62 | } 63 | int id = breakpoint_exists(bp); 64 | if (id != -1) { 65 | return error_printf( 66 | "Note: breakpoint %s is already set as %d\n", breakpoint_str(bp), id 67 | ); 68 | } 69 | breakpoints[breakpoint_count] = bp; 70 | breakpoint_count++; 71 | return NULL; 72 | } 73 | 74 | static bool 75 | breakpoint_equal(struct breakpoint bp1, struct breakpoint bp2); 76 | 77 | static int 78 | breakpoint_exists(struct breakpoint bp) 79 | { 80 | for (int i = 0; i < breakpoint_count; i++) { 81 | if (breakpoint_equal(bp, breakpoints[i]) && !breakpoints[i].reached) { 82 | breakpoints[i].reached = true; 83 | return i; 84 | } 85 | } 86 | return -1; 87 | } 88 | 89 | static bool 90 | breakpoint_equal(struct breakpoint bp1, struct breakpoint bp2) 91 | { 92 | return bp1.linenumber == bp2.linenumber; 93 | } 94 | 95 | struct error * 96 | breakpoint_delete(int id) 97 | { 98 | if (breakpoints[id].enabled) { 99 | breakpoints[id].enabled = false; 100 | return NULL; 101 | } 102 | return error_printf("No breakpoint with id: %d", id); 103 | } 104 | 105 | bool 106 | breakpoint_shouldbreak(struct lexememarker *loc) 107 | { 108 | // char *fname = lexememarker_filename(loc); 109 | int linenum = lexememarker_linenum(loc); 110 | 111 | struct breakpoint bp = (struct breakpoint) { 112 | .linenumber = linenum, 113 | }; 114 | int index = breakpoint_exists(bp); 115 | if (index == -1) { 116 | return false; 117 | } 118 | return true; 119 | } 120 | 121 | void 122 | breakpoint_reset(void) 123 | { 124 | for (int i = 0; i < breakpoint_count; i++) { 125 | breakpoints[i].reached = false; 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /src/ast/expr/shift.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct shift { 4 | char *id; 5 | int width; 6 | }; 7 | 8 | struct shift * 9 | shift_create(char *id, int width) 10 | { 11 | struct shift *s = malloc(sizeof(struct shift)); 12 | s->id = id; 13 | s->width = width; 14 | return s; 15 | } 16 | 17 | void 18 | shift_destroy(struct shift *s) 19 | { 20 | free(s->id); 21 | free(s); 22 | } 23 | 24 | char * 25 | shift_id(struct shift *s) { return s->id; } 26 | 27 | int 28 | shift_width(struct shift *s) { return s->width; } 29 | 30 | -------------------------------------------------------------------------------- /src/ast/externdecl.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "ast.h" 6 | #include "ext.h" 7 | #include "util.h" 8 | 9 | struct ast_externdecl { 10 | enum ast_externdecl_kind { 11 | EXTERN_FUNCTION, 12 | EXTERN_VARIABLE, 13 | EXTERN_TYPEDEF, 14 | EXTERN_STRUCT, 15 | } kind; 16 | union { 17 | struct ast_function *function; 18 | struct ast_variable *variable; 19 | struct { 20 | char *name; 21 | struct ast_type *type; 22 | } _typedef; 23 | struct ast_type *_struct; 24 | }; 25 | }; 26 | 27 | struct ast_externdecl * 28 | ast_functiondecl_create(struct ast_function *f) 29 | { 30 | struct ast_externdecl *decl = malloc(sizeof(struct ast_externdecl)); 31 | decl->kind = EXTERN_FUNCTION; 32 | decl->function = f; 33 | return decl; 34 | } 35 | 36 | bool 37 | ast_externdecl_isfunction(struct ast_externdecl *decl) 38 | { 39 | return decl->kind == EXTERN_FUNCTION; 40 | } 41 | 42 | struct ast_function * 43 | ast_externdecl_as_function(struct ast_externdecl *decl) 44 | { 45 | assert(decl->kind == EXTERN_FUNCTION); 46 | return decl->function; 47 | } 48 | 49 | struct ast_externdecl * 50 | ast_decl_create(char *name, struct ast_type *t) 51 | { 52 | struct ast_externdecl *decl = malloc(sizeof(struct ast_externdecl)); 53 | if (ast_type_istypedef(t)) { 54 | decl->kind = EXTERN_TYPEDEF; 55 | decl->_typedef.name = name; 56 | decl->_typedef.type = t; 57 | } else if (ast_type_isstruct(t)) { 58 | assert(ast_type_struct_tag(t)); 59 | decl->kind = EXTERN_STRUCT; 60 | decl->_struct = t; 61 | } else { /* variable */ 62 | decl->kind = EXTERN_VARIABLE; 63 | decl->variable = ast_variable_create(name, t); 64 | } 65 | return decl; 66 | } 67 | 68 | void 69 | ast_externdecl_install(struct ast_externdecl *decl, struct externals *ext) 70 | { 71 | struct ast_function *f; 72 | struct ast_variable *v; 73 | 74 | switch (decl->kind) { 75 | case EXTERN_FUNCTION: 76 | f = decl->function; 77 | externals_declarefunc(ext, ast_function_name(f), f); 78 | break; 79 | case EXTERN_VARIABLE: 80 | v = decl->variable; 81 | externals_declarevar(ext, ast_variable_name(v), v); 82 | break; 83 | case EXTERN_TYPEDEF: 84 | externals_declaretypedef( 85 | ext, decl->_typedef.name, decl->_typedef.type 86 | ); 87 | break; 88 | case EXTERN_STRUCT: 89 | externals_declarestruct(ext, decl->_struct); 90 | break; 91 | default: 92 | assert(false); 93 | } 94 | } 95 | 96 | void 97 | ast_externdecl_destroy(struct ast_externdecl *decl) 98 | { 99 | switch (decl->kind) { 100 | case EXTERN_FUNCTION: 101 | ast_function_destroy(decl->function); 102 | break; 103 | case EXTERN_VARIABLE: 104 | ast_variable_destroy(decl->variable); 105 | break; 106 | case EXTERN_TYPEDEF: 107 | free(decl->_typedef.name); 108 | ast_type_destroy(decl->_typedef.type); 109 | break; 110 | case EXTERN_STRUCT: 111 | ast_type_destroy(decl->_struct); 112 | break; 113 | default: 114 | assert(false); 115 | } 116 | free(decl); 117 | } 118 | -------------------------------------------------------------------------------- /src/ast/function/arr.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "ast.h" 6 | #include "function.h" 7 | 8 | struct ast_function_arr { 9 | int n; 10 | struct ast_function **f; 11 | }; 12 | 13 | struct ast_function_arr * 14 | ast_function_arr_create(void) 15 | { 16 | return calloc(1, sizeof(struct ast_function_arr)); 17 | } 18 | 19 | struct ast_function_arr * 20 | ast_function_arr_copy(struct ast_function_arr *old) 21 | { 22 | struct ast_function_arr *new = ast_function_arr_create(); 23 | for (int i = 0; i < old->n; i++) { 24 | ast_function_arr_append(new, ast_function_copy(old->f[i])); 25 | } 26 | return new; 27 | } 28 | 29 | void 30 | ast_function_arr_destroy(struct ast_function_arr *arr) 31 | { 32 | for (int i = 0; i < arr->n; i++) { 33 | ast_function_destroy(arr->f[i]); 34 | } 35 | free(arr); 36 | } 37 | 38 | void 39 | ast_function_arr_append(struct ast_function_arr *arr, struct ast_function *f) 40 | { 41 | arr->f = realloc(arr->f, sizeof(struct ast_function *) * ++arr->n); 42 | arr->f[arr->n-1] = f; 43 | } 44 | 45 | void 46 | ast_function_arr_appendrange(struct ast_function_arr *arr, 47 | struct ast_function_arr *range) 48 | { 49 | for (int i = 0; i < range->n; i++) { 50 | ast_function_arr_append(arr, range->f[i]); 51 | } 52 | } 53 | 54 | int 55 | ast_function_arr_len(struct ast_function_arr *arr) 56 | { 57 | return arr->n; 58 | } 59 | 60 | struct ast_function ** 61 | ast_function_arr_func(struct ast_function_arr *arr) 62 | { 63 | return arr->f; 64 | } 65 | -------------------------------------------------------------------------------- /src/ast/include/command.h: -------------------------------------------------------------------------------- 1 | #ifndef COMMAND_H 2 | #define COMMAND_H 3 | 4 | struct verifier; 5 | 6 | struct error * 7 | command_next(struct verifier *, char *debugsep); 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /src/ast/include/expr.h: -------------------------------------------------------------------------------- 1 | #ifndef XR0_AST_EXPR_H 2 | #define XR0_AST_EXPR_H 3 | 4 | #include "util.h" 5 | 6 | struct ast_expr { 7 | enum ast_expr_kind { 8 | EXPR_IDENTIFIER = 1 << 0, 9 | EXPR_CONSTANT = 1 << 1, 10 | EXPR_STRING_LITERAL = 1 << 2, 11 | EXPR_BRACKETED = 1 << 3, 12 | EXPR_ITERATION = 1 << 4, 13 | 14 | EXPR_CALL = 1 << 5, 15 | EXPR_INCDEC = 1 << 6, 16 | 17 | EXPR_STRUCTMEMBER = 1 << 7, 18 | 19 | EXPR_UNARY = 1 << 8, 20 | EXPR_BINARY = 1 << 9, 21 | 22 | EXPR_ASSIGNMENT = 1 << 10, 23 | 24 | EXPR_ISDEALLOCAND = 1 << 11, 25 | EXPR_RANGE = 1 << 12, 26 | EXPR_RANGEBOUND = 1 << 13, 27 | EXPR_ALLOCATION = 1 << 14, 28 | } kind; 29 | struct ast_expr *root; 30 | union { 31 | char *string; /* identifier, literal, assertion */ 32 | struct { 33 | int constant; 34 | bool ischar; 35 | } constant; 36 | struct { 37 | int n; 38 | struct ast_expr **arg; 39 | } call; 40 | struct { 41 | int inc, pre; 42 | } incdec; 43 | enum ast_unary_operator { 44 | UNARY_OP_ADDRESS = 1 << 0, 45 | UNARY_OP_DEREFERENCE = 1 << 1, 46 | UNARY_OP_POSITIVE = 1 << 2, 47 | UNARY_OP_NEGATIVE = 1 << 3, 48 | UNARY_OP_ONES_COMPLEMENT = 1 << 4, 49 | UNARY_OP_BANG = 1 << 5, 50 | } unary_op; 51 | struct { 52 | enum ast_binary_operator { 53 | BINARY_OP_EQ = 1 << 0, 54 | BINARY_OP_NE = 1 << 1, 55 | 56 | BINARY_OP_LT = 1 << 2, 57 | BINARY_OP_GT = 1 << 3, 58 | BINARY_OP_LE = 1 << 4, 59 | BINARY_OP_GE = 1 << 5, 60 | 61 | BINARY_OP_ADDITION = 1 << 6, 62 | BINARY_OP_SUBTRACTION = 1 << 7, 63 | BINARY_OP_MULTIPLICATION = 1 << 8, 64 | } op; 65 | struct ast_expr *e1, *e2; 66 | } binary; 67 | struct ast_expr *assignment_value; 68 | struct { 69 | char *key; 70 | struct ast_expr *lw, *up; 71 | } range; 72 | bool ismax; 73 | struct { 74 | enum ast_alloc_kind { 75 | ALLOC = 1 << 0, 76 | DEALLOC = 1 << 1, 77 | CLUMP = 1 << 2, 78 | } kind; 79 | struct ast_expr *arg; 80 | } alloc; 81 | } u; 82 | }; 83 | 84 | enum ast_expr_kind 85 | ast_expr_kind(struct ast_expr *); 86 | 87 | struct ast_expr * 88 | ast_expr_binary_create(struct ast_expr *e1, enum ast_binary_operator, 89 | struct ast_expr *e2); 90 | 91 | enum ast_binary_operator 92 | ast_expr_binary_op(struct ast_expr *); 93 | 94 | struct ast_expr * 95 | ast_expr_unary_create(struct ast_expr *, enum ast_unary_operator); 96 | 97 | enum ast_unary_operator 98 | ast_expr_unary_op(struct ast_expr *); 99 | 100 | struct ast_stmt_splits 101 | ast_expr_splits(struct ast_expr *, struct state *); 102 | 103 | enum ast_alloc_kind 104 | ast_expr_alloc_kind(struct ast_expr *); 105 | 106 | struct ast_expr * 107 | ast_expr_alloc_kind_create(struct ast_expr *arg, enum ast_alloc_kind); 108 | 109 | struct value_arr; 110 | struct value_arr_res; 111 | 112 | struct value_arr_res * 113 | prepare_arguments(int nargs, struct ast_expr **arg, int nparams, 114 | struct ast_variable **param, struct state *state); 115 | 116 | struct error * 117 | prepare_parameters(int nparams, struct ast_variable **param, 118 | struct value_arr *args, char *fname, struct state *state); 119 | 120 | struct string_arr * 121 | ast_expr_getfuncs(struct ast_expr *); 122 | 123 | struct ast_type; 124 | struct ast_declaration; 125 | 126 | char * 127 | ast_declaration_name(struct ast_declaration *); 128 | 129 | struct ast_type * 130 | ast_declaration_type(struct ast_declaration *); 131 | 132 | struct ast_declaration * 133 | ast_expr_declare(struct ast_expr *, struct ast_type *base); 134 | 135 | struct ast_expr * 136 | ast_expr_declarator(struct ast_expr *); 137 | 138 | struct ast_expr * 139 | ast_expr_initialiser(struct ast_expr *); 140 | 141 | struct ast_type * 142 | calloralloc_type(struct ast_expr *e, struct state *s); 143 | 144 | struct e_res; 145 | 146 | struct e_res * 147 | ast_expr_setupverify(struct ast_expr *, struct state *); 148 | 149 | #endif 150 | -------------------------------------------------------------------------------- /src/ast/include/function.h: -------------------------------------------------------------------------------- 1 | #ifndef AST_FUNCTION_H 2 | #define AST_FUNCTION_H 3 | 4 | struct ast_function; 5 | struct ast_function_arr; 6 | 7 | struct ast_function_arr * 8 | ast_function_arr_create(void); 9 | 10 | struct ast_function_arr * 11 | ast_function_arr_copy(struct ast_function_arr *); 12 | 13 | void 14 | ast_function_arr_destroy(struct ast_function_arr *); 15 | 16 | void 17 | ast_function_arr_append(struct ast_function_arr *, struct ast_function *); 18 | 19 | void 20 | ast_function_arr_appendrange(struct ast_function_arr *, struct ast_function_arr *); 21 | 22 | int 23 | ast_function_arr_len(struct ast_function_arr *); 24 | 25 | struct ast_function ** 26 | ast_function_arr_func(struct ast_function_arr *); 27 | 28 | struct ast_function_arr * 29 | paths_fromfunction(struct ast_function *f); 30 | 31 | struct externals; 32 | 33 | struct map * 34 | ast_function_buildgraph(char *fname, struct externals *ext); 35 | 36 | struct ast_function * 37 | ast_function_protostitch(struct ast_function *f, struct externals *ext); 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /src/ast/include/intern.h: -------------------------------------------------------------------------------- 1 | #ifndef XR0_AST_RESULT_H 2 | #define XR0_AST_RESULT_H 3 | #include 4 | 5 | struct error; 6 | 7 | struct ast_type; 8 | struct location; 9 | struct value; 10 | 11 | struct state; 12 | 13 | struct value_res; 14 | 15 | struct value_res * 16 | eval_to_value(struct eval *, struct state *); 17 | 18 | struct object_res; 19 | 20 | struct object_res * 21 | eval_to_object(struct eval *, struct state *, bool constructive); 22 | 23 | struct preresult; 24 | 25 | struct preresult * 26 | preresult_empty_create(void); 27 | 28 | struct preresult * 29 | preresult_error_create(struct error *err); 30 | 31 | struct preresult * 32 | preresult_contradiction_create(void); 33 | 34 | void 35 | preresult_destroy(struct preresult *); 36 | 37 | bool 38 | preresult_isempty(struct preresult *); 39 | 40 | bool 41 | preresult_iserror(struct preresult *); 42 | 43 | struct error * 44 | preresult_as_error(struct preresult *); 45 | 46 | bool 47 | preresult_iscontradiction(struct preresult *); 48 | 49 | DECLARE_RESULT_TYPE(struct ast_expr *, expr, iresult) 50 | 51 | struct namedseq; 52 | 53 | struct namedseq * 54 | namedseq_create(char *name); 55 | 56 | char * 57 | namedseq_next(struct namedseq *); 58 | 59 | void 60 | namedseq_destroy(struct namedseq *); 61 | 62 | #endif 63 | -------------------------------------------------------------------------------- /src/ast/include/literals.h: -------------------------------------------------------------------------------- 1 | #ifndef XR0_AST_LITERALS_H 2 | #define XR0_AST_LITERALS_H 3 | 4 | int 5 | parse_int(char *s); 6 | 7 | char 8 | parse_char(char *s); 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /src/ast/include/stmt.h: -------------------------------------------------------------------------------- 1 | #ifndef XR0_AST_STMT_H 2 | #define XR0_AST_STMT_H 3 | 4 | struct string_arr; 5 | 6 | struct string_arr * 7 | ast_stmt_getfuncs(struct ast_stmt *stmt); 8 | 9 | struct ast_stmt * 10 | ast_stmt_create_for(struct lexememarker *loc, struct ast_stmt *init, 11 | struct ast_stmt *cond, struct ast_expr *update, 12 | struct ast_block *inv, struct ast_stmt *body); 13 | 14 | int 15 | ast_stmt_isjump(struct ast_stmt *); 16 | 17 | int 18 | ast_stmt_isreturn(struct ast_stmt *); 19 | 20 | int 21 | ast_stmt_isbreak(struct ast_stmt *); 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /src/ast/include/topological.h: -------------------------------------------------------------------------------- 1 | #ifndef XR0_TOPOLOGICAL_H 2 | #define XR0_TOPOLOGICAL_H 3 | 4 | struct externals; 5 | 6 | struct string_arr * 7 | topological_order(char *fname, struct externals *); 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /src/ast/include/type.h: -------------------------------------------------------------------------------- 1 | #ifndef XR0_AST_TYPE_H 2 | #define XR0_AST_TYPE_H 3 | 4 | enum ast_type_modifier { 5 | MOD_TYPEDEF = 1 << 0, 6 | 7 | /* storage class */ 8 | MOD_EXTERN = 1 << 1, 9 | MOD_STATIC = 1 << 2, 10 | MOD_AUTO = 1 << 3, 11 | MOD_REGISTER = 1 << 4, 12 | 13 | /* qualifier */ 14 | MOD_CONST = 1 << 5, 15 | MOD_VOLATILE = 1 << 6, 16 | }; 17 | 18 | enum ast_type_base { /* base type */ 19 | /* variable type */ 20 | TYPE_VOID, 21 | TYPE_CHAR, 22 | TYPE_SHORT, 23 | TYPE_INT, 24 | TYPE_LONG, 25 | TYPE_FLOAT, 26 | TYPE_DOUBLE, 27 | TYPE_SIGNED, 28 | TYPE_UNSIGNED, 29 | 30 | /* derived */ 31 | TYPE_POINTER, 32 | TYPE_ARRAY, 33 | TYPE_STRUCT, 34 | TYPE_UNION, 35 | TYPE_USERDEF, 36 | 37 | TYPE_ENUM, 38 | }; 39 | 40 | struct ast_type * 41 | ast_type_create(enum ast_type_base base, enum ast_type_modifier mod); 42 | 43 | void 44 | ast_type_mod_or(struct ast_type *, enum ast_type_modifier); 45 | 46 | struct externals; 47 | struct namedseq; 48 | struct lexememarker; 49 | 50 | struct ast_expr * 51 | ast_type_rconstgeninstr(struct ast_type *, struct namedseq *, 52 | struct lexememarker *, struct ast_block *, struct externals *); 53 | 54 | int 55 | ast_type_compatible(struct ast_type *, struct ast_type *); 56 | 57 | int 58 | ast_type_compatiblewithrconst(struct ast_type *); 59 | 60 | #endif 61 | -------------------------------------------------------------------------------- /src/ast/literals.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "literals.h" 6 | 7 | int 8 | parse_int(char *s) 9 | { 10 | /* XXX */ 11 | int n = 0; 12 | for (; *s; s++) { 13 | n = 10*n + ((int) *s - '0'); 14 | } 15 | return n; 16 | } 17 | 18 | int 19 | parse_escape(char c); 20 | 21 | char 22 | parse_char(char *s) 23 | { 24 | /* literal must be nonempty and begin in a quote */ 25 | assert(strlen(s) >= 3 && s[0] == '\''); 26 | 27 | switch (s[1]) { 28 | case '\\': 29 | assert(s[3] == '\''); 30 | return parse_escape(s[2]); 31 | default: 32 | assert(s[2] == '\''); 33 | return s[1]; 34 | } 35 | } 36 | 37 | int 38 | parse_escape(char c) 39 | { 40 | switch (c) { 41 | case '0': 42 | return '\0'; 43 | case 't': 44 | return '\t'; 45 | case 'n': 46 | return '\t'; 47 | default: 48 | assert(false); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/ast/stmt/iter.h: -------------------------------------------------------------------------------- 1 | #ifndef XR0_AST_STMT_ITER_H 2 | #define XR0_AST_STMT_ITER_H 3 | 4 | struct iter; 5 | 6 | struct ast_block; 7 | struct ast_expr; 8 | struct ast_stmt; 9 | 10 | struct iter * 11 | iter_for_create(struct ast_stmt *init, struct ast_stmt *cond, 12 | struct ast_expr *update, struct ast_block *inv, 13 | struct ast_stmt *body); 14 | 15 | struct iter * 16 | iter_copy(struct iter *); 17 | 18 | void 19 | iter_destroy(struct iter *); 20 | 21 | struct strbuilder; 22 | 23 | void 24 | iter_sprint(struct iter *iter, int indent, struct strbuilder *); 25 | 26 | struct ast_block * 27 | iter_inv(struct iter *); 28 | 29 | int 30 | iter_inwhile1form(struct iter *); 31 | 32 | struct lexememarker; 33 | 34 | struct ast_block * 35 | iter_while1form(struct iter *, struct lexememarker *); 36 | 37 | struct state; 38 | 39 | void 40 | iter_pushstatebody(struct iter *, struct state *); 41 | 42 | struct string_arr; 43 | 44 | struct string_arr * 45 | iter_getfuncs(struct iter *); 46 | 47 | #endif 48 | -------------------------------------------------------------------------------- /src/ast/stmt/jump.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "ast.h" 5 | #include "util.h" 6 | 7 | #include "expr.h" 8 | 9 | #include "jump.h" 10 | 11 | struct jump { 12 | enum type { 13 | BREAK, 14 | RETURN, 15 | } t; 16 | struct ast_expr *rv; 17 | }; 18 | 19 | static struct jump * 20 | jump_create(enum type t) 21 | { 22 | struct jump *j = malloc(sizeof(struct jump)); 23 | assert(j); 24 | j->t = t; 25 | return j; 26 | } 27 | 28 | struct jump * 29 | jump_break_create(void) 30 | { 31 | return jump_create(BREAK); 32 | } 33 | 34 | struct jump * 35 | jump_return_create(struct ast_expr *rv) 36 | { 37 | struct jump *j = jump_create(RETURN); 38 | j->rv = rv; 39 | return j; 40 | } 41 | 42 | struct jump * 43 | jump_copy(struct jump *old) 44 | { 45 | struct jump *new = jump_create(old->t); 46 | if (old->t == RETURN && old->rv) { 47 | new->rv = ast_expr_copy(old->rv); 48 | } 49 | return new; 50 | } 51 | 52 | void 53 | jump_destroy(struct jump *j) 54 | { 55 | if (j->t == RETURN && j->rv) { 56 | ast_expr_destroy(j->rv); 57 | } 58 | free(j); 59 | } 60 | 61 | static char * 62 | return_str(struct jump *); 63 | 64 | char * 65 | jump_str(struct jump *j) 66 | { 67 | switch (j->t) { 68 | case BREAK: 69 | return dynamic_str("break;"); 70 | case RETURN: 71 | return return_str(j); 72 | default: 73 | assert(false); 74 | } 75 | } 76 | 77 | static char * 78 | return_str(struct jump *j) 79 | { 80 | struct strbuilder *b = strbuilder_create(); 81 | if (j->rv) { 82 | char *rv = ast_expr_str(j->rv); 83 | strbuilder_printf(b, "return %s;", rv); 84 | free(rv); 85 | } else { 86 | strbuilder_printf(b, "return;"); 87 | } 88 | return strbuilder_build(b); 89 | } 90 | 91 | int 92 | jump_isreturn(struct jump *j) 93 | { 94 | return j->t == RETURN; 95 | } 96 | 97 | int 98 | jump_hasrv(struct jump *j) 99 | { 100 | return jump_isreturn(j) && j->rv; 101 | } 102 | 103 | struct ast_expr * 104 | jump_rv(struct jump *j) 105 | { 106 | assert(jump_isreturn(j)); 107 | assert(jump_hasrv(j)); 108 | return j->rv; 109 | } 110 | 111 | int 112 | jump_isbreak(struct jump *j) 113 | { 114 | return j->t == BREAK; 115 | } 116 | 117 | 118 | struct string_arr * 119 | jump_getfuncs(struct jump *j) 120 | { 121 | if (j->t == RETURN && j->rv) { 122 | return ast_expr_getfuncs(j->rv); 123 | } 124 | return string_arr_create(); 125 | } 126 | -------------------------------------------------------------------------------- /src/ast/stmt/jump.h: -------------------------------------------------------------------------------- 1 | #ifndef XR0_AST_STMT_JUMP_H 2 | #define XR0_AST_STMT_JUMP_H 3 | 4 | struct jump * 5 | jump_break_create(void); 6 | 7 | struct jump * 8 | jump_return_create(struct ast_expr *rv); 9 | 10 | struct jump * 11 | jump_copy(struct jump *); 12 | 13 | void 14 | jump_destroy(struct jump *); 15 | 16 | char * 17 | jump_str(struct jump *); 18 | 19 | int 20 | jump_isreturn(struct jump *); 21 | 22 | int 23 | jump_hasrv(struct jump *); 24 | 25 | struct ast_expr; 26 | 27 | struct ast_expr * 28 | jump_rv(struct jump *); 29 | 30 | int 31 | jump_isbreak(struct jump *); 32 | 33 | struct string_arr; 34 | 35 | struct string_arr * 36 | jump_getfuncs(struct jump *); 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /src/ast/stmt/stmt.h: -------------------------------------------------------------------------------- 1 | #ifndef XR0_AST_STMT_STMT_H 2 | #define XR0_AST_STMT_STMT_H 3 | 4 | #include "util.h" 5 | 6 | enum ast_stmt_kind { 7 | STMT_NOP, 8 | STMT_DECLARATION, 9 | STMT_LABELLED, 10 | STMT_COMPOUND, 11 | STMT_COMPOUND_V, 12 | STMT_EXPR, 13 | STMT_SELECTION, 14 | STMT_ITERATION, 15 | STMT_JUMP, 16 | STMT_ALLOCATION, 17 | STMT_REGISTER, 18 | }; 19 | 20 | enum ast_stmt_kind 21 | ast_stmt_kind(struct ast_stmt *); 22 | 23 | bool 24 | ast_stmt_issetup(struct ast_stmt *); 25 | 26 | struct string_arr * 27 | ast_stmt_getfuncs(struct ast_stmt *); 28 | 29 | struct iter * 30 | ast_stmt_as_iter(struct ast_stmt *); 31 | 32 | struct lexememarker; 33 | 34 | struct ast_stmt * 35 | ast_stmt_create_iter(struct lexememarker *, struct iter *); 36 | 37 | struct jump * 38 | ast_stmt_as_jump(struct ast_stmt *); 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /src/ast/topological.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "ast.h" 5 | #include "ext.h" 6 | #include "util.h" 7 | #include "function.h" 8 | 9 | /* 10 | * map g maps node to adjacent neighbouring nodes 11 | */ 12 | 13 | static struct map * 14 | calculate_indegrees(struct map *g); 15 | 16 | static struct string_arr * 17 | build_indegree_zero(struct map *indegrees); 18 | 19 | struct string_arr * 20 | topological_order(char *fname, struct externals *ext) 21 | { 22 | struct string_arr *order = string_arr_create(); 23 | 24 | struct map *g = ast_function_buildgraph(fname, ext); 25 | struct map *indegrees = calculate_indegrees(g); 26 | struct string_arr *indegree_zero = build_indegree_zero(indegrees); 27 | /* while there are nodes of indegree zero */ 28 | while (string_arr_n(indegree_zero) > 0) { 29 | /* add one node with indegree zero to ordered */ 30 | char *curr = string_arr_deque(indegree_zero); 31 | string_arr_append(order, curr); 32 | 33 | for (int i = 0; i < g->n; i++) { 34 | struct entry e = g->entry[i]; 35 | struct string_arr *v = (struct string_arr *) map_get(g, e.key); 36 | if (string_arr_contains(v, curr)) { 37 | /* decrement indegree */ 38 | int *count = (int *) map_get(indegrees, e.key); 39 | *count = *count - 1; 40 | if (*count == 0) { 41 | string_arr_append(indegree_zero, dynamic_str(e.key)); 42 | } 43 | } 44 | } 45 | } 46 | 47 | /* no more nodes with incoming edges */ 48 | if (string_arr_n(order) != indegrees->n) { 49 | /* TODO: pass up error */ 50 | fprintf(stderr, "cycle detected in graph\n"); 51 | exit(EXIT_FAILURE); 52 | } 53 | 54 | return order; 55 | } 56 | 57 | static int * 58 | dynamic_int(int i); 59 | 60 | static struct map * 61 | calculate_indegrees(struct map *g) 62 | { 63 | struct map *indegrees = map_create(); 64 | for (int i = 0; i < g->n; i++) { 65 | struct entry e = g->entry[i]; 66 | struct string_arr *deps = (struct string_arr *) map_get(g, e.key); 67 | 68 | /* init all nodes and their dependencies to 0 */ 69 | if (map_get(indegrees, e.key) != NULL) { 70 | continue; 71 | } 72 | map_set(indegrees, dynamic_str(e.key), dynamic_int(0)); 73 | for (int j = 0; j < string_arr_n(deps); j++) { 74 | char *dep_key = string_arr_s(deps)[j]; 75 | if (map_get(indegrees, dep_key) != NULL) { 76 | continue; 77 | } 78 | map_set(indegrees, dynamic_str(dep_key), dynamic_int(0)); 79 | } 80 | } 81 | 82 | for (int i = 0; i < indegrees->n; i++) { 83 | struct entry e = indegrees->entry[i]; 84 | struct string_arr *n_arr = map_get(g, e.key); 85 | if (!n_arr) { 86 | continue; 87 | } 88 | for (int j = 0; j < string_arr_n(n_arr); j++) { 89 | int *count = (int *) map_get(indegrees, e.key); 90 | *count = *count + 1; /* XXX */ 91 | } 92 | } 93 | return indegrees; 94 | } 95 | 96 | static int * 97 | dynamic_int(int i) 98 | { 99 | int *val = malloc(sizeof(int)); 100 | *val = i; 101 | return val; 102 | } 103 | 104 | static struct string_arr * 105 | build_indegree_zero(struct map *indegrees) 106 | { 107 | struct string_arr *indegree_zero = string_arr_create(); 108 | for (int i = 0; i < indegrees->n; i++) { 109 | struct entry e = indegrees->entry[i]; 110 | int *val = (int *) map_get(indegrees, e.key); 111 | if (*val == 0) { 112 | string_arr_append( 113 | indegree_zero, 114 | dynamic_str(e.key) 115 | ); 116 | } 117 | } 118 | return indegree_zero; 119 | } 120 | -------------------------------------------------------------------------------- /src/ast/variable.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "ast.h" 6 | #include "util.h" 7 | 8 | struct ast_variable { 9 | char *name; 10 | struct ast_type *type; 11 | struct ast_expr *init; /* optional */ 12 | }; 13 | 14 | struct ast_variable * 15 | ast_variable_create(char *name, struct ast_type *type) 16 | { 17 | struct ast_variable *v = malloc(sizeof(struct ast_variable)); 18 | v->name = name; 19 | v->type = type; 20 | v->init = NULL; 21 | return v; 22 | } 23 | 24 | void 25 | ast_variable_setinit(struct ast_variable *v, struct ast_expr *e) 26 | { 27 | assert(!v->init); 28 | v->init = e; 29 | } 30 | 31 | struct ast_expr * 32 | ast_variable_init(struct ast_variable *v) 33 | { 34 | return v->init; 35 | } 36 | 37 | void 38 | ast_variable_destroy(struct ast_variable *v) 39 | { 40 | ast_type_destroy(v->type); 41 | free(v->name); 42 | free(v); 43 | } 44 | 45 | struct ast_variable * 46 | ast_variable_copy(struct ast_variable *v) 47 | { 48 | assert(v); 49 | struct ast_variable *copy = ast_variable_create( 50 | dynamic_str(v->name), ast_type_copy(v->type) 51 | ); 52 | if (v->init) { 53 | copy->init = ast_expr_copy(v->init); 54 | } 55 | return copy; 56 | } 57 | 58 | struct ast_variable ** 59 | ast_variables_copy(int n, struct ast_variable **v) 60 | { 61 | assert(v || !n); 62 | struct ast_variable **new = calloc(n, sizeof(struct variable *)); 63 | for (int i = 0; i < n; i++) { 64 | new[i] = ast_variable_copy(v[i]); 65 | } 66 | return new; 67 | } 68 | 69 | char * 70 | ast_variable_str(struct ast_variable *v) 71 | { 72 | struct strbuilder *b = strbuilder_create(); 73 | char *t = ast_type_str(v->type); 74 | 75 | strbuilder_printf(b, "%s %s", t, v->name); 76 | free(t); 77 | return strbuilder_build(b); 78 | } 79 | 80 | char * 81 | ast_variable_name(struct ast_variable *v) 82 | { 83 | return v->name; 84 | } 85 | 86 | struct ast_type * 87 | ast_variable_type(struct ast_variable *v) 88 | { 89 | return v->type; 90 | } 91 | 92 | 93 | struct ast_variable_arr { 94 | int n; 95 | struct ast_variable **v; 96 | }; 97 | 98 | struct ast_variable_arr * 99 | ast_variable_arr_create(void) 100 | { 101 | return calloc(1, sizeof(struct ast_variable_arr)); 102 | } 103 | 104 | void 105 | ast_variable_arr_append(struct ast_variable_arr *arr, struct ast_variable *v) 106 | { 107 | arr->v = realloc(arr->v, sizeof(struct ast_variable *) * ++arr->n); 108 | arr->v[arr->n-1] = v; 109 | } 110 | 111 | void 112 | ast_variable_arr_destroy(struct ast_variable_arr *arr) 113 | { 114 | for (int i = 0; i < arr->n; i++) { 115 | ast_variable_destroy(arr->v[i]); 116 | } 117 | free(arr); 118 | } 119 | 120 | int 121 | ast_variable_arr_n(struct ast_variable_arr *arr) 122 | { 123 | return arr->n; 124 | } 125 | 126 | struct ast_variable ** 127 | ast_variable_arr_v(struct ast_variable_arr *arr) 128 | { 129 | return arr->v; 130 | } 131 | 132 | struct ast_variable_arr * 133 | ast_variable_arr_copy(struct ast_variable_arr *old) 134 | { 135 | struct ast_variable_arr *new = ast_variable_arr_create(); 136 | for (int i = 0; i < old->n; i++) { 137 | ast_variable_arr_append(new, ast_variable_copy(old->v[i])); 138 | } 139 | return new; 140 | } 141 | -------------------------------------------------------------------------------- /src/ext/ext.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "ast.h" 5 | #include "util.h" 6 | 7 | struct externals { 8 | struct map *func, *var, *_typedef, *_struct; 9 | }; 10 | 11 | struct externals * 12 | externals_create(void) 13 | { 14 | struct externals *ext = malloc(sizeof(struct externals)); 15 | ext->func = map_create(); 16 | ext->var = map_create(); 17 | ext->_typedef = map_create(); 18 | ext->_struct = map_create(); 19 | return ext; 20 | } 21 | 22 | void 23 | externals_destroy(struct externals *ext) 24 | { 25 | map_destroy(ext->func); 26 | map_destroy(ext->var); 27 | map_destroy(ext->_typedef); 28 | map_destroy(ext->_struct); 29 | free(ext); 30 | } 31 | 32 | char * 33 | externals_types_str(struct externals *ext, char *indent) 34 | { 35 | struct strbuilder *b = strbuilder_create(); 36 | 37 | struct map *m = ext->_typedef; 38 | for (int i = 0; i < m->n; i++) { 39 | struct entry e = m->entry[i]; 40 | char *type = ast_type_str((struct ast_type *) e.value); 41 | strbuilder_printf(b, "%s%s %s\n", indent, type, e.key); 42 | free(type); 43 | } 44 | m = ext->_struct; 45 | for (int i = 0; i < m->n; i++) { 46 | char *type = ast_type_str((struct ast_type *) m->entry[i].value); 47 | strbuilder_printf(b, "%s%s\n", indent, type); 48 | free(type); 49 | } 50 | 51 | return strbuilder_build(b); 52 | } 53 | 54 | void 55 | externals_declarefunc(struct externals *ext, char *id, struct ast_function *f) 56 | { 57 | map_set(ext->func, dynamic_str(id), f); 58 | } 59 | 60 | void 61 | externals_declarevar(struct externals *ext, char *id, struct ast_variable *v) 62 | { 63 | map_set(ext->var, dynamic_str(id), v); 64 | } 65 | 66 | void 67 | externals_declaretypedef(struct externals *ext, char *id, struct ast_type *t) 68 | { 69 | map_set(ext->_typedef, dynamic_str(id), t); 70 | } 71 | 72 | void 73 | externals_declarestruct(struct externals *ext, struct ast_type *t) 74 | { 75 | char *id = ast_type_struct_tag(t); 76 | assert(id); 77 | map_set(ext->_struct, dynamic_str(id), t); 78 | } 79 | 80 | struct ast_function * 81 | externals_getfunc(struct externals *ext, char *id) 82 | { 83 | return map_get(ext->func, id); 84 | } 85 | 86 | struct ast_type * 87 | externals_gettypedef(struct externals *ext, char *id) 88 | { 89 | return map_get(ext->_typedef, id); 90 | } 91 | 92 | struct ast_type * 93 | externals_getstruct(struct externals *ext, char *id) 94 | { 95 | return map_get(ext->_struct, id); 96 | } 97 | -------------------------------------------------------------------------------- /src/include/breakpoint.h: -------------------------------------------------------------------------------- 1 | #ifndef BREAKPOINT_H 2 | #define BREAKPOINT_H 3 | 4 | struct breakpoint; 5 | 6 | char * 7 | breakpoint_list(void); 8 | 9 | struct error * 10 | breakpoint_set(char *filename, int linenum); 11 | 12 | struct error * 13 | breakpoint_delete(int id); 14 | 15 | struct lexememarker; 16 | 17 | bool 18 | breakpoint_shouldbreak(struct lexememarker *); 19 | 20 | void 21 | breakpoint_reset(void); 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /src/include/ext.h: -------------------------------------------------------------------------------- 1 | #ifndef EXT_H 2 | #define EXT_H 3 | 4 | struct externals; 5 | 6 | struct externals * 7 | externals_create(void); 8 | 9 | void 10 | externals_destroy(struct externals *); 11 | 12 | char * 13 | externals_types_str(struct externals *, char *indent); 14 | 15 | struct ast_function; 16 | struct ast_variable; 17 | struct ast_type; 18 | 19 | void 20 | externals_declarefunc(struct externals *, char *id, struct ast_function *); 21 | 22 | void 23 | externals_declarevar(struct externals *, char *id, struct ast_variable *); 24 | 25 | void 26 | externals_declaretypedef(struct externals *, char *id, struct ast_type *type); 27 | 28 | void 29 | externals_declarestruct(struct externals *, struct ast_type *type); 30 | 31 | struct ast_function * 32 | externals_getfunc(struct externals *, char *id); 33 | 34 | struct ast_type * 35 | externals_gettypedef(struct externals *, char *id); 36 | 37 | struct ast_type * 38 | externals_getstruct(struct externals *, char *id); 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /src/include/gram_util.h: -------------------------------------------------------------------------------- 1 | #ifndef GRAM_UTIL_H 2 | #define GRAM_UTIL_H 3 | 4 | /* TODO: refactor this file out of existence */ 5 | 6 | struct expr_array { 7 | int n; 8 | struct ast_expr **expr; 9 | }; 10 | 11 | struct stmt_array { 12 | int n; 13 | struct ast_stmt **stmt; 14 | }; 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /src/include/lex.h: -------------------------------------------------------------------------------- 1 | #ifndef XR0_LEX_H 2 | #define XR0_LEX_H 3 | 4 | #define XR0_INCLUDES_SEGMENT "libx/" 5 | 6 | struct lexememarker { 7 | int linenum, column; 8 | char *filename; 9 | enum linemarker_flag { 10 | LM_FLAG_NEW_FILE = 1 << 0, 11 | LM_FLAG_RESUME_FILE = 1 << 1, 12 | LM_FLAG_SYS_HEADER = 1 << 2, 13 | LM_FLAG_IMPLICIT_EXTERN = 1 << 3, 14 | } flags; 15 | }; 16 | 17 | struct lexememarker * 18 | lexloc(void); 19 | 20 | int 21 | lexememarker_linenum(struct lexememarker *); 22 | 23 | char * 24 | lexememarker_filename(struct lexememarker *); 25 | 26 | struct lexememarker * 27 | lexememarker_copy(struct lexememarker *); 28 | 29 | void 30 | lexememarker_destroy(struct lexememarker *); 31 | 32 | char * 33 | lexememarker_str(struct lexememarker *); 34 | 35 | extern struct ast_expr *YACC_PARSED_EXPR; 36 | extern struct ast *root; 37 | extern struct map *table; 38 | 39 | enum ictype { 40 | IC_NONE = 1 << 0, 41 | IC_TYPE = 1 << 1, 42 | IC_PRED = 2 << 2, 43 | }; 44 | 45 | extern enum ictype installclass; 46 | 47 | void 48 | lex_begin(void); 49 | 50 | void 51 | lex_finish(void); 52 | 53 | int 54 | yylex_destroy(void); 55 | 56 | #endif 57 | -------------------------------------------------------------------------------- /src/include/math.h: -------------------------------------------------------------------------------- 1 | #ifndef XR0_MATH_KERNEL_H 2 | #define XR0_MATH_KERNEL_H 3 | 4 | #include 5 | 6 | struct math_expr; 7 | 8 | /* math_le: e1 ≤ e2 */ 9 | bool 10 | math_le(struct math_expr *e1, struct math_expr *e2); 11 | 12 | bool 13 | math_eq(struct math_expr *e1, struct math_expr *e2); 14 | 15 | bool 16 | math_lt(struct math_expr *e1, struct math_expr *e2); 17 | 18 | bool 19 | math_gt(struct math_expr *e1, struct math_expr *e2); 20 | 21 | bool 22 | math_ge(struct math_expr *e1, struct math_expr *e2); 23 | 24 | 25 | struct math_atom; 26 | 27 | struct math_expr * 28 | math_expr_atom_create(struct math_atom *); 29 | 30 | struct math_expr * 31 | math_expr_sum_create(struct math_expr *, struct math_expr *); 32 | 33 | struct math_expr * 34 | math_expr_neg_create(struct math_expr *); 35 | 36 | struct math_expr * 37 | math_expr_copy(struct math_expr *); 38 | 39 | void 40 | math_expr_destroy(struct math_expr *); 41 | 42 | char * 43 | math_expr_str(struct math_expr *); 44 | 45 | struct math_expr * 46 | math_expr_simplify(struct math_expr *raw); 47 | 48 | 49 | struct math_atom * 50 | math_atom_nat_create(unsigned int); 51 | 52 | struct math_atom * 53 | math_atom_variable_create(char *); 54 | 55 | struct math_atom * 56 | math_atom_copy(struct math_atom *); 57 | 58 | void 59 | math_atom_destroy(struct math_atom *); 60 | 61 | char * 62 | math_atom_str(struct math_atom *); 63 | 64 | #endif 65 | -------------------------------------------------------------------------------- /src/include/object.h: -------------------------------------------------------------------------------- 1 | #ifndef OBJECT_H 2 | #define OBJECT_H 3 | 4 | struct value; 5 | struct object; 6 | 7 | struct ast_expr; 8 | 9 | struct object * 10 | object_value_create(struct ast_expr *offset, struct value *); 11 | 12 | struct object * 13 | object_copy(struct object *old); 14 | 15 | struct object * 16 | object_abstractcopy(struct object *old, struct state *s); 17 | 18 | struct int_arr; 19 | 20 | struct circuitbreaker; 21 | 22 | struct state; 23 | 24 | struct int_arr * 25 | object_deriveorder(struct object *, struct circuitbreaker *, struct state *); 26 | 27 | struct permutation; 28 | 29 | struct object * 30 | object_permuteheaplocs(struct object *, struct permutation *); 31 | 32 | void 33 | object_destroy(struct object *); 34 | 35 | char * 36 | object_str(struct object *); 37 | 38 | struct ast_expr * 39 | object_lower(struct object *); 40 | 41 | struct ast_expr * 42 | object_upper(struct object *); 43 | 44 | struct state; 45 | 46 | bool 47 | object_isdeallocand(struct object *, struct state *); 48 | 49 | struct location; 50 | 51 | bool 52 | object_references(struct object *, struct location *, struct state *, 53 | struct circuitbreaker *); 54 | 55 | 56 | bool 57 | object_referencesheap(struct object *, struct state *, struct circuitbreaker *); 58 | 59 | bool 60 | object_hasvalue(struct object *); 61 | 62 | struct value * 63 | object_as_value(struct object *); 64 | 65 | struct error * 66 | object_assign(struct object *, struct value *); 67 | 68 | struct error * 69 | object_transfigure(struct object *obj, struct value *val, struct state *actual, 70 | struct state *compare, bool islval); 71 | 72 | bool 73 | object_contains(struct object *, struct ast_expr *, struct state *); 74 | 75 | bool 76 | object_contig_precedes(struct object *before, struct object *after, 77 | struct state *); 78 | 79 | struct object * 80 | object_upto(struct object *, struct ast_expr *excl_upper, struct state *); 81 | 82 | struct object * 83 | object_from(struct object *, struct ast_expr *incl_lower, struct state *); 84 | 85 | struct object * 86 | object_getmember(struct object *obj, struct ast_type *t, char *member, 87 | struct state *s); 88 | 89 | struct ast_type * 90 | object_getmembertype(struct object *obj, struct ast_type *t, char *member, 91 | struct state *s); 92 | 93 | struct error * 94 | object_dealloc(struct object *, struct state *); 95 | 96 | 97 | struct heap; 98 | 99 | 100 | struct object_arr; 101 | 102 | struct object_arr * 103 | object_arr_create(void); 104 | 105 | void 106 | object_arr_destroy(struct object_arr *); 107 | 108 | struct object_arr * 109 | object_arr_copy(struct object_arr *); 110 | 111 | int 112 | object_arr_nobjects(struct object_arr *); 113 | 114 | struct object ** 115 | object_arr_objects(struct object_arr *); 116 | 117 | int 118 | object_arr_index(struct object_arr *arr, struct ast_expr *offset, struct state *); 119 | 120 | int 121 | object_arr_index_upperincl(struct object_arr *arr, struct ast_expr *offset, 122 | struct state *); 123 | 124 | int 125 | object_arr_insert(struct object_arr *arr, int index, struct object *); 126 | 127 | int 128 | object_arr_append(struct object_arr *arr, struct object *obj); 129 | 130 | void 131 | object_arr_remove(struct object_arr *arr, int index); 132 | 133 | DECLARE_RESULT_TYPE(struct object *, object, object_res) 134 | 135 | #endif 136 | -------------------------------------------------------------------------------- /src/include/storage.h: -------------------------------------------------------------------------------- 1 | #ifndef XR0_STATE_H 2 | #define XR0_STATE_H 3 | 4 | /* util.h */ 5 | struct map; 6 | 7 | struct state; 8 | 9 | struct state * 10 | state_create(struct map *extfunc, struct ast_type *result_type); 11 | 12 | void 13 | state_destroy(struct state *state); 14 | 15 | bool 16 | state_abstractly_equivalent(struct state *s1, struct state *s2); 17 | 18 | bool 19 | state_heap_referenced(struct state *state); 20 | 21 | void 22 | state_pushframe(struct state *state, struct ast_type *type); 23 | 24 | void 25 | state_popframe(struct state *state); 26 | 27 | void 28 | state_declare(struct state *state, struct ast_variable *var, bool isparam); 29 | 30 | struct ast_variable ** 31 | state_getvariables(struct state *state); 32 | 33 | int 34 | state_nvariables(struct state *state); 35 | 36 | struct map * 37 | state_extfunc(struct state *state); 38 | 39 | struct ast_function * 40 | state_getfunc(struct state *state, char *f); 41 | 42 | struct reference * 43 | state_getresult(struct state *state); 44 | 45 | typedef struct reference Ref; 46 | 47 | Ref * 48 | ref_create_offset(char *id, int nderef, struct ast_expr *offset); 49 | 50 | Ref * 51 | ref_create_range(char *id, int nderef, struct ast_expr *lower, 52 | struct ast_expr *upper); 53 | 54 | void 55 | ref_destroy(Ref *ref); 56 | 57 | bool 58 | ref_isresult(Ref *ref); 59 | 60 | char * 61 | ref_id(Ref *ref); 62 | 63 | int 64 | ref_nderef(Ref *ref); 65 | 66 | char * 67 | ref_str(Ref *ref); 68 | 69 | bool 70 | state_ref_onheap(struct state *state, Ref *ref); 71 | 72 | struct error * 73 | state_ref_unalloc(struct state *state, Ref *ref); 74 | 75 | typedef struct heaploc Heaploc; 76 | 77 | struct error * 78 | state_heaploc_free(struct state *state, Heaploc *loc); 79 | 80 | Heaploc * 81 | state_ref_get_heaploc(struct state *state, Ref *ref); 82 | 83 | void 84 | state_ref_assign_heaploc(struct state *state, Ref *ref, Heaploc *loc); 85 | 86 | bool 87 | state_ref_canfree(struct state *state, Ref *ref); 88 | 89 | void 90 | state_result_assign(struct state *state, Heaploc *loc); 91 | 92 | Heaploc * 93 | state_alloc(struct state *state); 94 | 95 | char * 96 | state_str(struct state *state); 97 | 98 | #endif 99 | -------------------------------------------------------------------------------- /src/include/value.h: -------------------------------------------------------------------------------- 1 | #ifndef XR0_VALUE_H 2 | #define XR0_VALUE_H 3 | 4 | #include 5 | 6 | struct value; 7 | 8 | struct location; 9 | 10 | struct permutation; 11 | 12 | struct int_arr; 13 | 14 | struct ast_type; 15 | 16 | struct state; 17 | 18 | struct int_arr * 19 | value_deriveorder(struct value *, struct circuitbreaker *, struct state *); 20 | 21 | struct value * 22 | value_permuteheaplocs(struct value *, struct permutation *); 23 | 24 | struct ast_type; 25 | 26 | struct value * 27 | value_ptr_create(struct location *loc); 28 | 29 | struct value * 30 | value_ptr_rconst_create(void); 31 | 32 | struct value * 33 | value_int_create(int val); 34 | 35 | int 36 | value_isint(struct value *v); 37 | 38 | struct value * 39 | value_literal_create(char *); 40 | 41 | struct ast_expr; 42 | 43 | struct value * 44 | value_int_range_create(int lw, int up); 45 | 46 | struct value * 47 | value_int_range_fromexpr(struct ast_expr *, struct state *); 48 | 49 | struct value * 50 | value_int_ne_create(int not_val); 51 | 52 | int 53 | value_int_lw(struct value *, struct state *); 54 | 55 | int 56 | value_int_up(struct value *, struct state *); 57 | 58 | int 59 | value_as_int(struct value *, struct state *); 60 | 61 | struct value * 62 | value_bang(struct value *); 63 | 64 | struct value * 65 | value_rconst_create(struct ast_expr *); 66 | 67 | struct value * 68 | value_struct_create(struct ast_type *); 69 | 70 | int 71 | value_isstruct(struct value *v); 72 | 73 | struct value * 74 | value_struct_rconst_create(struct ast_type *, struct state *, 75 | char *key, bool persist); 76 | 77 | struct value * 78 | value_struct_rconstnokey_create(struct ast_type *, struct state *, bool persist); 79 | 80 | struct value * 81 | value_pf_augment(struct value *, struct ast_expr *root); 82 | 83 | struct ast_type * 84 | value_struct_membertype(struct value *, char *member); 85 | 86 | struct object * 87 | value_struct_member(struct value *, char *member); 88 | 89 | struct error * 90 | value_struct_specval_verify(struct value *param, struct value *arg, 91 | struct state *spec, struct state *caller); 92 | 93 | struct value * 94 | value_copy(struct value *); 95 | 96 | struct value * 97 | value_abstractcopy(struct value *, struct state *s); 98 | 99 | void 100 | value_destroy(struct value *); 101 | 102 | char * 103 | value_str(struct value *); 104 | 105 | char * 106 | value_type_str(struct value *); 107 | 108 | int 109 | value_islocation(struct value *); 110 | 111 | struct location * 112 | value_as_location(struct value *); 113 | 114 | struct circuitbreaker; 115 | 116 | bool 117 | value_referencesheap(struct value *, struct state *, struct circuitbreaker *); 118 | 119 | int 120 | value_isconstant(struct value *v); 121 | 122 | int 123 | value_as_constant(struct value *v); 124 | 125 | int 126 | value_isrconst(struct value *v); 127 | 128 | struct ast_expr * 129 | value_as_rconst(struct value *v); 130 | 131 | struct ast_expr * 132 | value_to_expr(struct value *); 133 | 134 | bool 135 | value_isliteral(struct value *v); 136 | 137 | struct ast_expr * 138 | value_as_literal(struct value *v); 139 | 140 | bool 141 | value_references(struct value *, struct location *, struct state *, 142 | struct circuitbreaker *); 143 | 144 | DECLARE_RESULT_TYPE(bool, bool, bool_res) 145 | 146 | int 147 | value_eq(struct value *lhs, struct value *rhs, struct state *); 148 | 149 | int 150 | value_lt(struct value *lhs, struct value *rhs, struct state *); 151 | 152 | struct error * 153 | value_disentangle(struct value *, struct value *, struct state *); 154 | 155 | /* value_confirmsubset: returns an error if v (as belonging to s) is not 156 | * decidably a subset of v0 (as belonging to s0). */ 157 | struct error * 158 | value_confirmsubset(struct value *v, struct value *v0, struct state *s, 159 | struct state *s0); 160 | 161 | struct number; 162 | 163 | /* value_splitassume: returns 0 if contradiction encountered. */ 164 | int 165 | value_splitassume(struct value *, struct number *, struct state *); 166 | 167 | DECLARE_RESULT_TYPE(struct value *, value, value_res) 168 | 169 | struct value_arr; 170 | 171 | struct value_arr * 172 | value_arr_create(void); 173 | 174 | void 175 | value_arr_destroy(struct value_arr *arr); 176 | 177 | void 178 | value_arr_append(struct value_arr *arr, struct value *res); 179 | 180 | int 181 | value_arr_len(struct value_arr *arr); 182 | 183 | struct value ** 184 | value_arr_v(struct value_arr *arr); 185 | 186 | DECLARE_RESULT_TYPE(struct value_arr *, arr, value_arr_res) 187 | 188 | /* TODO: remove */ 189 | struct number; 190 | 191 | struct number * 192 | number_const_create(long); 193 | 194 | char * 195 | number_str(struct number *); 196 | 197 | char * 198 | number_short_str(struct number *); 199 | 200 | struct value * 201 | value_number_create(struct number *); 202 | 203 | #endif 204 | -------------------------------------------------------------------------------- /src/include/verifier.h: -------------------------------------------------------------------------------- 1 | #ifndef XR0_PATH 2 | #define XR0_PATH 3 | 4 | #include 5 | 6 | struct ast_function; 7 | struct ast_expr; 8 | struct externals; 9 | struct error; 10 | struct state; 11 | struct value; 12 | 13 | struct verifier; 14 | 15 | struct verifier * 16 | verifier_create(struct ast_function *, struct externals *); 17 | 18 | void 19 | verifier_destroy(struct verifier *); 20 | 21 | char * 22 | verifier_str(struct verifier *); 23 | 24 | bool 25 | verifier_atend(struct verifier *); 26 | 27 | typedef struct error *(progressor)(struct state *); 28 | 29 | progressor * 30 | progressor_step(void); 31 | 32 | progressor * 33 | progressor_next(void); 34 | 35 | struct error * 36 | verifier_progress(struct verifier *, progressor *); 37 | 38 | struct error * 39 | verifier_verify(struct verifier *, struct ast_expr *); 40 | 41 | struct error * 42 | verifier_setbreakpoint(struct verifier *); 43 | 44 | struct lexememarker * 45 | verifier_lexememarker(struct verifier *); 46 | 47 | int 48 | verifier_frameid(struct verifier *); 49 | 50 | struct verifierinstruct; 51 | 52 | struct splitinstruct; 53 | 54 | struct verifierinstruct * 55 | verifierinstruct_split(struct splitinstruct *); 56 | 57 | struct splitinstruct; 58 | 59 | struct splitinstruct * 60 | splitinstruct_create(struct state *); 61 | 62 | struct map; 63 | 64 | void 65 | splitinstruct_append(struct splitinstruct *, struct map *); 66 | 67 | int 68 | splitinstruct_n(struct splitinstruct *); 69 | 70 | struct map ** 71 | splitinstruct_splits(struct splitinstruct *); 72 | 73 | struct state * 74 | splitinstruct_state(struct splitinstruct *); 75 | 76 | struct rconst; 77 | 78 | struct rconst * 79 | rconst_create(void); 80 | 81 | struct rconst * 82 | rconst_copy(struct rconst *); 83 | 84 | void 85 | rconst_destroy(struct rconst *); 86 | 87 | char * 88 | rconst_str(struct rconst *, char *indent); 89 | 90 | char * 91 | rconst_declare(struct rconst *, struct value *, char *key, bool persist); 92 | 93 | char * 94 | rconst_declarenokey(struct rconst *, struct value *, bool persist); 95 | 96 | struct value * 97 | rconst_get(struct rconst *, char *id); 98 | 99 | char * 100 | rconst_getidbykey(struct rconst *, char *key); 101 | 102 | void 103 | rconst_undeclare(struct rconst *); 104 | 105 | bool 106 | rconst_eval(struct rconst *, struct ast_expr *); 107 | 108 | #endif 109 | -------------------------------------------------------------------------------- /src/state/.gitignore: -------------------------------------------------------------------------------- 1 | bin/ 2 | -------------------------------------------------------------------------------- /src/state/clump.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "ast.h" 6 | #include "location.h" 7 | #include "block.h" 8 | #include "util.h" 9 | 10 | #include "clump.h" 11 | 12 | struct clump { 13 | struct block_arr *blocks; 14 | }; 15 | 16 | struct clump * 17 | clump_create(void) 18 | { 19 | struct clump *c = malloc(sizeof(struct clump)); 20 | assert(c); 21 | c->blocks = block_arr_create(); 22 | return c; 23 | } 24 | 25 | void 26 | clump_destroy(struct clump *c) 27 | { 28 | block_arr_destroy(c->blocks); 29 | } 30 | 31 | char * 32 | clump_str(struct clump *c, char *indent) 33 | { 34 | struct strbuilder *b = strbuilder_create(); 35 | int n = block_arr_nblocks(c->blocks); 36 | struct block **arr = block_arr_blocks(c->blocks); 37 | for (int i = 0; i < n; i++) { 38 | char *block = block_str(arr[i]); 39 | strbuilder_printf(b, "%s%d: %s\n", indent, i, block); 40 | free(block); 41 | } 42 | return strbuilder_build(b); 43 | } 44 | 45 | struct clump * 46 | clump_copy(struct clump *c) 47 | { 48 | struct clump *copy = malloc(sizeof(struct clump)); 49 | copy->blocks = block_arr_copy(c->blocks); 50 | return copy; 51 | } 52 | 53 | int 54 | clump_newblock(struct clump *c, int size) 55 | { 56 | int address = block_arr_append(c->blocks, block_callercreate(size)); 57 | 58 | int n = block_arr_nblocks(c->blocks); 59 | assert(n > 0); 60 | 61 | return address; 62 | } 63 | 64 | struct block * 65 | clump_getblock(struct clump *c, int address) 66 | { 67 | if (address >= block_arr_nblocks(c->blocks)) { 68 | return NULL; 69 | } 70 | return block_arr_blocks(c->blocks)[address]; 71 | } 72 | 73 | static bool 74 | block_referenceswithcb(struct block *, struct location *, struct state *); 75 | 76 | bool 77 | clump_callerreferences(struct clump *c, struct location *loc, struct state *s) 78 | { 79 | int n = block_arr_nblocks(c->blocks); 80 | struct block **arr = block_arr_blocks(c->blocks); 81 | for (int i = 0; i < n; i++) { 82 | if (block_referenceswithcb(arr[i], loc, s)) { 83 | return true; 84 | } 85 | } 86 | return false; 87 | } 88 | 89 | static bool 90 | block_referenceswithcb(struct block *b, struct location *loc, struct state *s) 91 | { 92 | struct circuitbreaker *cb = circuitbreaker_create(); 93 | bool ref = block_references(b, loc, s, cb); 94 | circuitbreaker_destroy(cb); 95 | return ref; 96 | } 97 | 98 | void 99 | clump_undeclare(struct clump *c, struct state *s) 100 | { 101 | int n = block_arr_nblocks(c->blocks); 102 | struct block **b = block_arr_blocks(c->blocks); 103 | for (int i = 0; i < n; i++) { 104 | block_undeclare(b[i], s); 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /src/state/constraint.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "ast.h" 6 | #include "object.h" 7 | #include "state.h" 8 | #include "value.h" 9 | 10 | #include "block.h" 11 | 12 | struct constraint { 13 | struct state *spec, *impl; 14 | struct ast_type *t; 15 | }; 16 | 17 | struct constraint * 18 | constraint_create(struct state *spec, struct state *impl, struct ast_type *t) 19 | { 20 | struct constraint *c = malloc(sizeof(struct constraint)); 21 | assert(c); 22 | c->spec = spec; 23 | c->impl = impl; 24 | c->t = t; 25 | return c; 26 | } 27 | 28 | void 29 | constraint_destroy(struct constraint *c) 30 | { 31 | ast_type_destroy(c->t); 32 | state_destroy(c->spec); 33 | state_destroy(c->impl); 34 | free(c); 35 | } 36 | 37 | static int 38 | size_le(struct location *spec_loc, struct location *impl_loc, struct state *spec, 39 | struct state *impl); 40 | 41 | /* location_reloffset: return a location pointing at the same block as l1 but 42 | * with an offset that is the difference between l1's and l2's offset. */ 43 | static struct location * 44 | location_reloffset(struct location *l1, struct location *l2); 45 | 46 | struct error * 47 | constraint_verify(struct constraint *c, struct value *spec_v, 48 | struct value *impl_v) 49 | { 50 | if (ast_type_isint(c->t)) { 51 | return value_confirmsubset(impl_v, spec_v, c->impl, c->spec); 52 | } else if (ast_type_isstruct(c->t)) { 53 | return value_struct_specval_verify(spec_v, impl_v, c->impl, c->spec); 54 | } 55 | a_printf( 56 | ast_type_isptr(c->t), 57 | "can only verify int, struct and pointer params\n" 58 | ); 59 | 60 | if (!value_islocation(spec_v)) { 61 | /* allow for NULL and other invalid-pointer setups */ 62 | return NULL; 63 | } 64 | /* spec requires value be valid pointer */ 65 | if (!value_islocation(impl_v)) { 66 | return error_printf("must be pointing at something"); 67 | } 68 | 69 | struct location *spec_loc = value_as_location(spec_v), 70 | *impl_loc = value_as_location(impl_v); 71 | if (!state_loc_valid(c->spec, spec_loc)) { 72 | /* spec freed reference */ 73 | return NULL; 74 | } 75 | if (!state_loc_valid(c->impl, impl_loc)) { 76 | return error_printf("must be lvalue"); 77 | } 78 | 79 | if (state_loc_onheap(c->spec, spec_loc) 80 | && !state_loc_onheap(c->impl, impl_loc)) { 81 | return error_printf("must be heap allocated"); 82 | } 83 | 84 | if (!size_le(spec_loc, impl_loc, c->spec, c->impl)) { 85 | return error_printf("must point at larger block"); 86 | } 87 | 88 | /* we shift the impl_loc's offset by spec_loc's so that 89 | * block_constraintverify can behave as though both were offset zero */ 90 | struct location *rel_impl_loc = location_reloffset(impl_loc, spec_loc); 91 | struct block *spec_b = state_getblock(c->spec, spec_loc); 92 | assert(spec_b); 93 | struct error *err = block_constraintverify(spec_b, rel_impl_loc, c); 94 | location_destroy(rel_impl_loc); 95 | 96 | return err; 97 | } 98 | 99 | static struct location * 100 | location_reloffset(struct location *l1, struct location *l2) 101 | { 102 | struct ast_expr *offset = ast_expr_difference_create( 103 | ast_expr_copy(offset_as_expr(location_offset(l1))), 104 | ast_expr_copy(offset_as_expr(location_offset(l2))) 105 | ); 106 | struct location *offset_loc = location_copy(l1); 107 | location_setoffset( 108 | offset_loc, offset_create(ast_expr_copy(offset)) 109 | ); 110 | return offset_loc; 111 | } 112 | 113 | static int 114 | size_le(struct location *spec_loc, struct location *impl_loc, struct state *spec, 115 | struct state *impl) 116 | { 117 | struct block *spec_b = state_getblock(spec, spec_loc), 118 | *impl_b = state_getblock(impl, impl_loc); 119 | assert(spec_b && impl_b); 120 | return block_size_le(spec_b, impl_b); 121 | } 122 | 123 | struct error * 124 | constraint_verifyobject(struct constraint *c, struct object *spec_obj, 125 | struct location *impl_loc) 126 | { 127 | struct block *b_impl = state_getblock(c->impl, impl_loc); 128 | assert(b_impl); 129 | struct ast_expr *offset = ast_expr_sum_create( 130 | offset_as_expr(location_offset(impl_loc)), 131 | object_lower(spec_obj) /* XXX: assuming lower is offset */ 132 | ); 133 | struct object_res *res = block_observe(b_impl, offset, c->impl, false); 134 | if (object_res_iserror(res)) { 135 | struct error *err = object_res_as_error(res); 136 | if (error_to_block_observe_noobj(err)) { 137 | return error_printf("must have object"); 138 | } 139 | return err; 140 | } 141 | struct object *arg_obj = object_res_as_object(res); 142 | if (!object_hasvalue(spec_obj)) { 143 | return NULL; 144 | } 145 | if (!object_hasvalue(arg_obj)) { 146 | return error_printf("must have value"); 147 | } 148 | return constraint_verify( 149 | c, object_as_value(spec_obj), object_as_value(arg_obj) 150 | ); 151 | } 152 | -------------------------------------------------------------------------------- /src/state/include/block.h: -------------------------------------------------------------------------------- 1 | #ifndef BLOCK_H 2 | #define BLOCK_H 3 | 4 | struct block; 5 | 6 | struct block * 7 | block_create(int size); 8 | 9 | struct block * 10 | block_callercreate(int size); 11 | 12 | void 13 | block_destroy(struct block *); 14 | 15 | char * 16 | block_str(struct block *); 17 | 18 | /* block_size_le: return whether b1's size ≤ b2's size */ 19 | int 20 | block_size_le(struct block *b1, struct block *b2); 21 | 22 | struct error; 23 | struct value; 24 | struct ast_expr; 25 | 26 | struct stack; 27 | struct heap; 28 | struct object; 29 | 30 | void 31 | block_install(struct block *, struct object *); 32 | 33 | struct state; 34 | struct object_res; 35 | 36 | struct object_res * 37 | block_observe(struct block *, struct ast_expr *offset, struct state *, 38 | bool constructive); 39 | 40 | struct location; 41 | 42 | struct circuitbreaker; 43 | 44 | bool 45 | block_references(struct block *, struct location *, struct state *, 46 | struct circuitbreaker *); 47 | 48 | bool 49 | block_iscaller(struct block *); 50 | 51 | struct state; 52 | 53 | void 54 | block_undeclare(struct block *, struct state *); 55 | 56 | struct permutation; 57 | 58 | struct block * 59 | block_permuteheaplocs(struct block *, struct permutation *); 60 | 61 | struct constraint; 62 | 63 | struct error * 64 | block_constraintverify(struct block *spec, struct location *impl, 65 | struct constraint *); 66 | 67 | struct block_arr; 68 | 69 | struct block_arr * 70 | block_arr_create(void); 71 | 72 | void 73 | block_arr_destroy(struct block_arr *); 74 | 75 | struct block_arr * 76 | block_arr_copy(struct block_arr *); 77 | 78 | struct block ** 79 | block_arr_blocks(struct block_arr *); 80 | 81 | int 82 | block_arr_nblocks(struct block_arr *); 83 | 84 | /* block_arr_append: Append struct block to array and return index (address). */ 85 | int 86 | block_arr_append(struct block_arr *, struct block *); 87 | 88 | void 89 | block_arr_delete(struct block_arr *, int address); 90 | 91 | DECLARE_RESULT_TYPE(struct block *, block, block_res) 92 | 93 | struct permutation; 94 | 95 | struct permutation * 96 | permutation_create(struct int_arr *); 97 | 98 | struct permutation * 99 | permutation_inverse_create(struct int_arr *); 100 | 101 | struct permutation * 102 | permutation_copy(struct permutation *); 103 | 104 | void 105 | permutation_destroy(struct permutation *); 106 | 107 | char * 108 | permutation_str(struct permutation *); 109 | 110 | int 111 | permutation_apply(struct permutation *, int); 112 | 113 | int 114 | permutation_applyinverse(struct permutation *, int); 115 | 116 | #endif 117 | -------------------------------------------------------------------------------- /src/state/include/clump.h: -------------------------------------------------------------------------------- 1 | #ifndef CLUMP_H 2 | #define CLUMP_H 3 | 4 | #include "block.h" 5 | 6 | struct clump; 7 | 8 | struct clump * 9 | clump_create(void); 10 | 11 | void 12 | clump_destroy(struct clump *); 13 | 14 | char * 15 | clump_str(struct clump *, char * indent); 16 | 17 | struct clump * 18 | clump_copy(struct clump *); 19 | 20 | int 21 | clump_newblock(struct clump *, int size); 22 | 23 | struct block; 24 | 25 | struct block * 26 | clump_getblock(struct clump *c, int address); 27 | 28 | bool 29 | clump_callerreferences(struct clump *, struct location *, struct state *); 30 | 31 | void 32 | clump_undeclare(struct clump *c, struct state *s); 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /src/state/include/constraint.h: -------------------------------------------------------------------------------- 1 | #ifndef XR0_STATE_CONSTRAINT 2 | #define XR0_STATE_CONSTRAINT 3 | 4 | struct constraint; 5 | 6 | struct constraint * 7 | constraint_create(struct state *spec, struct state *impl, struct ast_type *); 8 | 9 | void 10 | constraint_destroy(struct constraint *); 11 | 12 | struct error; 13 | 14 | struct error * 15 | constraint_verify(struct constraint *, struct value *spec_v, 16 | struct value *impl_v); 17 | 18 | struct error * 19 | constraint_verifyobject(struct constraint *c, struct object *spec_obj, 20 | struct location *impl_loc); 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /src/state/include/heap.h: -------------------------------------------------------------------------------- 1 | #ifndef HEAP_H 2 | #define HEAP_H 3 | 4 | #include "block.h" 5 | 6 | struct heap; 7 | 8 | struct heap * 9 | heap_create(void); 10 | 11 | void 12 | heap_destroy(struct heap *); 13 | 14 | struct heap * 15 | heap_copy(struct heap *); 16 | 17 | char * 18 | heap_str(struct heap *, char *indent); 19 | 20 | struct permutation; 21 | 22 | struct permutation * 23 | heap_transposezero(struct heap *, int block); 24 | 25 | struct heap * 26 | heap_permute(struct heap *, struct permutation *p); 27 | 28 | struct location_arr; 29 | 30 | struct ast_expr; 31 | 32 | struct block_arr * 33 | heap_blocks(struct heap *); 34 | 35 | struct location * 36 | heap_newblock(struct heap *, int size); 37 | 38 | struct location * 39 | heap_newcallerblock(struct heap *, int size); 40 | 41 | struct block; 42 | 43 | struct block * 44 | heap_getblock(struct heap *h, int block); 45 | 46 | bool 47 | heap_referenced(struct heap *h, struct state *); 48 | 49 | bool 50 | heap_blockisfreed(struct heap *h, int block); 51 | 52 | struct error * 53 | heap_deallocblock(struct heap *h, int block); 54 | 55 | void 56 | heap_undeclare(struct heap *, struct state *); 57 | 58 | void 59 | heap_fillorder(struct heap *, struct int_arr *); 60 | 61 | #endif 62 | -------------------------------------------------------------------------------- /src/state/include/intern.h: -------------------------------------------------------------------------------- 1 | #ifndef XR0_STATE_INTERN_H 2 | #define XR0_STATE_INTERN_H 3 | 4 | struct location; 5 | struct object; 6 | 7 | struct object_res * 8 | state_get(struct state *state, struct location *loc, bool constructive); 9 | 10 | struct block * 11 | state_getblock(struct state *state, struct location *loc); 12 | 13 | bool 14 | state_references(struct state *s, struct location *loc); 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /src/state/include/location.h: -------------------------------------------------------------------------------- 1 | #ifndef LOCATION_H 2 | #define LOCATION_H 3 | 4 | #include 5 | 6 | struct ast_expr; 7 | 8 | enum location_type { 9 | LOCATION_STATIC, 10 | LOCATION_VCONST, 11 | LOCATION_DEREFERENCABLE, 12 | LOCATION_AUTOMATIC, 13 | LOCATION_DYNAMIC, 14 | }; 15 | 16 | struct offset; 17 | struct location; 18 | 19 | struct location * 20 | location_create_static(int block, struct offset *offset); 21 | 22 | struct location * 23 | location_create_rconst(int block, struct offset *offset); 24 | 25 | struct location * 26 | location_create_dereferencable(int block, struct offset *offset); 27 | 28 | struct location * 29 | location_create_dynamic(int block, struct offset *offset); 30 | 31 | struct location * 32 | location_create_automatic(int frame, int block, struct offset *offset); 33 | 34 | void 35 | location_setframe(struct location *loc, int frame); 36 | 37 | int 38 | location_getframe(struct location *loc); 39 | 40 | struct location * 41 | location_copy(struct location *loc); 42 | 43 | void 44 | location_destroy(struct location *); 45 | 46 | char * 47 | location_str(struct location *); 48 | 49 | bool 50 | location_isauto(struct location *); 51 | 52 | struct static_memory; 53 | 54 | bool 55 | location_tostatic(struct location *, struct static_memory *); 56 | 57 | struct heap; 58 | 59 | bool 60 | location_toheap(struct location *, struct heap *); 61 | 62 | struct stack; 63 | 64 | bool 65 | location_tostack(struct location *, struct stack *); 66 | 67 | struct clump; 68 | 69 | bool 70 | location_toclump(struct location *, struct clump *); 71 | 72 | bool 73 | location_referencesheap(struct location *, struct state *, struct circuitbreaker *); 74 | 75 | enum location_type 76 | location_type(struct location *loc); 77 | 78 | struct offset * 79 | location_offset(struct location *loc); 80 | 81 | void 82 | location_setoffset(struct location *loc, struct offset *offset); 83 | 84 | struct heap; 85 | 86 | struct state; 87 | 88 | bool 89 | location_equal(struct location *loc1, struct location *loc2); 90 | 91 | bool 92 | location_referencescaller(struct location *l1, struct location *l2, struct state *s, 93 | struct circuitbreaker *cb); 94 | 95 | bool 96 | location_references(struct location *loc1, struct location *loc2, struct state *, 97 | struct circuitbreaker *cb); 98 | 99 | struct permutation; 100 | 101 | struct permutation * 102 | location_heaptransposezero(struct location *, struct heap *); 103 | 104 | struct static_memory; 105 | 106 | struct rconst; 107 | 108 | struct clump; 109 | 110 | struct stack; 111 | 112 | struct object; 113 | 114 | struct block; 115 | 116 | struct block_res * 117 | location_getblock(struct location *, struct static_memory *, struct rconst *, struct stack *, 118 | struct heap *, struct clump *); 119 | 120 | struct block * 121 | location_getstackblock(struct location *loc, struct stack *s); 122 | 123 | struct error * 124 | location_dealloc(struct location *, struct heap *); 125 | 126 | struct location_arr; 127 | 128 | struct location_arr * 129 | location_arr_create(void); 130 | 131 | void 132 | location_arr_destroy(struct location_arr *); 133 | 134 | struct location ** 135 | location_arr_loc(struct location_arr *); 136 | 137 | int 138 | location_arr_n(struct location_arr *); 139 | 140 | void 141 | location_arr_append(struct location_arr *, struct location *); 142 | 143 | 144 | struct offset; 145 | struct ast_type; 146 | 147 | struct offset * 148 | offset_create(struct ast_expr *o); 149 | 150 | struct offset * 151 | offset_create_member(struct offset *o, char *member, struct ast_type *membertype); 152 | 153 | struct offset * 154 | offset_copy(struct offset *); 155 | 156 | void 157 | offset_destroy(struct offset *); 158 | 159 | char * 160 | offset_str(struct offset *); 161 | 162 | struct ast_expr * 163 | offset_as_expr(struct offset *); 164 | 165 | struct ast_expr * 166 | offset_offset(struct offset *); 167 | 168 | char * 169 | offset_member(struct offset *); 170 | 171 | struct ast_type * 172 | offset_membertype(struct offset *); 173 | 174 | #endif 175 | -------------------------------------------------------------------------------- /src/state/include/program.h: -------------------------------------------------------------------------------- 1 | #ifndef PROGRAM_H 2 | #define PROGRAM_H 3 | 4 | struct program; 5 | 6 | struct program * 7 | program_same_create(struct ast_block *, struct program *origin); 8 | 9 | struct program * 10 | program_findsetup_create(struct ast_block *); 11 | 12 | struct program * 13 | program_setup_create(struct ast_block *); 14 | 15 | struct program * 16 | program_abstract_create(struct ast_block *); 17 | 18 | struct program * 19 | program_actual_create(struct ast_block *); 20 | 21 | struct program * 22 | program_verify_create(struct ast_block *); 23 | 24 | struct program * 25 | program_copy(struct program *); 26 | 27 | void 28 | program_destroy(struct program *); 29 | 30 | char * 31 | program_str(struct program *); 32 | 33 | int 34 | program_index(struct program *); 35 | 36 | int 37 | program_modecanverify(struct program *); 38 | 39 | int 40 | program_modecanrunxr0cmd(struct program *); 41 | 42 | void 43 | program_storeloc(struct program *); 44 | 45 | char * 46 | program_render(struct program *); 47 | 48 | void 49 | program_setatend(struct program *); 50 | 51 | bool 52 | program_atend(struct program *); 53 | 54 | struct ast_expr * 55 | program_prevcall(struct program *); 56 | 57 | struct error * 58 | program_step(struct program *, struct state *); 59 | 60 | struct error * 61 | program_next(struct program *, struct state *); 62 | 63 | char * 64 | program_loc(struct program *); 65 | 66 | struct lexememarker * 67 | program_lexememarker(struct program *); 68 | 69 | #endif 70 | -------------------------------------------------------------------------------- /src/state/include/stack.h: -------------------------------------------------------------------------------- 1 | #ifndef STACK_H 2 | #define STACK_H 3 | 4 | #include 5 | #include "block.h" 6 | 7 | struct stack; 8 | 9 | struct frame; 10 | 11 | struct stack * 12 | stack_create(struct frame *, struct stack *prev); 13 | 14 | struct stack * 15 | stack_getframe(struct stack *, int frame); 16 | 17 | char * 18 | stack_programtext(struct stack *); 19 | 20 | int 21 | stack_programindex(struct stack *); 22 | 23 | void 24 | stack_break(struct stack *); 25 | 26 | void 27 | stack_return(struct stack *); 28 | 29 | struct ast_type * 30 | stack_returntype(struct stack *); 31 | 32 | struct ast_expr * 33 | stack_framecall(struct stack *); 34 | 35 | struct externals; 36 | 37 | char * 38 | stack_argmodulator(struct stack *, struct state *); 39 | 40 | void 41 | stack_destroy(struct stack *); 42 | 43 | struct stack * 44 | stack_copy(struct stack *); 45 | 46 | struct stack * 47 | stack_copywithname(struct stack *, char *new_name); 48 | 49 | char * 50 | stack_funcname(struct stack *); 51 | 52 | char * 53 | stack_str(struct stack *, struct state *); 54 | 55 | bool 56 | stack_islinear(struct stack *); 57 | 58 | int 59 | stack_modecanverify(struct stack *); 60 | 61 | int 62 | stack_modecanrunxr0cmd(struct stack *); 63 | 64 | struct lexememarker * 65 | stack_lexememarker(struct stack *); 66 | 67 | int 68 | stack_atend(struct stack *); 69 | 70 | int 71 | stack_atsetupend(struct stack *); 72 | 73 | int 74 | stack_atinvariantend(struct stack *); 75 | 76 | int 77 | stack_atloopend(struct stack *); 78 | 79 | int 80 | stack_id(struct stack *); 81 | 82 | struct error * 83 | stack_step(struct stack *, struct state *); 84 | 85 | struct error * 86 | stack_next(struct stack *, struct state *); 87 | 88 | void 89 | stack_nextstmt(struct stack *s, struct state *state); 90 | 91 | struct stack * 92 | stack_prev(struct stack *); 93 | 94 | void 95 | stack_popprep(struct stack *, struct state *); 96 | 97 | void 98 | stack_storeloc(struct stack *); 99 | 100 | void 101 | stack_declare(struct stack *, struct ast_variable *var, bool isparam); 102 | 103 | void 104 | stack_undeclare(struct stack *stack, struct state *state); 105 | 106 | bool 107 | stack_isnested(struct stack *); 108 | 109 | int 110 | stack_insetup(struct stack *); 111 | 112 | int 113 | stack_ininvariant(struct stack *); 114 | 115 | int 116 | stack_inloop(struct stack *); 117 | 118 | int 119 | stack_isloopbase(struct stack *); 120 | 121 | struct error * 122 | stack_trace(struct stack *, struct error *); 123 | 124 | struct map * 125 | stack_getvarmap(struct stack *); 126 | 127 | struct variable * 128 | stack_getvariable(struct stack *s, char *id); 129 | 130 | struct error * 131 | stack_constraintverify_all(struct stack *spec_stack, struct state *spec, 132 | struct state *impl); 133 | 134 | struct error * 135 | stack_verifyinvariant(struct stack *s, struct state *impl); 136 | 137 | struct ast_expr; 138 | 139 | struct block * 140 | stack_getblock(struct stack *, int address); 141 | 142 | struct frame * 143 | frame_invariant_create(struct ast_block *, struct stack *); 144 | 145 | struct frame * 146 | frame_loop_create(struct ast_block *, struct stack *, struct state *inv_state); 147 | 148 | /* variable */ 149 | 150 | struct ast_type; 151 | 152 | struct variable; 153 | 154 | struct stack; 155 | 156 | struct variable * 157 | variable_create(struct ast_type *type, struct stack *, bool isparam); 158 | 159 | void 160 | variable_destroy(struct variable *); 161 | 162 | struct variable * 163 | variable_copy(struct variable *); 164 | 165 | struct location * 166 | variable_location(struct variable *); 167 | 168 | struct ast_type * 169 | variable_type(struct variable *); 170 | 171 | bool 172 | variable_references(struct variable *v, struct location *loc, struct state *s); 173 | 174 | bool 175 | variable_isparam(struct variable *); 176 | 177 | #endif 178 | -------------------------------------------------------------------------------- /src/state/include/static.h: -------------------------------------------------------------------------------- 1 | #ifndef STATIC_H 2 | #define STATIC_H 3 | 4 | #include "block.h" 5 | 6 | struct static_memory; 7 | 8 | struct static_memory * 9 | static_memory_create(void); 10 | 11 | void 12 | static_memory_destroy(struct static_memory *); 13 | 14 | char * 15 | static_memory_str(struct static_memory *, char * indent); 16 | 17 | struct static_memory * 18 | static_memory_copy(struct static_memory *); 19 | 20 | struct value; 21 | 22 | int 23 | static_memory_newblock(struct static_memory *); 24 | 25 | struct block; 26 | 27 | struct block * 28 | static_memory_getblock(struct static_memory *, int address); 29 | 30 | void 31 | static_memory_stringpool(struct static_memory *sm, char *lit, struct location *); 32 | 33 | struct location * 34 | static_memory_checkpool(struct static_memory *, char *); 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /src/state/static.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "ast.h" 7 | #include "location.h" 8 | #include "block.h" 9 | #include "value.h" 10 | #include "util.h" 11 | 12 | struct static_memory { 13 | struct block_arr *blocks; 14 | struct map *pool; 15 | }; 16 | 17 | struct static_memory * 18 | static_memory_create(void) 19 | { 20 | struct static_memory *sm = malloc(sizeof(struct static_memory)); 21 | assert(sm); 22 | sm->blocks = block_arr_create(); 23 | sm->pool = map_create(); 24 | return sm; 25 | } 26 | 27 | void 28 | static_memory_destroy(struct static_memory *sm) 29 | { 30 | block_arr_destroy(sm->blocks); 31 | } 32 | 33 | char * 34 | static_memory_str(struct static_memory *sm, char *indent) 35 | { 36 | struct strbuilder *b = strbuilder_create(); 37 | int n = block_arr_nblocks(sm->blocks); 38 | struct block **arr = block_arr_blocks(sm->blocks); 39 | for (int i = 0; i < n; i++) { 40 | char *block = block_str(arr[i]); 41 | strbuilder_printf(b, "%s%d: %s\n", indent, i, block); 42 | free(block); 43 | } 44 | return strbuilder_build(b); 45 | } 46 | 47 | static struct map * 48 | pool_copy(struct map *); 49 | 50 | struct static_memory * 51 | static_memory_copy(struct static_memory *sm) 52 | { 53 | struct static_memory *copy = malloc(sizeof(struct static_memory)); 54 | copy->blocks = block_arr_copy(sm->blocks); 55 | copy->pool = pool_copy(sm->pool); 56 | return copy; 57 | } 58 | 59 | static struct map * 60 | pool_copy(struct map *p) 61 | { 62 | struct map *pcopy = map_create(); 63 | for (int i = 0; i < p->n; i++) { 64 | struct entry e = p->entry[i]; 65 | map_set( 66 | pcopy, 67 | dynamic_str(e.key), 68 | location_copy((struct location *) e.value) 69 | ); 70 | } 71 | return pcopy; 72 | } 73 | 74 | int 75 | static_memory_newblock(struct static_memory *sm) 76 | { 77 | int address = block_arr_append(sm->blocks, block_create(1)); 78 | 79 | int n = block_arr_nblocks(sm->blocks); 80 | assert(n > 0); 81 | return address; 82 | } 83 | 84 | struct block * 85 | static_memory_getblock(struct static_memory *sm, int address) 86 | { 87 | if (address >= block_arr_nblocks(sm->blocks)) { 88 | return NULL; 89 | } 90 | return block_arr_blocks(sm->blocks)[address]; 91 | } 92 | 93 | /* string pooling to write one string literal to static_memory and all subsequent 94 | * literals reference it is used to avoid infinite loops in splitting logic with 95 | * different literals per selection condition */ 96 | void 97 | static_memory_stringpool(struct static_memory *sm, char *lit, struct location *loc) 98 | { 99 | map_set( 100 | sm->pool, 101 | dynamic_str(lit), 102 | location_copy(loc) 103 | ); 104 | } 105 | 106 | struct location * 107 | static_memory_checkpool(struct static_memory *sm, char *lit) 108 | { 109 | return (struct location *) map_get(sm->pool, lit); 110 | } 111 | -------------------------------------------------------------------------------- /src/value/include/_limits.h: -------------------------------------------------------------------------------- 1 | #ifndef XR0_VALUE_LIMITS_H 2 | #define XR0_VALUE_LIMITS_H 3 | 4 | #define C89_INT_MIN (-32767) 5 | #define C89_INT_MAX 32767 6 | 7 | #endif 8 | -------------------------------------------------------------------------------- /src/value/include/intern.h: -------------------------------------------------------------------------------- 1 | #ifndef XR0_VALUE_INTERN_H 2 | #define XR0_VALUE_INTERN_H 3 | 4 | struct number * 5 | value_as_number(struct value *); 6 | 7 | #endif 8 | -------------------------------------------------------------------------------- /src/value/include/number.h: -------------------------------------------------------------------------------- 1 | #ifndef XR0_VALUE_NUMBER_H 2 | #define XR0_VALUE_NUMBER_H 3 | 4 | struct number; 5 | 6 | struct number * 7 | number_const_create(long); 8 | 9 | struct ast_expr; 10 | 11 | struct number * 12 | number_expr_create(struct ast_expr *); 13 | 14 | struct range; 15 | 16 | struct number * 17 | number_range_create(struct range *); 18 | 19 | struct number * 20 | number_ne_create(long not_val); 21 | 22 | struct number * 23 | number_copy(struct number *); 24 | 25 | void 26 | number_destroy(struct number *); 27 | 28 | char * 29 | number_str(struct number *); 30 | 31 | char * 32 | number_short_str(struct number *); 33 | 34 | struct range; 35 | 36 | int 37 | number_isexpr(struct number *); 38 | 39 | struct ast_expr * 40 | number_as_expr(struct number *); 41 | 42 | struct ast_expr * 43 | number_to_expr(struct number *); 44 | 45 | long 46 | number_as_const(struct number *); 47 | 48 | int 49 | number_isconst(struct number *); 50 | 51 | struct range * 52 | number_as_range(struct number *); 53 | 54 | int 55 | number_lt(struct number *lhs, struct number *rhs, struct state *); 56 | 57 | int 58 | number_le(struct number *lhs, struct number *rhs, struct state *); 59 | 60 | int 61 | number_eq(struct number *, struct number *, struct state *); 62 | 63 | int 64 | number_ge(struct number *lhs, struct number *rhs, struct state *); 65 | 66 | int 67 | number_issinglerange(struct number *, struct state *); 68 | 69 | int 70 | numbers_aresinglerange(struct number *lw, struct number *up); 71 | 72 | struct number * 73 | number_tosinglerange(struct number *, struct state *); 74 | 75 | struct state; 76 | 77 | struct number * 78 | number_lw(struct number *, struct state *); 79 | 80 | struct number * 81 | number_up(struct number *, struct state *); 82 | 83 | struct map; 84 | 85 | void 86 | number_splitto(struct number *n, struct number *range, struct map *splits, 87 | struct state *s); 88 | 89 | int 90 | number_assume(struct number *n, struct number *split, struct state *); 91 | 92 | struct error * 93 | number_disentangle(struct number *, struct number *, struct state *); 94 | 95 | #endif 96 | -------------------------------------------------------------------------------- /src/value/include/range.h: -------------------------------------------------------------------------------- 1 | #ifndef XR0_VALUE_RANGE_H 2 | #define XR0_VALUE_RANGE_H 3 | 4 | struct range; 5 | 6 | struct range * 7 | range_create(long lw, long up); 8 | 9 | struct range * 10 | range_entire_create(void); 11 | 12 | struct range * 13 | range_fromexpr(struct ast_expr *, struct state *); 14 | 15 | struct range * 16 | range_copy(struct range *); 17 | 18 | void 19 | range_destroy(struct range *); 20 | 21 | char * 22 | range_str(struct range *r); 23 | 24 | char * 25 | range_short_str(struct range *r); 26 | 27 | long 28 | range_lower(struct range *); 29 | 30 | long 31 | range_upper(struct range *); 32 | 33 | long 34 | range_as_const(struct range *); 35 | 36 | struct state; 37 | 38 | int 39 | range_contains_range(struct range *r, struct range *r2); 40 | 41 | int 42 | range_issingle(struct range *r); 43 | 44 | struct range_arr; 45 | 46 | struct range_arr * 47 | range_arr_create(void); 48 | 49 | struct range_arr * 50 | range_arr_copy(struct range_arr *); 51 | 52 | void 53 | range_arr_destroy(struct range_arr *arr); 54 | 55 | int 56 | range_arr_n(struct range_arr *); 57 | 58 | struct range ** 59 | range_arr_range(struct range_arr *); 60 | 61 | int 62 | range_arr_append(struct range_arr *, struct range *); 63 | 64 | int 65 | range_arr_containsrangearr(struct range_arr *arr, struct range_arr *range); 66 | 67 | struct range_arr * 68 | range_arr_ne_create(long); 69 | 70 | #endif 71 | -------------------------------------------------------------------------------- /src/verifier/arr.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "ast.h" 5 | #include "verifier.h" 6 | 7 | #include "arr.h" 8 | 9 | struct verifier_arr { 10 | int n; 11 | struct verifier **verifiers; 12 | }; 13 | 14 | struct verifier_arr * 15 | verifier_arr_create(void) 16 | { 17 | struct verifier_arr *arr = calloc(1, sizeof(struct verifier_arr)); 18 | assert(arr); 19 | return arr; 20 | } 21 | 22 | void 23 | verifier_arr_destroy(struct verifier_arr *arr) 24 | { 25 | for (int i = 0; i < arr->n; i++) { 26 | verifier_destroy(arr->verifiers[i]); 27 | } 28 | free(arr->verifiers); 29 | free(arr); 30 | } 31 | 32 | int 33 | verifier_arr_n(struct verifier_arr *arr) 34 | { 35 | return arr->n; 36 | } 37 | 38 | struct verifier ** 39 | verifier_arr_paths(struct verifier_arr *arr) 40 | { 41 | return arr->verifiers; 42 | } 43 | 44 | int 45 | verifier_arr_append(struct verifier_arr *arr, struct verifier *p) 46 | { 47 | arr->verifiers = realloc(arr->verifiers, sizeof(struct verifier_arr) * ++arr->n); 48 | assert(arr->verifiers); 49 | int loc = arr->n-1; 50 | arr->verifiers[loc] = p; 51 | return loc; 52 | } 53 | -------------------------------------------------------------------------------- /src/verifier/include/arr.h: -------------------------------------------------------------------------------- 1 | #ifndef XR0_VERIFIER_ARR 2 | #define XR0_VERIFIER_ARR 3 | 4 | struct verifier; 5 | 6 | struct verifier_arr; 7 | 8 | struct verifier_arr * 9 | verifier_arr_create(void); 10 | 11 | void 12 | verifier_arr_destroy(struct verifier_arr *); 13 | 14 | int 15 | verifier_arr_n(struct verifier_arr *); 16 | 17 | struct verifier ** 18 | verifier_arr_paths(struct verifier_arr *); 19 | 20 | int 21 | verifier_arr_append(struct verifier_arr *, struct verifier *); 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /src/verifier/include/instruct.h: -------------------------------------------------------------------------------- 1 | #ifndef XR0_VERIFIER_INSTRUCT 2 | #define XR0_VERIFIER_INSTRUCT 3 | 4 | struct verifier; 5 | struct verifierinstruct; 6 | 7 | void 8 | verifierinstruct_do(struct verifierinstruct *, struct verifier *); 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /src/verifier/include/intern.h: -------------------------------------------------------------------------------- 1 | #ifndef XR0_VERIFIER_INTERN 2 | #define XR0_VERIFIER_INTERN 3 | 4 | void 5 | verifier_split(struct verifier *, struct splitinstruct *); 6 | 7 | #endif 8 | -------------------------------------------------------------------------------- /src/verifier/include/mux.h: -------------------------------------------------------------------------------- 1 | #ifndef XR0_VERIFIER_MUX 2 | #define XR0_VERIFIER_MUX 3 | 4 | struct verifier; 5 | struct verifier_arr; 6 | 7 | /* mux: multiplexer for splittings of verifiers */ 8 | struct mux; 9 | 10 | struct mux * 11 | mux_create(struct verifier_arr *); 12 | 13 | void 14 | mux_destroy(struct mux *); 15 | 16 | int 17 | mux_atend(struct mux *); 18 | 19 | struct verifier * 20 | mux_activeverifier(struct mux *); 21 | 22 | void 23 | mux_next(struct mux *); 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /src/verifier/include/path.h: -------------------------------------------------------------------------------- 1 | #ifndef XR0_VERIFIER_PATH 2 | #define XR0_VERIFIER_PATH 3 | 4 | /* must be included after verifier.h */ 5 | 6 | struct rconst; 7 | struct ast_function; 8 | struct externals; 9 | 10 | struct path * 11 | path_create(struct state *abstract, struct state *actual); 12 | 13 | void 14 | path_destroy(struct path *); 15 | 16 | char * 17 | path_str(struct path *); 18 | 19 | int 20 | path_atend(struct path *); 21 | 22 | struct error * 23 | path_progress(struct path *, progressor *); 24 | 25 | struct path * 26 | path_split(struct path *, struct rconst *, char *fname); 27 | 28 | struct error * 29 | path_verify(struct path *, struct ast_expr *); 30 | 31 | struct lexememarker * 32 | path_lexememarker(struct path *); 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /src/verifier/include/segment.h: -------------------------------------------------------------------------------- 1 | #ifndef XR0_VERFIIER_SEGMENT 2 | #define XR0_VERFIIER_SEGMENT 3 | 4 | /* must be included after verifier.h */ 5 | 6 | struct state; 7 | struct rconst; 8 | struct ast_expr; 9 | struct lexememarker; 10 | 11 | struct segment; 12 | 13 | struct segment * 14 | segment_create_withstate(struct state *); 15 | 16 | struct segment * 17 | segment_split(struct segment *old, struct rconst *rconst, char *fname); 18 | 19 | void 20 | segment_destroy(struct segment *); 21 | 22 | char * 23 | segment_str(struct segment *, char *phase); 24 | 25 | int 26 | segment_atend(struct segment *); 27 | 28 | struct error * 29 | segment_progress(struct segment *, progressor *prog); 30 | 31 | struct error * 32 | segment_verify(struct segment *, struct ast_expr *); 33 | 34 | struct lexememarker * 35 | segment_lexememarker(struct segment *); 36 | 37 | struct error * 38 | segment_audit(struct segment *abstract, struct segment *actual); 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /src/verifier/instruct.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "verifier.h" 5 | 6 | #include "intern.h" 7 | #include "instruct.h" 8 | 9 | struct verifierinstruct { 10 | enum verifierinstruct_type { 11 | PATHINSTRUCT_SPLIT, 12 | } type; 13 | union { 14 | struct splitinstruct *split; 15 | }; 16 | }; 17 | 18 | struct verifierinstruct * 19 | verifierinstruct_split(struct splitinstruct *s) 20 | { 21 | struct verifierinstruct *inst = malloc(sizeof(struct verifierinstruct)); 22 | assert(inst); 23 | inst->type = PATHINSTRUCT_SPLIT; 24 | inst->split = s; 25 | return inst; 26 | } 27 | 28 | void 29 | verifierinstruct_do(struct verifierinstruct *inst, struct verifier *p) 30 | { 31 | switch (inst->type) { 32 | case PATHINSTRUCT_SPLIT: 33 | verifier_split(p, inst->split); 34 | break; 35 | default: 36 | assert(false); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/verifier/mux.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "verifier.h" 5 | 6 | #include "arr.h" 7 | #include "mux.h" 8 | 9 | struct mux { 10 | int index; 11 | struct verifier_arr *verifiers; 12 | }; 13 | 14 | struct mux * 15 | mux_create(struct verifier_arr *verifiers) 16 | { 17 | struct mux *mux = calloc(1, sizeof(struct mux)); 18 | assert(mux); 19 | mux->verifiers = verifiers; 20 | return mux; 21 | } 22 | 23 | void 24 | mux_destroy(struct mux *mux) 25 | { 26 | verifier_arr_destroy(mux->verifiers); 27 | free(mux); 28 | } 29 | 30 | int 31 | mux_atend(struct mux *mux) 32 | { 33 | int n = verifier_arr_n(mux->verifiers); 34 | assert(n); 35 | 36 | return mux->index == n-1 37 | && verifier_atend(mux_activeverifier(mux)); 38 | } 39 | 40 | struct verifier * 41 | mux_activeverifier(struct mux *mux) 42 | { 43 | assert(mux->index < verifier_arr_n(mux->verifiers)); 44 | 45 | return verifier_arr_paths(mux->verifiers)[mux->index]; 46 | } 47 | 48 | void 49 | mux_next(struct mux *mux) 50 | { 51 | assert(!mux_atend(mux)); 52 | mux->index++; 53 | } 54 | -------------------------------------------------------------------------------- /src/verifier/path.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "ast.h" 6 | #include "lex.h" 7 | #include "state.h" 8 | #include "util.h" 9 | #include "verifier.h" 10 | 11 | #include "path.h" 12 | #include "segment.h" 13 | 14 | struct path { 15 | enum path_phase { 16 | PATH_PHASE_ABSTRACT, 17 | PATH_PHASE_ACTUAL, 18 | PATH_PHASE_AUDIT, 19 | PATH_PHASE_ATEND, 20 | } phase; 21 | struct segment *abstract, *actual; 22 | }; 23 | 24 | struct path * 25 | path_create(struct state *abstract, struct state *actual) 26 | { 27 | struct path *p = malloc(sizeof(struct path)); 28 | assert(p); 29 | p->phase = PATH_PHASE_ABSTRACT; 30 | p->abstract = segment_create_withstate(abstract); 31 | p->actual = segment_create_withstate(actual); 32 | return p; 33 | } 34 | 35 | struct path * 36 | path_split(struct path *old, struct rconst *rconst, char *fname) 37 | { 38 | struct path *p = malloc(sizeof(struct path)); 39 | assert(p); 40 | p->phase = old->phase; 41 | switch (old->phase) { 42 | case PATH_PHASE_ABSTRACT: 43 | case PATH_PHASE_ACTUAL: 44 | p->abstract = segment_split(old->abstract, rconst, fname); 45 | p->actual = segment_split(old->actual, rconst, fname); 46 | break; 47 | default: 48 | assert(false); 49 | } 50 | return p; 51 | } 52 | 53 | void 54 | path_destroy(struct path *p) 55 | { 56 | segment_destroy(p->abstract); 57 | segment_destroy(p->actual); 58 | free(p); 59 | } 60 | 61 | char * 62 | path_str(struct path *p) 63 | { 64 | switch (p->phase) { 65 | case PATH_PHASE_ABSTRACT: 66 | return segment_str(p->abstract, "ABSTRACT"); 67 | case PATH_PHASE_ACTUAL: 68 | return segment_str(p->actual, "ACTUAL"); 69 | case PATH_PHASE_AUDIT: 70 | return dynamic_str("phase:\tAUDIT\n"); 71 | break; 72 | case PATH_PHASE_ATEND: 73 | return dynamic_str("phase:\tEND\n"); 74 | default: 75 | assert(false); 76 | } 77 | } 78 | 79 | int 80 | path_atend(struct path *p) 81 | { 82 | return p->phase == PATH_PHASE_ATEND; 83 | } 84 | 85 | struct error * 86 | path_progress(struct path *p, progressor *prog) 87 | { 88 | switch (p->phase) { 89 | case PATH_PHASE_ABSTRACT: 90 | if (segment_atend(p->abstract)) { 91 | p->phase = PATH_PHASE_ACTUAL; 92 | return path_progress(p, prog); 93 | } 94 | return segment_progress(p->abstract, prog); 95 | case PATH_PHASE_ACTUAL: 96 | if (segment_atend(p->actual)) { 97 | p->phase = PATH_PHASE_AUDIT; 98 | return path_progress(p, prog); 99 | } 100 | return segment_progress(p->actual, prog); 101 | case PATH_PHASE_AUDIT: 102 | p->phase = PATH_PHASE_ATEND; 103 | return segment_audit(p->abstract, p->actual); 104 | case PATH_PHASE_ATEND: 105 | default: 106 | assert(false); 107 | } 108 | } 109 | 110 | struct error * 111 | path_verify(struct path *p, struct ast_expr *expr) 112 | { 113 | switch (p->phase) { 114 | case PATH_PHASE_ABSTRACT: 115 | return segment_verify(p->abstract, expr); 116 | case PATH_PHASE_ACTUAL: 117 | return segment_verify(p->actual, expr); 118 | case PATH_PHASE_AUDIT: 119 | case PATH_PHASE_ATEND: 120 | return NULL; 121 | default: 122 | assert(false); 123 | } 124 | } 125 | 126 | struct lexememarker * 127 | path_lexememarker(struct path *p) 128 | { 129 | switch (p->phase) { 130 | case PATH_PHASE_ABSTRACT: 131 | return segment_lexememarker(p->abstract); 132 | case PATH_PHASE_ACTUAL: 133 | return segment_lexememarker(p->actual); 134 | case PATH_PHASE_AUDIT: 135 | case PATH_PHASE_ATEND: 136 | return NULL; 137 | default: 138 | assert(false); 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /src/verifier/rconst.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "ast.h" 6 | #include "util.h" 7 | #include "value.h" 8 | 9 | struct rconst { 10 | struct map *varmap; 11 | struct map *keymap; 12 | struct map *persist; 13 | }; 14 | 15 | struct rconst * 16 | rconst_create(void) 17 | { 18 | struct rconst *v = malloc(sizeof(struct rconst)); 19 | v->varmap = map_create(); 20 | v->keymap = map_create(); 21 | v->persist = map_create(); 22 | return v; 23 | } 24 | 25 | void 26 | rconst_destroy(struct rconst *v) 27 | { 28 | struct map *m = v->varmap; 29 | for (int i = 0; i < m->n; i++) { 30 | value_destroy((struct value *) m->entry[i].value); 31 | } 32 | map_destroy(m); 33 | map_destroy(v->keymap); 34 | map_destroy(v->persist); 35 | free(v); 36 | } 37 | 38 | struct rconst * 39 | rconst_copy(struct rconst *old) 40 | { 41 | struct rconst *new = rconst_create(); 42 | struct map *m = old->varmap; 43 | for (int i = 0; i < m->n; i++) { 44 | struct entry e = m->entry[i]; 45 | map_set( 46 | new->varmap, 47 | dynamic_str(e.key), 48 | value_copy((struct value *) e.value) 49 | ); 50 | } 51 | m = old->keymap; 52 | for (int i = 0; i < m->n; i++) { 53 | struct entry e = m->entry[i]; 54 | map_set( 55 | new->keymap, 56 | dynamic_str(e.key), 57 | dynamic_str(e.value) 58 | ); 59 | } 60 | m = old->persist; 61 | for (int i = 0; i < m->n; i++) { 62 | struct entry e = m->entry[i]; 63 | map_set( 64 | new->persist, 65 | dynamic_str(e.key), 66 | e.value 67 | ); 68 | } 69 | 70 | return new; 71 | } 72 | 73 | static char * 74 | rconst_id(struct map *varmap, struct map *persistmap, bool persist); 75 | 76 | char * 77 | rconst_declarenokey(struct rconst *v, struct value *val, bool persist) 78 | { 79 | struct map *m = v->varmap; 80 | char *s = rconst_id(m, v->persist, persist); 81 | map_set(m, dynamic_str(s), val); 82 | map_set(v->persist, dynamic_str(s), (void *) persist); 83 | return s; 84 | } 85 | 86 | static int 87 | count_true(struct map *m); 88 | 89 | static char * 90 | rconst_id(struct map *varmap, struct map *persistmap, bool persist) 91 | { 92 | int npersist = count_true(persistmap), 93 | nnonpersist = varmap->n - npersist; 94 | struct strbuilder *b = strbuilder_create(); 95 | if (persist) { 96 | strbuilder_printf(b, "$%d", (int) npersist); 97 | } else { 98 | strbuilder_printf(b, "#%d", (int) nnonpersist); 99 | } 100 | return strbuilder_build(b); 101 | } 102 | 103 | static int 104 | count_true(struct map *m) 105 | { 106 | int n = 0; 107 | for (int i = 0; i < m->n; i++) { 108 | if (m->entry[i].value) { 109 | n++; 110 | } 111 | } 112 | return n; 113 | } 114 | 115 | char * 116 | rconst_declare(struct rconst *v, struct value *val, char *key, bool persist) 117 | { 118 | char *s = rconst_declarenokey(v, val, persist); 119 | assert(key); 120 | map_set(v->keymap, dynamic_str(s), dynamic_str(key)); 121 | return s; 122 | } 123 | 124 | struct value * 125 | rconst_get(struct rconst *v, char *id) 126 | { 127 | return map_get(v->varmap, id); 128 | } 129 | 130 | char * 131 | rconst_getidbykey(struct rconst *v, char *key) 132 | { 133 | /* XXX */ 134 | struct map *m = v->keymap; 135 | for (int i = 0; i < m->n; i++) { 136 | struct entry e = m->entry[i]; 137 | char *id = e.key, 138 | *varkey = (char *) e.value; 139 | if (strcmp(key, varkey) == 0) { 140 | return id; 141 | } 142 | } 143 | return NULL; 144 | } 145 | 146 | void 147 | rconst_undeclare(struct rconst *v) 148 | { 149 | struct map *varmap = map_create(), 150 | *keymap = map_create(), 151 | *persist = map_create(); 152 | 153 | struct map *m = v->varmap; 154 | for (int i = 0; i < m->n; i++) { 155 | char *key = m->entry[i].key; 156 | if (!map_get(v->persist, key)) { 157 | continue; 158 | } 159 | map_set( 160 | varmap, dynamic_str(key), 161 | value_copy((struct value *) map_get(v->varmap, key)) 162 | ); 163 | char *c = map_get(v->keymap, key); 164 | map_set(keymap, dynamic_str(key), dynamic_str(c)); 165 | map_set(persist, dynamic_str(key), (void *) true); 166 | } 167 | 168 | v->varmap = varmap; 169 | v->keymap = keymap; 170 | v->persist = persist; 171 | } 172 | 173 | char * 174 | rconst_str(struct rconst *v, char *indent) 175 | { 176 | struct strbuilder *b = strbuilder_create(); 177 | struct map *m = v->varmap; 178 | for (int i = 0; i < m->n; i++) { 179 | struct entry e = m->entry[i]; 180 | char *value = value_str((struct value *) e.value); 181 | strbuilder_printf(b, "%s%s: %s", indent, e.key, value); 182 | char *key = map_get(v->keymap, e.key); 183 | if (key) { 184 | strbuilder_printf(b, "\t\"%s\"", key); 185 | } 186 | strbuilder_printf(b, "\n"); 187 | free(value); 188 | } 189 | return strbuilder_build(b); 190 | } 191 | 192 | bool 193 | rconst_eval(struct rconst *v, struct ast_expr *e) 194 | { 195 | return ast_expr_matheval(e); 196 | } 197 | -------------------------------------------------------------------------------- /src/verifier/segment.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "ast.h" 6 | #include "state.h" 7 | #include "util.h" 8 | #include "verifier.h" 9 | 10 | #include "segment.h" 11 | 12 | struct segment { 13 | enum segment_phase { 14 | SEGMENT_PHASE_INIT, 15 | SEGMENT_PHASE_SETUP, 16 | SEGMENT_PHASE_EXEC, 17 | SEGMENT_PHASE_ATEND, 18 | SEGMENT_PHASE_ATLOOPEND, 19 | } phase; 20 | struct state *state; 21 | }; 22 | 23 | static struct segment * 24 | _segment_create(enum segment_phase phase) 25 | { 26 | struct segment *s = malloc(sizeof(struct segment)); 27 | assert(s); 28 | s->phase = phase; 29 | return s; 30 | } 31 | 32 | struct segment * 33 | segment_create_withstate(struct state *state) 34 | { 35 | struct segment *s = _segment_create(SEGMENT_PHASE_INIT); 36 | s->state = state; 37 | return s; 38 | } 39 | 40 | struct segment * 41 | segment_split(struct segment *old, struct rconst *rconst, char *fname) 42 | { 43 | struct segment *new = _segment_create(old->phase); 44 | switch (old->phase) { 45 | case SEGMENT_PHASE_INIT: 46 | assert(old->state); 47 | /* fallthrough */ 48 | case SEGMENT_PHASE_SETUP: 49 | case SEGMENT_PHASE_EXEC: 50 | case SEGMENT_PHASE_ATEND: 51 | new->state = state_split(old->state, rconst, fname); 52 | break; 53 | default: 54 | assert(false); 55 | } 56 | return new; 57 | } 58 | 59 | void 60 | segment_destroy(struct segment *s) 61 | { 62 | /*state_destroy(s->state);*/ 63 | free(s); 64 | } 65 | 66 | static char * 67 | phasename(struct segment *); 68 | 69 | char * 70 | segment_str(struct segment *s, char *pathphase) 71 | { 72 | struct strbuilder *b = strbuilder_create(); 73 | strbuilder_printf(b, "phase:\t%s (%s)\n", pathphase, phasename(s)); 74 | switch (s->phase) { 75 | case SEGMENT_PHASE_INIT: 76 | case SEGMENT_PHASE_ATEND: 77 | case SEGMENT_PHASE_ATLOOPEND: 78 | break; 79 | case SEGMENT_PHASE_SETUP: 80 | case SEGMENT_PHASE_EXEC: 81 | strbuilder_printf(b, "\ntext:\n%s\n", state_programtext(s->state)); 82 | strbuilder_printf(b, "%s\n", state_str(s->state)); 83 | break; 84 | default: 85 | assert(false); 86 | } 87 | return strbuilder_build(b); 88 | } 89 | 90 | static char * 91 | phasename(struct segment *s) 92 | { 93 | switch (s->phase) { 94 | case SEGMENT_PHASE_INIT: 95 | return "INIT"; 96 | case SEGMENT_PHASE_SETUP: 97 | return "SETUP"; 98 | case SEGMENT_PHASE_EXEC: 99 | return "EXEC"; 100 | case SEGMENT_PHASE_ATEND: 101 | return "END"; 102 | case SEGMENT_PHASE_ATLOOPEND: 103 | return "END LOOP"; 104 | default: 105 | assert(false); 106 | } 107 | } 108 | 109 | int 110 | segment_atend(struct segment *s) 111 | { 112 | switch (s->phase) { 113 | case SEGMENT_PHASE_ATEND: 114 | case SEGMENT_PHASE_ATLOOPEND: 115 | return 1; 116 | default: 117 | return 0; 118 | } 119 | } 120 | 121 | 122 | /* segment_progress */ 123 | 124 | static struct error * 125 | setup(struct segment *, progressor *); 126 | 127 | static struct error * 128 | exec(struct segment *, progressor *); 129 | 130 | struct error * 131 | segment_progress(struct segment *s, progressor *prog) 132 | { 133 | switch (s->phase) { 134 | case SEGMENT_PHASE_INIT: 135 | s->phase = SEGMENT_PHASE_SETUP; 136 | return NULL; 137 | case SEGMENT_PHASE_SETUP: 138 | return setup(s, prog); 139 | case SEGMENT_PHASE_EXEC: 140 | return exec(s, prog); 141 | default: 142 | assert(false); 143 | } 144 | } 145 | 146 | static struct error * 147 | progressortrace(struct state *, progressor *); 148 | 149 | static struct error * 150 | setup(struct segment *s, progressor *prog) 151 | { 152 | if (state_atsetupend(s->state)) { 153 | s->phase = SEGMENT_PHASE_EXEC; 154 | return NULL; 155 | } 156 | return progressortrace(s->state, prog); 157 | } 158 | 159 | static struct error * 160 | progressortrace(struct state *s, progressor *prog) 161 | { 162 | struct error *err = prog(s); 163 | if (err) { 164 | return state_stacktrace(s, err); 165 | } 166 | return NULL; 167 | } 168 | 169 | static struct error * 170 | exec(struct segment *s, progressor *prog) 171 | { 172 | if (state_atloopend(s->state)) { 173 | struct error *err = state_verifyinvariant(s->state); 174 | if (err) { 175 | return state_stacktrace(s->state, err); 176 | } 177 | s->phase = SEGMENT_PHASE_ATLOOPEND; 178 | } 179 | if (state_atend(s->state)) { 180 | s->phase = SEGMENT_PHASE_ATEND; 181 | return NULL; 182 | } 183 | return progressortrace(s->state, prog); 184 | } 185 | 186 | struct error * 187 | segment_verify(struct segment *s, struct ast_expr *e) 188 | { 189 | switch (s->phase) { 190 | case SEGMENT_PHASE_EXEC: 191 | return ast_stmt_verify(ast_stmt_create_expr(NULL, e), s->state); 192 | case SEGMENT_PHASE_INIT: 193 | case SEGMENT_PHASE_ATEND: 194 | return NULL; 195 | default: 196 | assert(false); 197 | } 198 | } 199 | 200 | struct lexememarker * 201 | segment_lexememarker(struct segment *s) 202 | { 203 | switch (s->phase) { 204 | case SEGMENT_PHASE_SETUP: 205 | case SEGMENT_PHASE_EXEC: 206 | return state_lexememarker(s->state); 207 | case SEGMENT_PHASE_INIT: 208 | case SEGMENT_PHASE_ATEND: 209 | case SEGMENT_PHASE_ATLOOPEND: 210 | return NULL; 211 | default: 212 | assert(false); 213 | } 214 | } 215 | 216 | struct error * 217 | segment_audit(struct segment *abstract, struct segment *actual) 218 | { 219 | if (actual->phase == SEGMENT_PHASE_ATLOOPEND) { 220 | return NULL; 221 | } 222 | 223 | if (state_hasgarbage(actual->state)) { 224 | v_printf("actual: %s", state_str(actual->state)); 225 | return error_printf( 226 | "%s: garbage on heap", state_funcname(actual->state) 227 | ); 228 | } 229 | struct error *err; 230 | if ((err = state_specverify(actual->state, abstract->state))) { 231 | v_printf("actual:\n%s", state_str(actual->state)); 232 | v_printf("abstract:\n%s", state_str(abstract->state)); 233 | return error_printf( 234 | "%s: %s", 235 | state_funcname(actual->state), 236 | error_str(err) 237 | ); 238 | } 239 | return NULL; 240 | } 241 | -------------------------------------------------------------------------------- /src/verifier/splitinstruct.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "util.h" 5 | #include "state.h" 6 | #include "verifier.h" 7 | 8 | struct splitinstruct { 9 | int n; 10 | struct map **m; 11 | struct state *s; 12 | }; 13 | 14 | struct splitinstruct * 15 | splitinstruct_create(struct state *state) 16 | { 17 | struct splitinstruct *s = malloc(sizeof(struct splitinstruct)); 18 | assert(s); 19 | s->n = 0; 20 | s->m = NULL; 21 | s->s = state; 22 | return s; 23 | } 24 | 25 | void 26 | splitinstruct_append(struct splitinstruct *s, struct map *m) 27 | { 28 | s->m = realloc(s->m, sizeof(struct map *) * ++s->n); 29 | assert(s->m); 30 | s->m[s->n-1] = m; 31 | } 32 | 33 | int 34 | splitinstruct_n(struct splitinstruct *s) 35 | { 36 | return s->n; 37 | } 38 | 39 | struct map ** 40 | splitinstruct_splits(struct splitinstruct *s) 41 | { 42 | return s->m; 43 | } 44 | 45 | 46 | struct state * 47 | splitinstruct_state(struct splitinstruct *s) 48 | { 49 | return s->s; 50 | } 51 | -------------------------------------------------------------------------------- /tests/0db/00-basic/expected/0: -------------------------------------------------------------------------------- 1 | (0db) The Xr0 Static Debugger for C 2 | Copyright (C) 2024 Xr0 3 | License Apache 2.0 4 | 5 | A static debugger is the compile-time analogue of 6 | runtime debuggers like GDB. Runtime debuggers 7 | require you to execute a program in order to 8 | analyse it, but 0db shows line-by-line the state 9 | of a C program on the basis of the semantics of 10 | the language alone. 11 | 12 | This matters because at runtime we interact with a 13 | very tiny subset of a program's possible 14 | behaviours. In the state supplied by 0db you see 15 | at once what applies to all possible executions 16 | of a program. 17 | 18 | For help, type "help". 19 | 20 | 21 | phase: ABSTRACT (INIT) 22 | 23 | (0db) 24 | -------------------------------------------------------------------------------- /tests/0db/00-basic/expected/1: -------------------------------------------------------------------------------- 1 | phase: ABSTRACT (SETUP) 2 | 3 | text: 4 | --> setup: q = .clump(1); 5 | if (x) { 6 | *(q) = 1; 7 | } 8 | 9 | rconst: 10 | $0: ptr:{?} "q" 11 | $1: int:{?} "x" 12 | 13 | stack: 14 | ---------------------------- findsetup 15 | 0: |1| {0:} (int * q, π) 16 | 1: |1| {0:} (int x, π) 17 | ---------------------------- modify0 18 | 19 | 20 | 21 | (0db) 22 | -------------------------------------------------------------------------------- /tests/0db/00-basic/expected/2: -------------------------------------------------------------------------------- 1 | phase: ABSTRACT (SETUP) 2 | 3 | text: 4 | setup: q = .clump(1); 5 | --> if (x) { 6 | *(q) = 1; 7 | } 8 | 9 | rconst: 10 | $0: ptr:{?} "q" 11 | $1: int:{?} "x" 12 | 13 | clump: 14 | 0: |1| 15 | 16 | stack: 17 | ---------------------------- findsetup 18 | 0: |1| {0:} (int * q, π) 19 | 1: |1| {0:} (int x, π) 20 | ---------------------------- modify0 21 | 22 | 23 | 24 | (0db) 25 | -------------------------------------------------------------------------------- /tests/0db/00-basic/expected/3: -------------------------------------------------------------------------------- 1 | phase: ABSTRACT (SETUP) 2 | 3 | text: 4 | setup: q = .clump(1); 5 | --> if (x) { 6 | *(q) = 1; 7 | } 8 | 9 | rconst: 10 | $0: ptr:{?} "q" 11 | $1: int:{?} "x" 12 | 13 | clump: 14 | 0: |1| 15 | 16 | stack: 17 | ---------------------------- findsetup 18 | 0: |1| {0:} (int * q, π) 19 | 1: |1| {0:} (int x, π) 20 | ---------------------------- modify0 21 | 22 | 23 | 24 | (0db) 25 | -------------------------------------------------------------------------------- /tests/0db/00-basic/expected/4: -------------------------------------------------------------------------------- 1 | phase: ABSTRACT (INIT) 2 | 3 | phase: ABSTRACT (INIT) 4 | 5 | phase: ACTUAL (EXEC) 6 | 7 | text: 8 | int p; 9 | --> p = 0; 10 | ~ [ p==0; ] 11 | modify0(&(p), 0); 12 | ~ [ p==0; ] 13 | modify0(&(p), 1); 14 | ~ [ p==1; ] 15 | modify1(&(p), 0); 16 | ~ [ p==1; ] 17 | modify1(&(p), 1); 18 | ~ [ p==2; ] 19 | 20 | rconst: 21 | #0: int:{?} "main:gen:0:{}" 22 | 23 | stack: 24 | 0: |1| {0:<>} (int p) 25 | ---------------------------- main 26 | 27 | 28 | 29 | (0db) 30 | -------------------------------------------------------------------------------- /tests/0db/00-basic/expected/5: -------------------------------------------------------------------------------- 1 | phase: ACTUAL (EXEC) 2 | 3 | text: 4 | --> p = 0; 5 | 6 | rconst: 7 | #0: int:{?} "main:gen:0:{}" 8 | 9 | stack: 10 | ---------------------------- inter 11 | 0: |1| {0:<>} (int p) 12 | ---------------------------- main 13 | 14 | 15 | 16 | (0db) 17 | -------------------------------------------------------------------------------- /tests/0db/00-basic/test.cfg: -------------------------------------------------------------------------------- 1 | step 2 | next 3 | break 29 4 | continue 5 | step 6 | quit 7 | -------------------------------------------------------------------------------- /tests/0db/00-basic/test.x: -------------------------------------------------------------------------------- 1 | void 2 | modify0(int *q, int x) ~ [ 3 | setup: q = .clump(1); 4 | if (x) { 5 | *q = 1; 6 | } 7 | ] { 8 | if (x) { 9 | *q = 1; 10 | } 11 | } 12 | 13 | void 14 | modify1(int *q, int x) ~ [ 15 | if (x) { 16 | setup: q = .clump(1); 17 | *q = 2; 18 | } 19 | ] { 20 | if (x) { 21 | *q = 2; 22 | } 23 | } 24 | 25 | int * 26 | main() 27 | { 28 | int p; 29 | p = 0; 30 | ~ [ p == 0; ] 31 | modify0(&p, 0); 32 | ~ [ p == 0; ] 33 | modify0(&p, 1); 34 | ~ [ p == 1; ] 35 | modify1(&p, 0); 36 | ~ [ p == 1; ] 37 | modify1(&p, 1); 38 | ~ [ p == 2; ] 39 | } 40 | -------------------------------------------------------------------------------- /tests/0db/run: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set +x 4 | 5 | XR0=$(pwd)/bin/0v 6 | LIBX=$(pwd)/libx 7 | AWKFILE=$(pwd)/tests/0db/split.awk 8 | TESTDIR=$(pwd)/tests/0db/00-basic 9 | 10 | output=$($XR0 -I $LIBX -r@ $TESTDIR/test.x < $TESTDIR/test.cfg 2>&1) 11 | 12 | tempdir=$(mktemp -d) 13 | 14 | # Split the output by the delimiter "(0db)" and write each part to a file 15 | # Using awk to process the splitting and file writing 16 | echo "$output" | awk -v file_prefix="$tempdir/" -f $AWKFILE 17 | 18 | diff -r $tempdir $TESTDIR/expected && rm -rf $tempdir 19 | -------------------------------------------------------------------------------- /tests/0db/split.awk: -------------------------------------------------------------------------------- 1 | BEGIN { RS="@"; count=0 } 2 | { 3 | # trim leading and trailing whitespace 4 | gsub(/^[ \t\r\n]+|[ \t\r\n]+$/, "", $0) 5 | if (length($0) > 0) { # line must be non-empty 6 | filename = file_prefix count # generate current filename 7 | print > filename # write current portion to file 8 | close(filename) 9 | count++ 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /tests/0v/00-basic/000-FAIL-naked-alloc.x: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void 4 | leak() 5 | { 6 | malloc(1); 7 | } 8 | -------------------------------------------------------------------------------- /tests/0v/00-basic/000-FAIL-naked-alloc.x.EXPECTED: -------------------------------------------------------------------------------- 1 | leak: garbage on heap 2 | -------------------------------------------------------------------------------- /tests/0v/00-basic/010-FAIL-non-returned-alloc.x: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void 4 | leak() 5 | { 6 | void *p; 7 | 8 | p = malloc(1); 9 | } 10 | -------------------------------------------------------------------------------- /tests/0v/00-basic/010-FAIL-non-returned-alloc.x.EXPECTED: -------------------------------------------------------------------------------- 1 | leak: garbage on heap 2 | -------------------------------------------------------------------------------- /tests/0v/00-basic/020-FAIL-annotation.x: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void * 4 | leak() 5 | { 6 | void *p; 7 | 8 | p = malloc(1); 9 | return p; 10 | } 11 | -------------------------------------------------------------------------------- /tests/0v/00-basic/020-FAIL-annotation.x.EXPECTED: -------------------------------------------------------------------------------- 1 | leak: actual and abstract states differ 2 | -------------------------------------------------------------------------------- /tests/0v/00-basic/030-alloc.x: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void * 4 | unit() ~ [ return .malloc(1); ] 5 | { 6 | void *p; 7 | 8 | p = malloc(1); 9 | return p; 10 | } 11 | -------------------------------------------------------------------------------- /tests/0v/00-basic/031-alloc-conditional-compile.x: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #ifdef XR0 4 | 5 | void * 6 | alloc() ~ [ return .malloc(1); ]; 7 | 8 | #endif 9 | 10 | void * 11 | alloc() 12 | { 13 | void *p; 14 | 15 | p = malloc(1); 16 | return p; 17 | } 18 | -------------------------------------------------------------------------------- /tests/0v/00-basic/041-FAIL-false-alloc-void.x: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void * 4 | unit() ~ [ return .malloc(1); ] 5 | { 6 | return NULL; 7 | } 8 | -------------------------------------------------------------------------------- /tests/0v/00-basic/041-FAIL-false-alloc-void.x.EXPECTED: -------------------------------------------------------------------------------- 1 | unit: return value must be pointing at something 2 | -------------------------------------------------------------------------------- /tests/0v/00-basic/050-two-variables.x: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void * 4 | unit() ~ [ return .malloc(1); ] 5 | { 6 | void *p; void *q; 7 | 8 | p = malloc(1); 9 | q = p; 10 | return q; 11 | } 12 | -------------------------------------------------------------------------------- /tests/0v/00-basic/060-FAIL-two-allocs.x: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void * 4 | leak() ~ [ return .malloc(1); ] 5 | { 6 | void *p; void *q; 7 | 8 | p = malloc(1); 9 | q = malloc(1); 10 | return q; 11 | } 12 | -------------------------------------------------------------------------------- /tests/0v/00-basic/060-FAIL-two-allocs.x.EXPECTED: -------------------------------------------------------------------------------- 1 | leak: garbage on heap 2 | -------------------------------------------------------------------------------- /tests/0v/00-basic/110-free-variable.x: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void 4 | unit() 5 | { 6 | void *p; 7 | 8 | p = malloc(1); 9 | ~ [ @p; ] 10 | free(p); 11 | ~ [ !@p; ] 12 | } 13 | -------------------------------------------------------------------------------- /tests/0v/00-basic/120-free-direct.x: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void 4 | unit() 5 | { 6 | free(malloc(1)); 7 | } 8 | -------------------------------------------------------------------------------- /tests/0v/00-basic/130-FAIL-double-free.x: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void 4 | unit() 5 | { 6 | void *p; 7 | 8 | p = malloc(1); 9 | free(p); 10 | free(p); 11 | } 12 | -------------------------------------------------------------------------------- /tests/0v/00-basic/130-FAIL-double-free.x.EXPECTED: -------------------------------------------------------------------------------- 1 | stdlib.h:14:24: precondition failure: argument of `ptr' must be lvalue (free) 2 | 00-basic/130-FAIL-double-free.x:10:9 (unit) 3 | -------------------------------------------------------------------------------- /tests/0v/00-basic/140-FAIL-sync-free.x: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void 4 | unit(void *p) 5 | { 6 | free(p); 7 | } 8 | -------------------------------------------------------------------------------- /tests/0v/00-basic/140-FAIL-sync-free.x.EXPECTED: -------------------------------------------------------------------------------- 1 | stdlib.h:14:24: precondition failure: argument of `ptr' must be pointing at something (free) 2 | 00-basic/140-FAIL-sync-free.x:6:9 (unit) 3 | -------------------------------------------------------------------------------- /tests/0v/00-basic/150-indirect-free.x: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void 4 | unit() 5 | { 6 | void *p; void *q; 7 | 8 | p = malloc(1); 9 | q = p; 10 | free(q); 11 | } 12 | -------------------------------------------------------------------------------- /tests/0v/00-basic/160-one-free-one-alloc.x: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void * 4 | unit() ~ [ return .malloc(1); ] 5 | { 6 | void *p; void *q; 7 | 8 | p = malloc(1); 9 | q = malloc(1); 10 | free(q); 11 | return p; 12 | } 13 | -------------------------------------------------------------------------------- /tests/0v/00-basic/170-FAIL-double-free.x: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void 4 | unit() 5 | { 6 | void *p; void *q; 7 | 8 | p = malloc(1); 9 | q = p; 10 | free(q); 11 | free(p); 12 | } 13 | -------------------------------------------------------------------------------- /tests/0v/00-basic/170-FAIL-double-free.x.EXPECTED: -------------------------------------------------------------------------------- 1 | stdlib.h:14:24: precondition failure: argument of `ptr' must be lvalue (free) 2 | 00-basic/170-FAIL-double-free.x:11:9 (unit) 3 | -------------------------------------------------------------------------------- /tests/0v/00-basic/180-FAIL-alloc-freed.x: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void * 4 | unit() ~ [ return .malloc(1); ] 5 | { 6 | void *p; 7 | 8 | p = malloc(1); 9 | free(p); 10 | return p; 11 | } 12 | -------------------------------------------------------------------------------- /tests/0v/00-basic/180-FAIL-alloc-freed.x.EXPECTED: -------------------------------------------------------------------------------- 1 | unit: return value must be lvalue 2 | -------------------------------------------------------------------------------- /tests/0v/00-basic/200-free-param.x: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void 4 | unit(void *p) ~ [ 5 | setup: p = .malloc(1); 6 | 7 | .free(p); 8 | ]{ 9 | free(p); 10 | } 11 | -------------------------------------------------------------------------------- /tests/0v/00-basic/300-FAIL-with-recursive-struct.x: -------------------------------------------------------------------------------- 1 | /* 2 | * thanks to jorendorff 3 | * https://github.com/xr0-org/xr0/issues/46 4 | */ 5 | 6 | #include 7 | 8 | struct node { 9 | struct node *next; 10 | }; 11 | 12 | struct node * 13 | f() ~ [ 14 | struct node *one; 15 | 16 | one = malloc(sizeof(struct node)); 17 | one->next = one; 18 | return one; 19 | ]{ 20 | struct node *one; 21 | 22 | one = malloc(sizeof(struct node)); 23 | one->next = one; 24 | malloc(1); 25 | return one; 26 | } 27 | -------------------------------------------------------------------------------- /tests/0v/00-basic/300-FAIL-with-recursive-struct.x.EXPECTED: -------------------------------------------------------------------------------- 1 | f: garbage on heap 2 | -------------------------------------------------------------------------------- /tests/0v/00-basic/301-FAIL-with-recursive-struct.x: -------------------------------------------------------------------------------- 1 | /* 2 | * thanks to jorendorff 3 | * https://github.com/xr0-org/xr0/issues/46 4 | */ 5 | 6 | #include 7 | 8 | struct node { 9 | struct node *next; 10 | }; 11 | 12 | struct node * 13 | f() ~ [ 14 | struct node one; 15 | 16 | one.next = &one; 17 | return &one; 18 | ]{ 19 | struct node one; 20 | 21 | one.next = &one; 22 | malloc(1); 23 | return &one; 24 | } 25 | -------------------------------------------------------------------------------- /tests/0v/00-basic/301-FAIL-with-recursive-struct.x.EXPECTED: -------------------------------------------------------------------------------- 1 | f: garbage on heap 2 | -------------------------------------------------------------------------------- /tests/0v/00-basic/400-out-of-order.x: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void * 4 | f() ~ [ return malloc(1); ] 5 | { 6 | free(malloc(1)); 7 | 8 | free(malloc(1)); 9 | free(malloc(1)); 10 | return malloc(1); 11 | } 12 | -------------------------------------------------------------------------------- /tests/0v/00-basic/410-struct-out-of-order.x: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct pair { 4 | void *p; 5 | void *q; 6 | }; 7 | 8 | struct pair * 9 | f() ~ [ 10 | struct pair *pair; 11 | 12 | pair = malloc(sizeof(struct pair)); 13 | pair->p = malloc(1); 14 | pair->q = malloc(1); 15 | return pair; 16 | ]{ 17 | struct pair *pair; 18 | void *q; 19 | 20 | q = malloc(1); 21 | pair = malloc(sizeof(struct pair)); 22 | pair->p = malloc(1); 23 | pair->q = q; 24 | return pair; 25 | } 26 | -------------------------------------------------------------------------------- /tests/0v/00-basic/420-struct-out-of-order.x: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct pair { 4 | void *p; 5 | void *q; 6 | }; 7 | 8 | struct pair 9 | f() ~ [ 10 | struct pair pair; 11 | 12 | pair.p = malloc(1); 13 | pair.q = malloc(1); 14 | return pair; 15 | ]{ 16 | struct pair pair; 17 | 18 | pair.q = malloc(1); 19 | pair.p = malloc(1); 20 | return pair; 21 | } 22 | -------------------------------------------------------------------------------- /tests/0v/00-basic/500-FAIL-side-effect.x: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void 4 | f(int *p) ~ [ setup: p = malloc(1); ] 5 | { 6 | *p = 5; 7 | } 8 | -------------------------------------------------------------------------------- /tests/0v/00-basic/510-side-effect.x: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void 4 | f(int *p) ~ [ 5 | setup: p = malloc(1); 6 | *p = 5; 7 | ]{ 8 | *p = 5; 9 | } 10 | -------------------------------------------------------------------------------- /tests/0v/00-basic/520-side-effect-rconst.x: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void 4 | f(int *p) ~ [ 5 | setup: p = malloc(1); 6 | *p = [?]; 7 | ]{ 8 | *p = 5; 9 | } 10 | -------------------------------------------------------------------------------- /tests/0v/01-branches/0100-body-trivial.x: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void * 4 | test(int x) ~ [ return .malloc(1); ] 5 | { 6 | if (x) { 7 | return malloc(1); 8 | } 9 | return malloc(1); 10 | } 11 | -------------------------------------------------------------------------------- /tests/0v/01-branches/0101-body-trivial-else.x: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void * 4 | test(int x) ~ [ return .malloc(1); ] 5 | { 6 | if (x) { 7 | return malloc(1); 8 | } else { 9 | return malloc(1); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /tests/0v/01-branches/0102-body-trivial-else-if.x: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void * 4 | test(int x) ~ [ return .malloc(1); ] 5 | { 6 | if (x) { 7 | return malloc(1); 8 | } else if (x) { 9 | return malloc(1); 10 | } else { 11 | return malloc(1); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /tests/0v/01-branches/0103-body-abstract.x: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void * 4 | f(int cond) ~ [ if (cond) return malloc(1); ] 5 | { 6 | if (cond) { 7 | return malloc(1); 8 | } 9 | return NULL; 10 | } 11 | -------------------------------------------------------------------------------- /tests/0v/01-branches/0200-conditional-allocation.x: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void * 4 | test(int x) ~ [ 5 | if (x) { 6 | return .malloc(1); 7 | } 8 | if (!x) { 9 | return .malloc(1); 10 | } 11 | ]{ 12 | return malloc(1); 13 | } 14 | -------------------------------------------------------------------------------- /tests/0v/01-branches/0201-conditional-allocation-else.x: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void * 4 | test(int x) ~ [ 5 | if (x) { 6 | return .malloc(1); 7 | } else { 8 | return .malloc(1); 9 | } 10 | ]{ 11 | return malloc(1); 12 | } 13 | -------------------------------------------------------------------------------- /tests/0v/01-branches/0300-conditional-allocation-body.x: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void * 4 | test(int x) ~ [ 5 | if (x) { 6 | return .malloc(1); 7 | } 8 | ]{ 9 | if (x) { 10 | return malloc(1); 11 | } 12 | return NULL; 13 | } 14 | -------------------------------------------------------------------------------- /tests/0v/01-branches/0301-FAIL-conditional-allocation-two.x: -------------------------------------------------------------------------------- 1 | /* 2 | * thanks to jorendorff 3 | * https://github.com/xr0-org/xr0/issues/50 4 | */ 5 | 6 | #include 7 | 8 | void * 9 | test(int x, int y) ~ [ 10 | if (x) { 11 | return .malloc(1); 12 | } else if (y) { 13 | return NULL; 14 | } else { 15 | return .malloc(1); 16 | } 17 | ]{ 18 | if (!y) { 19 | return malloc(1); 20 | } 21 | return NULL; 22 | } 23 | -------------------------------------------------------------------------------- /tests/0v/01-branches/0301-FAIL-conditional-allocation-two.x.EXPECTED: -------------------------------------------------------------------------------- 1 | test | $0 ∈ {?0} | $1 ∈ {?0}: return value must be pointing at something 2 | -------------------------------------------------------------------------------- /tests/0v/01-branches/0302-conditional-allocation-two.x: -------------------------------------------------------------------------------- 1 | /* 2 | * thanks to jorendorff 3 | * https://github.com/xr0-org/xr0/issues/50 4 | */ 5 | 6 | #include 7 | 8 | void * 9 | test(int x, int y) ~ [ 10 | if (x) { 11 | return .malloc(1); 12 | } else if (y) { 13 | return NULL; 14 | } else { 15 | return .malloc(1); 16 | } 17 | ]{ 18 | if (x) { 19 | return malloc(1); 20 | } 21 | if (!y) { 22 | return malloc(1); 23 | } 24 | return NULL; 25 | } 26 | -------------------------------------------------------------------------------- /tests/0v/01-branches/0310-FAIL-conditional-allocation-body.x: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void * 4 | test(int x) ~ [ 5 | if (x) { 6 | return .malloc(1); 7 | } 8 | ]{ 9 | return NULL; 10 | } 11 | -------------------------------------------------------------------------------- /tests/0v/01-branches/0310-FAIL-conditional-allocation-body.x.EXPECTED: -------------------------------------------------------------------------------- 1 | test | $0 ∈ {?0}: return value must be pointing at something 2 | -------------------------------------------------------------------------------- /tests/0v/01-branches/0320-FAIL-conditional-allocation-body.x: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void * 4 | test(int x) ~ [ 5 | if (x) { 6 | return .malloc(1); 7 | } 8 | ]{ 9 | return malloc(1); 10 | } 11 | -------------------------------------------------------------------------------- /tests/0v/01-branches/0320-FAIL-conditional-allocation-body.x.EXPECTED: -------------------------------------------------------------------------------- 1 | test | $0 ∈ {0?} | $0 ∈ {0}: actual and abstract states differ 2 | -------------------------------------------------------------------------------- /tests/0v/01-branches/0400-strcmp-conditional-allocation.x: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void * 5 | test(char *s) ~ [ 6 | if (strcmp(s, "yes")) { 7 | return .malloc(1); 8 | } 9 | if (!(strcmp(s, "yes"))) { 10 | return .malloc(1); 11 | } 12 | ]{ 13 | return malloc(1); 14 | } 15 | -------------------------------------------------------------------------------- /tests/0v/01-branches/0500-strcmp-conditional-allocation-body.x: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void * 5 | test(char *s) ~ [ 6 | if (strcmp(s, "yes")) { 7 | return .malloc(1); 8 | } 9 | ]{ 10 | if (strcmp(s, "yes")) { 11 | return malloc(1); 12 | } 13 | return NULL; 14 | } 15 | -------------------------------------------------------------------------------- /tests/0v/01-branches/0600-indirect.x: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void * 4 | alloc_if(int num) ~ [ 5 | if (num) { 6 | return .malloc(1); 7 | } 8 | ]{ 9 | if (num) { 10 | return malloc(1); 11 | } 12 | return NULL; 13 | } 14 | 15 | void * 16 | test(int x) ~ [ 17 | if (x) { 18 | return .malloc(1); 19 | } 20 | ]{ 21 | void *p; 22 | 23 | p = alloc_if(x); 24 | 25 | return p; 26 | } 27 | -------------------------------------------------------------------------------- /tests/0v/01-branches/0610-indirect-setup.x: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | foo(int cond, void *p) ~ [ 4 | if (cond) { 5 | setup: p = malloc(1); 6 | } 7 | ]{} 8 | 9 | test(int x) 10 | { 11 | void *p; 12 | 13 | p = malloc(1); 14 | foo(x, p); 15 | free(p); 16 | } 17 | -------------------------------------------------------------------------------- /tests/0v/01-branches/0700-indirect.x: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int 4 | number(); 5 | 6 | void * 7 | alloc_if(int num) ~ [ 8 | if (num) { 9 | return .malloc(1); 10 | } 11 | ]; 12 | 13 | void * 14 | test() ~ [ 15 | if (number()) { 16 | return .malloc(1); 17 | } 18 | ]{ 19 | int num; 20 | void *p; 21 | 22 | num = number(); 23 | p = alloc_if(num); 24 | 25 | return p; 26 | } 27 | 28 | int 29 | number() 30 | { 31 | return 0; 32 | } 33 | 34 | void * 35 | alloc_if(int num) 36 | { 37 | if (num) { 38 | return malloc(1); 39 | } 40 | return NULL; 41 | } 42 | -------------------------------------------------------------------------------- /tests/0v/01-branches/0800-indirect.x: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int 4 | number(int param); 5 | 6 | void * 7 | alloc_if(int num) ~ [ 8 | if (num) { 9 | return .malloc(1); 10 | } 11 | ]; 12 | 13 | void * 14 | test(int x) ~ [ 15 | if (number(x)) { 16 | return .malloc(1); 17 | } 18 | ]{ 19 | int n; 20 | 21 | n = x; 22 | 23 | return alloc_if(number(n)); 24 | } 25 | 26 | int 27 | number(int param) 28 | { 29 | return param; 30 | } 31 | 32 | void * 33 | alloc_if(int num) 34 | { 35 | if (num) { 36 | return malloc(1); 37 | } 38 | return NULL; 39 | } 40 | 41 | 42 | -------------------------------------------------------------------------------- /tests/0v/01-branches/0900-subsequent.x: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int 4 | f(int param); 5 | 6 | int 7 | g(int param); 8 | 9 | void * 10 | alloc_if(int num) ~ [ 11 | if (num) { 12 | return .malloc(1); 13 | } 14 | ]; 15 | 16 | void * 17 | test(int x) ~ [ 18 | if (f(g(x))) { 19 | return .malloc(1); 20 | } 21 | ]{ 22 | int m; 23 | int n; 24 | int k; 25 | 26 | m = x; 27 | ~ [ m == x; ] 28 | n = g(m); 29 | k = g(x); 30 | ~ [ n == k; ] 31 | return alloc_if(f(n)); 32 | } 33 | 34 | int 35 | f(int param) 36 | { 37 | return param; 38 | } 39 | 40 | int 41 | g(int param) 42 | { 43 | return param; 44 | } 45 | 46 | void * 47 | alloc_if(int num) 48 | { 49 | if (num) { 50 | return malloc(1); 51 | } 52 | return NULL; 53 | } 54 | -------------------------------------------------------------------------------- /tests/0v/01-branches/0901-FAIL-subsequent.x: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int 4 | f(int param); 5 | 6 | int 7 | g(int param); 8 | 9 | void * 10 | alloc_if(int num) ~ [ 11 | if (num) { 12 | return .malloc(1); 13 | } 14 | ]; 15 | 16 | void * 17 | test(int x) ~ [ 18 | if (f(g(x))) { 19 | return .malloc(1); 20 | } 21 | ]{ 22 | int m; 23 | int n; 24 | int k; 25 | 26 | m = x; 27 | ~ [ m == x; ] 28 | n = g(m); 29 | ~ [ n != g(x); ] 30 | return alloc_if(f(n)); 31 | } 32 | 33 | int 34 | f(int param) 35 | { 36 | return param; 37 | } 38 | 39 | int 40 | g(int param) 41 | { 42 | return param; 43 | } 44 | 45 | void * 46 | alloc_if(int num) 47 | { 48 | if (num) { 49 | return malloc(1); 50 | } 51 | return NULL; 52 | } 53 | -------------------------------------------------------------------------------- /tests/0v/01-branches/0901-FAIL-subsequent.x.EXPECTED: -------------------------------------------------------------------------------- 1 | 01-branches/0901-FAIL-subsequent.x:29:17: cannot verify complex expressions: `n!=g(x)' (test | #1 ∈ {?0}) 2 | -------------------------------------------------------------------------------- /tests/0v/01-branches/1000-chaining-functions.x: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct tuple { int x; int y; }; 4 | 5 | struct tuple 6 | tuple_create(); 7 | 8 | void * 9 | conditional_alloc(int x) ~ [ if (x) return .malloc(1); ]; 10 | 11 | void * 12 | test() ~ [ if (tuple_create().x) return .malloc(1); ] 13 | { 14 | struct tuple t; 15 | 16 | t = tuple_create(); 17 | 18 | return conditional_alloc(t.x); 19 | } 20 | 21 | struct tuple 22 | tuple_create() 23 | { 24 | struct tuple t; 25 | 26 | t.x = 0; 27 | t.y = 0; 28 | return t; 29 | } 30 | 31 | void * 32 | conditional_alloc(int x) 33 | { 34 | if (x) { 35 | return malloc(1); 36 | } 37 | return NULL; 38 | } 39 | -------------------------------------------------------------------------------- /tests/0v/01-branches/1001-chaining-functions.x: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct tuple { int x; int y; }; 4 | 5 | struct tuple 6 | tuple_create() ~ [ 7 | struct tuple t; 8 | t.x = [?]; 9 | t.y = [?]; 10 | return t; 11 | ]; 12 | 13 | void * 14 | conditional_alloc(int x) ~ [ if (x) { return .malloc(1); } ]; 15 | 16 | void * 17 | test() ~ [ if (tuple_create().x) { return .malloc(1); } ] 18 | { 19 | struct tuple t; 20 | 21 | t = tuple_create(); 22 | 23 | return conditional_alloc(t.x); 24 | } 25 | 26 | struct tuple 27 | tuple_create() 28 | { 29 | struct tuple t; 30 | 31 | t.x = 0; 32 | t.y = 0; 33 | return t; 34 | } 35 | 36 | void * 37 | conditional_alloc(int x) 38 | { 39 | if (x) { 40 | return malloc(1); 41 | } 42 | return NULL; 43 | } 44 | -------------------------------------------------------------------------------- /tests/0v/01-branches/1002-chaining-functions.x: -------------------------------------------------------------------------------- 1 | struct tuple { int x; int y; }; 2 | 3 | struct tuple 4 | tuple_create() ~ [ 5 | struct tuple t; 6 | t.x = [?]; 7 | t.y = [?]; 8 | return t; 9 | ]; 10 | 11 | test() 12 | { 13 | struct tuple a; 14 | struct tuple b; 15 | 16 | a = tuple_create(); 17 | b = tuple_create(); 18 | ~ [ a.x == b.x; ] 19 | } 20 | 21 | struct tuple 22 | tuple_create() 23 | { 24 | struct tuple t; 25 | 26 | t.x = 0; 27 | t.y = 0; 28 | return t; 29 | } 30 | -------------------------------------------------------------------------------- /tests/0v/01-branches/1300-nested-branch-return.x: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void * 4 | foo(int a, int b) 5 | { 6 | int *p; 7 | p = malloc(1); 8 | if (a) { 9 | free(p); 10 | if (b) { 11 | return NULL; 12 | } 13 | } 14 | if (b) { 15 | free(p); 16 | } 17 | if (!a) { 18 | if (!b) { 19 | free(p); 20 | } 21 | } 22 | return NULL; 23 | } 24 | -------------------------------------------------------------------------------- /tests/0v/02-loops/000-loop.x: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void 4 | unit() 5 | { 6 | int i; 7 | 8 | for (i = 0; i < 9; i++) ~ [ i = [0?10]; ] 9 | ; 10 | 11 | ~ [ i == 9; ] 12 | } 13 | -------------------------------------------------------------------------------- /tests/0v/02-loops/010-FAIL-loop-invariant.x: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void 4 | unit() 5 | { 6 | int i; 7 | 8 | for (i = 0; i < 9; i++) ~ [ i = [0?9]; ] 9 | ; 10 | 11 | ~ [ i == 9; ] 12 | } 13 | -------------------------------------------------------------------------------- /tests/0v/02-loops/010-FAIL-loop-invariant.x.EXPECTED: -------------------------------------------------------------------------------- 1 | 02-loops/010-FAIL-loop-invariant.x:9:3: invariant failure: `i' must be < 9 (unit) 2 | -------------------------------------------------------------------------------- /tests/0v/02-loops/020-FAIL-loop-conclusion.x: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void 4 | unit() 5 | { 6 | int i; 7 | 8 | for (i = 0; i < 9; i++) ~ [ i = [0?10]; ] 9 | ; 10 | 11 | ~ [ i == 8; ] 12 | } 13 | -------------------------------------------------------------------------------- /tests/0v/02-loops/020-FAIL-loop-conclusion.x.EXPECTED: -------------------------------------------------------------------------------- 1 | 02-loops/020-FAIL-loop-conclusion.x:11:14: cannot verify statement (unit | #0 ∈ {9}) 2 | -------------------------------------------------------------------------------- /tests/0v/02-loops/100-variable-limit.x: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void 4 | unit(int limit) ~ [ setup: limit = [0?50]; ] 5 | { 6 | int i; 7 | 8 | for (i = 0; i < limit; i++) ~ [ i = [0?limit+1]; ] 9 | ; 10 | 11 | ~ [ i == limit; ] 12 | } 13 | -------------------------------------------------------------------------------- /tests/0v/04-linking/000-internal-prototype-abstract.x: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void * 4 | allocating() ~ [ return .malloc(1); ]; 5 | 6 | int 7 | main() 8 | { 9 | void *p; 10 | 11 | p = allocating(); 12 | free(p); 13 | return 0; 14 | } 15 | 16 | void * 17 | allocating() 18 | { 19 | void *p; 20 | 21 | p = malloc(1); 22 | return p; 23 | } 24 | -------------------------------------------------------------------------------- /tests/0v/04-linking/010-internal-two-matching-abstracts.x: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void * 4 | allocating() ~ [ return .malloc(1); ]; 5 | 6 | int 7 | main() 8 | { 9 | void *p; 10 | 11 | p = allocating(); 12 | free(p); 13 | return 0; 14 | } 15 | 16 | void * 17 | allocating() ~ [ return .malloc(1); ] 18 | { 19 | void *p; 20 | 21 | p = malloc(1); 22 | return p; 23 | } 24 | -------------------------------------------------------------------------------- /tests/0v/04-linking/020-FAIL-internal-mismatch-abstracts.x: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void * 4 | allocating() ~ [ .free(result); ]; 5 | 6 | int 7 | main() 8 | { 9 | void *p; 10 | 11 | p = allocating(); 12 | free(p); 13 | } 14 | 15 | void * 16 | allocating() ~ [ return .malloc(1); ] 17 | { 18 | void *p; 19 | 20 | p = malloc(1); 21 | return p; 22 | } 23 | -------------------------------------------------------------------------------- /tests/0v/04-linking/020-FAIL-internal-mismatch-abstracts.x.EXPECTED: -------------------------------------------------------------------------------- 1 | function `allocating' prototype and definition abstracts mismatch 2 | -------------------------------------------------------------------------------- /tests/0v/04-linking/030-FAIL-internal-missing-definition.x: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | static void * 4 | allocating() ~ [ return .malloc(1); ]; 5 | -------------------------------------------------------------------------------- /tests/0v/04-linking/030-FAIL-internal-missing-definition.x.EXPECTED: -------------------------------------------------------------------------------- 1 | function `allocating' missing definition 2 | -------------------------------------------------------------------------------- /tests/0v/04-linking/040-FAIL-multiple-definitions.x: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void * 4 | allocating() ~ [ return .malloc(1); ]; 5 | 6 | void * 7 | allocating() { } 8 | 9 | void * 10 | allocating() { } 11 | -------------------------------------------------------------------------------- /tests/0v/04-linking/040-FAIL-multiple-definitions.x.EXPECTED: -------------------------------------------------------------------------------- 1 | function `allocating' has multiple definitions 2 | -------------------------------------------------------------------------------- /tests/0v/04-linking/050-multiple-prototype.x: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void * 4 | allocating() ~ [ return .malloc(1); ]; 5 | 6 | void * 7 | nonallocating(); 8 | 9 | void * 10 | allocating() 11 | { 12 | void *p; 13 | void *q; 14 | 15 | p = malloc(1); 16 | q = nonallocating(); 17 | return p; 18 | } 19 | 20 | void * 21 | nonallocating() 22 | { 23 | return NULL; 24 | } 25 | -------------------------------------------------------------------------------- /tests/0v/05-pass-by-ptr/000-basic.x: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void 4 | assign(void *p) ~ [ 5 | setup: p = .clump(1); 6 | *p = 1; 7 | ]{ 8 | /* TODO: internal verification */ 9 | *p = 1; 10 | } 11 | 12 | int 13 | main() 14 | { 15 | int p; int q; 16 | 17 | assign(&q); 18 | p = 2; 19 | 20 | ~ [ q == 1; p == 2; ] 21 | return 0; 22 | } 23 | -------------------------------------------------------------------------------- /tests/0v/06-preconditions/100-FAIL-need-alloced-lval.x: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void 4 | func(int *x) ~ [ 5 | setup: x = .malloc(1); 6 | *x = 5; 7 | ]{ 8 | *x = 5; 9 | } 10 | 11 | int 12 | main() 13 | { 14 | int p; 15 | func(&p); /* ERROR: spec requires heap */ 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /tests/0v/06-preconditions/100-FAIL-need-alloced-lval.x.EXPECTED: -------------------------------------------------------------------------------- 1 | 06-preconditions/100-FAIL-need-alloced-lval.x:5:23: precondition failure: argument of `x' must be heap allocated (func) 2 | 06-preconditions/100-FAIL-need-alloced-lval.x:15:10 (main) 3 | -------------------------------------------------------------------------------- /tests/0v/06-preconditions/110-FAIL-need-alloced-rval.x: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int 4 | func(int *x) ~ [ 5 | setup: { 6 | x = .malloc(1); 7 | *x = [?]; 8 | } 9 | return *x; 10 | ]{ 11 | return *x; 12 | } 13 | 14 | int 15 | main() 16 | { 17 | int *p; 18 | int q; 19 | p = malloc(1); 20 | q = func(p); /* ERROR: spec required rvalue */ 21 | return 0; 22 | } 23 | -------------------------------------------------------------------------------- /tests/0v/06-preconditions/110-FAIL-need-alloced-rval.x.EXPECTED: -------------------------------------------------------------------------------- 1 | 06-preconditions/110-FAIL-need-alloced-rval.x:8:2: precondition failure: argument of `x' must have object at index 0 (func) 2 | 06-preconditions/110-FAIL-need-alloced-rval.x:20:13 (main) 3 | -------------------------------------------------------------------------------- /tests/0v/06-preconditions/111-FAIL-need-alloced-rval.x: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int 4 | func(int *x) ~ [ 5 | setup: { 6 | x = malloc(1); 7 | *x = [?]; 8 | } 9 | return *x; 10 | ]{ 11 | return *x; 12 | } 13 | 14 | int 15 | main() 16 | { 17 | int p; 18 | int q; 19 | p = malloc(1); 20 | q = func(p); /* ERROR: spec required rvalue */ 21 | } 22 | -------------------------------------------------------------------------------- /tests/0v/06-preconditions/111-FAIL-need-alloced-rval.x.EXPECTED: -------------------------------------------------------------------------------- 1 | 06-preconditions/111-FAIL-need-alloced-rval.x:8:2: precondition failure: argument of `x' must have object at index 0 (func) 2 | 06-preconditions/111-FAIL-need-alloced-rval.x:20:13 (main) 3 | -------------------------------------------------------------------------------- /tests/0v/06-preconditions/112-FAIL-need-rval.x: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int 4 | func(int *x) ~ [ 5 | setup: { 6 | x = .clump(1); 7 | *x = [?]; 8 | } 9 | return *x; 10 | ]{ 11 | return *x; 12 | } 13 | 14 | int 15 | main() 16 | { 17 | int p; 18 | int q; 19 | q = func(&p); /* ERROR: spec required rvalue */ 20 | } 21 | -------------------------------------------------------------------------------- /tests/0v/06-preconditions/112-FAIL-need-rval.x.EXPECTED: -------------------------------------------------------------------------------- 1 | 06-preconditions/112-FAIL-need-rval.x:8:2: precondition failure: argument of `x' must have value at index 0 (func) 2 | 06-preconditions/112-FAIL-need-rval.x:19:14 (main) 3 | -------------------------------------------------------------------------------- /tests/0v/06-preconditions/120-FAIL-need-clump-lval-freed-ptr.x: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void 4 | func(int *x) ~ [ 5 | setup: x = .clump(1); 6 | ]{ 7 | } 8 | 9 | int 10 | main() 11 | { 12 | int *p; 13 | p = malloc(1); 14 | free(p); 15 | 16 | func(p); /* ERROR: spec required rvalue */ 17 | } 18 | -------------------------------------------------------------------------------- /tests/0v/06-preconditions/120-FAIL-need-clump-lval-freed-ptr.x.EXPECTED: -------------------------------------------------------------------------------- 1 | 06-preconditions/120-FAIL-need-clump-lval-freed-ptr.x:5:22: precondition failure: argument of `x' must be lvalue (func) 2 | 06-preconditions/120-FAIL-need-clump-lval-freed-ptr.x:16:9 (main) 3 | -------------------------------------------------------------------------------- /tests/0v/06-preconditions/130-FAIL-need-clump-lval-assigned-ptr.x: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void 4 | func(int *x) ~ [ 5 | setup: x = .clump(1); 6 | ]{ 7 | 8 | } 9 | 10 | int 11 | main() 12 | { 13 | int *p; 14 | p = 5; 15 | 16 | func(p); /* ERROR: spec required lvalue */ 17 | } 18 | -------------------------------------------------------------------------------- /tests/0v/06-preconditions/130-FAIL-need-clump-lval-assigned-ptr.x.EXPECTED: -------------------------------------------------------------------------------- 1 | 06-preconditions/130-FAIL-need-clump-lval-assigned-ptr.x:5:22: precondition failure: argument of `x' must be pointing at something (func) 2 | 06-preconditions/130-FAIL-need-clump-lval-assigned-ptr.x:16:9 (main) 3 | -------------------------------------------------------------------------------- /tests/0v/06-preconditions/140-setup-null.x: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void 4 | func(int *x) ~ [ 5 | setup: x = NULL; 6 | ]{ 7 | 8 | } 9 | 10 | int 11 | main() 12 | { 13 | int *p; 14 | p = 5; 15 | 16 | func(p); 17 | return 0; 18 | } 19 | -------------------------------------------------------------------------------- /tests/0v/06-preconditions/200-clump-no-leak.x: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | notleak(void **p) ~ [ 4 | setup: p = .clump(1); 5 | *p = malloc(1); 6 | ]{ 7 | *p = malloc(1); 8 | } 9 | -------------------------------------------------------------------------------- /tests/0v/06-preconditions/201-clump-nested-not-leak.x: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct composite { 4 | void *p; 5 | }; 6 | 7 | void 8 | allocsub(struct composite *p) ~ [ 9 | setup: p = .clump(1); 10 | p->p = malloc(1); 11 | ]{ 12 | p->p = malloc(1); 13 | } 14 | 15 | -------------------------------------------------------------------------------- /tests/0v/06-preconditions/210-composite.x: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct composite { 4 | void *p; 5 | }; 6 | 7 | notleak(struct composite *p) ~ [ 8 | setup: p = .clump(1); 9 | p->p = malloc(1); 10 | ]{ 11 | p->p = malloc(1); 12 | } 13 | -------------------------------------------------------------------------------- /tests/0v/06-preconditions/220-FAIL-leak.x: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | leak(void *p) ~ [ p = malloc(1); ] 4 | { 5 | p = malloc(1); 6 | } 7 | -------------------------------------------------------------------------------- /tests/0v/06-preconditions/220-FAIL-leak.x.EXPECTED: -------------------------------------------------------------------------------- 1 | leak: garbage on heap 2 | -------------------------------------------------------------------------------- /tests/0v/06-preconditions/230-FAIL-side-effect-leak.x: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void 4 | notleak(void **p) ~ [ 5 | setup: p = .clump(1); 6 | *p = malloc(1); 7 | ]{ 8 | *p = malloc(1); 9 | } 10 | 11 | int 12 | main() 13 | { 14 | void *p; 15 | p = malloc(1); 16 | notleak(&p); 17 | free(p); 18 | } 19 | -------------------------------------------------------------------------------- /tests/0v/06-preconditions/230-FAIL-side-effect-leak.x.EXPECTED: -------------------------------------------------------------------------------- 1 | main: garbage on heap 2 | -------------------------------------------------------------------------------- /tests/0v/06-preconditions/231-still-referenced.x: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void 4 | notleak(void **p) ~ [ 5 | setup: p = .clump(1); 6 | *p = malloc(1); 7 | ]{ 8 | *p = malloc(1); 9 | } 10 | 11 | int 12 | main() 13 | { 14 | void *p; void *q; 15 | 16 | p = malloc(1); 17 | q = p; 18 | notleak(&p); 19 | free(p); 20 | free(q); 21 | return 0; 22 | } 23 | -------------------------------------------------------------------------------- /tests/0v/06-preconditions/300-range-verification.x: -------------------------------------------------------------------------------- 1 | int 2 | foo(int x) ~ [ setup: x = [0?2]; ] 3 | { 4 | return 3; 5 | } 6 | 7 | int 8 | bar(int x) 9 | { 10 | foo(1); 11 | return 0; 12 | } 13 | -------------------------------------------------------------------------------- /tests/0v/06-preconditions/310-FAIL-range-verification.x: -------------------------------------------------------------------------------- 1 | int 2 | foo(int x) ~ [ setup: x = [0?2]; ] 3 | { 4 | return 3; 5 | } 6 | 7 | int 8 | bar(int x) 9 | { 10 | foo(2); /* FAIL */ 11 | return 0; 12 | } 13 | -------------------------------------------------------------------------------- /tests/0v/06-preconditions/310-FAIL-range-verification.x.EXPECTED: -------------------------------------------------------------------------------- 1 | 06-preconditions/310-FAIL-range-verification.x:2:32: precondition failure: argument of `x' must be < 2 (foo) 2 | 06-preconditions/310-FAIL-range-verification.x:10:8 (bar) 3 | -------------------------------------------------------------------------------- /tests/0v/06-preconditions/320-FAIL-range-verification.x: -------------------------------------------------------------------------------- 1 | int 2 | foo(int x) ~ [ setup: x = [-1?2]; ] 3 | { 4 | return 3; 5 | } 6 | 7 | int 8 | bar(int x) 9 | { 10 | foo(-2); /* FAIL */ 11 | } 12 | -------------------------------------------------------------------------------- /tests/0v/06-preconditions/320-FAIL-range-verification.x.EXPECTED: -------------------------------------------------------------------------------- 1 | 06-preconditions/320-FAIL-range-verification.x:2:33: precondition failure: argument of `x' must be ≥ -1 (foo) 2 | 06-preconditions/320-FAIL-range-verification.x:10:9 (bar) 3 | -------------------------------------------------------------------------------- /tests/0v/06-preconditions/330-FAIL-range-verification.x: -------------------------------------------------------------------------------- 1 | int 2 | foo(int x) ~ [ return [0?3]; ] 3 | { 4 | return 3; 5 | } 6 | -------------------------------------------------------------------------------- /tests/0v/06-preconditions/330-FAIL-range-verification.x.EXPECTED: -------------------------------------------------------------------------------- 1 | foo: return value must be < 3 2 | -------------------------------------------------------------------------------- /tests/0v/06-preconditions/400-array-nested-value.x: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int * 4 | foo(int **arr) ~ [ 5 | setup: { 6 | arr = .clump(2); 7 | arr[0] = [?]; 8 | arr[1] = .clump(1); 9 | arr[1][0] = [?]; 10 | } 11 | return arr[0]; 12 | ]{ 13 | int k; 14 | k = arr[1][0]; 15 | return arr[0]; 16 | } 17 | 18 | void 19 | bar() 20 | { 21 | int *obj[2]; 22 | 23 | obj[0] = 0; 24 | obj[1] = malloc(1); 25 | obj[1][0] = 0; 26 | foo(obj); 27 | free(obj[1]); 28 | } 29 | -------------------------------------------------------------------------------- /tests/0v/06-preconditions/410-FAIL-array-nested-value.x: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int * 4 | foo(int **arr) ~ [ 5 | setup: { 6 | arr = .clump(2); 7 | arr[0] = [?]; 8 | arr[1] = .clump(1); 9 | arr[1][0] = [?]; 10 | } 11 | return arr[0]; 12 | ]{ 13 | int k; 14 | k = arr[1][0]; 15 | return arr[0]; 16 | } 17 | 18 | void 19 | bar() 20 | { 21 | int *obj[2]; 22 | 23 | obj[0] = 0; 24 | obj[1] = malloc(1); 25 | foo(obj); 26 | free(obj[1]); 27 | } 28 | -------------------------------------------------------------------------------- /tests/0v/06-preconditions/410-FAIL-array-nested-value.x.EXPECTED: -------------------------------------------------------------------------------- 1 | 06-preconditions/410-FAIL-array-nested-value.x:10:2: precondition failure: argument of `arr' must have object at index 0 at index 1 (foo) 2 | 06-preconditions/410-FAIL-array-nested-value.x:25:10 (bar) 3 | -------------------------------------------------------------------------------- /tests/0v/06-preconditions/420-array-nested-object.x: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int * 4 | foo(int **arr) ~ [ 5 | setup: { 6 | arr = .clump(2); 7 | arr[0] = [?]; 8 | arr[1] = .clump(1); 9 | } 10 | return arr[0]; 11 | ]{ 12 | return arr[0]; 13 | } 14 | 15 | void 16 | bar() 17 | { 18 | int *obj[2]; 19 | 20 | obj[0] = 0; 21 | obj[1] = malloc(1); 22 | foo(obj); 23 | free(obj[1]); 24 | } 25 | -------------------------------------------------------------------------------- /tests/0v/06-preconditions/430-FAIL-array-nested-object.x: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int * 4 | foo(int **arr) ~ [ 5 | setup: { 6 | arr = .clump(2); 7 | arr[0] = [?]; 8 | arr[1] = .clump(1); 9 | } 10 | return arr[0]; 11 | ]{ 12 | return arr[0]; 13 | } 14 | 15 | void 16 | bar() 17 | { 18 | int *obj[2]; 19 | 20 | obj[0] = 0; 21 | foo(obj); 22 | } 23 | -------------------------------------------------------------------------------- /tests/0v/06-preconditions/430-FAIL-array-nested-object.x.EXPECTED: -------------------------------------------------------------------------------- 1 | 06-preconditions/430-FAIL-array-nested-object.x:9:2: precondition failure: argument of `arr' must have object at index 1 (foo) 2 | 06-preconditions/430-FAIL-array-nested-object.x:21:10 (bar) 3 | -------------------------------------------------------------------------------- /tests/0v/06-preconditions/440-array-value.x: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int * 4 | foo(int **arr) ~ [ 5 | setup: { 6 | arr = .clump(2); 7 | arr[0] = [?]; 8 | arr[1] = [?]; 9 | } 10 | return arr[0]; 11 | ]{ 12 | int k; 13 | k = arr[1]; 14 | return arr[0]; 15 | } 16 | 17 | void 18 | bar() 19 | { 20 | int *obj[2]; 21 | 22 | obj[0] = 0; 23 | obj[1] = 0; 24 | foo(obj); 25 | } 26 | -------------------------------------------------------------------------------- /tests/0v/06-preconditions/450-FAIL-array-value.x: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int * 4 | foo(int **arr) ~ [ 5 | setup: { 6 | arr = .clump(2); 7 | arr[0] = [?]; 8 | arr[1] = [?]; 9 | } 10 | return arr[0]; 11 | ]{ 12 | int k; 13 | k = arr[1]; 14 | return arr[0]; 15 | } 16 | 17 | void 18 | bar() 19 | { 20 | int *obj[2]; 21 | 22 | obj[0] = 0; 23 | foo(obj); 24 | } 25 | -------------------------------------------------------------------------------- /tests/0v/06-preconditions/450-FAIL-array-value.x.EXPECTED: -------------------------------------------------------------------------------- 1 | 06-preconditions/450-FAIL-array-value.x:9:2: precondition failure: argument of `arr' must have object at index 1 (foo) 2 | 06-preconditions/450-FAIL-array-value.x:23:10 (bar) 3 | -------------------------------------------------------------------------------- /tests/0v/06-preconditions/500-shifted-array.x: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int 4 | foo(int *arr) ~ [ 5 | setup: { 6 | arr = .clump(2); 7 | arr[0] = [?]; 8 | arr[1] = [?]; 9 | } 10 | return arr[0]; 11 | ]{ 12 | int k; 13 | k = arr[1]; 14 | return arr[0]; 15 | } 16 | 17 | void 18 | bar() 19 | { 20 | int obj[3]; 21 | 22 | obj[1] = 0; 23 | obj[2] = 0; 24 | foo(obj+1); 25 | } 26 | -------------------------------------------------------------------------------- /tests/0v/06-preconditions/510-FAIL-shifted-array.x: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int 4 | foo(int *arr) ~ [ 5 | setup: { 6 | arr = .clump(2); 7 | arr[0] = [?]; 8 | arr[1] = [?]; 9 | } 10 | return arr[0]; 11 | ]{ 12 | int k; 13 | k = arr[1]; 14 | return arr[0]; 15 | } 16 | 17 | void 18 | bar() 19 | { 20 | int obj[3]; 21 | 22 | obj[1] = 0; 23 | obj[2] = 0; 24 | foo(obj); 25 | } 26 | -------------------------------------------------------------------------------- /tests/0v/06-preconditions/510-FAIL-shifted-array.x.EXPECTED: -------------------------------------------------------------------------------- 1 | 06-preconditions/510-FAIL-shifted-array.x:9:2: precondition failure: argument of `arr' must have value at index 0 (foo) 2 | 06-preconditions/510-FAIL-shifted-array.x:24:10 (bar) 3 | -------------------------------------------------------------------------------- /tests/0v/07-use-after-free/001-read-and-write-arbitrary.x: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int * 4 | read_and_write_arbitrary() ~ [ 5 | int *p; 6 | p = .malloc(sizeof(int)); 7 | *p = 1; 8 | return p; 9 | ] { 10 | int *p; 11 | p = malloc(sizeof(int)); 12 | *p = 1; 13 | return p; 14 | } 15 | 16 | int 17 | main() 18 | { 19 | int *r; 20 | int j; 21 | 22 | r = read_and_write_arbitrary(); 23 | j = *r; /* valid rvalue deref */ 24 | // ~ [ *r == $; ]; 25 | // ~ [ j == $; ]; /* j has arbitrary value */ 26 | *r = 2; /* valid lvalue deref */ 27 | ~ [ *r == 2; ]; 28 | 29 | free(r); 30 | 31 | return 0; 32 | } 33 | -------------------------------------------------------------------------------- /tests/0v/07-use-after-free/002-pass-in-lvalue.x: -------------------------------------------------------------------------------- 1 | void 2 | modify(int *q) ~ [ 3 | setup: q = .clump(sizeof(int)); 4 | *q = 2; 5 | ] { 6 | *q = 2; 7 | } 8 | 9 | int 10 | main() 11 | { 12 | int p; 13 | p = 1; 14 | ~ [ p == 1; ]; 15 | modify(&p); 16 | ~ [ p == 2; ]; 17 | return 0; 18 | } 19 | -------------------------------------------------------------------------------- /tests/0v/07-use-after-free/003-pass-in-rvalue.x: -------------------------------------------------------------------------------- 1 | void 2 | assign(int *q) ~ [ 3 | setup: { 4 | q = .clump(sizeof(int)); 5 | *q = [?]; 6 | } 7 | ]{ 8 | int p; 9 | p = *q; 10 | } 11 | 12 | int 13 | main() 14 | { 15 | int p; 16 | p = 1; 17 | assign(&p); 18 | ~ [ p == 1; ]; 19 | return 0; 20 | } 21 | -------------------------------------------------------------------------------- /tests/0v/07-use-after-free/004-mix-multiple-levels.x: -------------------------------------------------------------------------------- 1 | int 2 | snapshot_and_change(int *arg) ~ [ 3 | int j; 4 | setup: { 5 | arg = .clump(sizeof(int)); 6 | *arg = [?]; 7 | } 8 | j = *arg; 9 | *arg = 3; 10 | return j; 11 | ] { 12 | int j; 13 | j = *arg; 14 | *arg = 3; 15 | return j; 16 | } 17 | 18 | void 19 | modify(int *p, int *q) ~ [ 20 | int i; 21 | setup: { 22 | p = .clump(sizeof(int)); 23 | *p = [?]; 24 | q = .clump(sizeof(int)); 25 | }; 26 | *q = 2; 27 | *p = 3; 28 | i = *p; 29 | ] { 30 | int i; 31 | i = 0; 32 | i = snapshot_and_change(p); 33 | ~ [ *p == 3; ]; 34 | 35 | *q = 2; 36 | } 37 | 38 | int 39 | main() 40 | { 41 | int p; 42 | int q; 43 | p = 9; 44 | ~ [ p == 9; ]; 45 | modify(&p, &q); 46 | ~ [ p == 3; ]; 47 | ~ [ q == 2; ]; 48 | return 0; 49 | } 50 | -------------------------------------------------------------------------------- /tests/0v/07-use-after-free/005-conditions.x: -------------------------------------------------------------------------------- 1 | void 2 | modify0(int *q, int x) ~ [ 3 | setup: q = .clump(1); 4 | if (x) { 5 | *q = 1; 6 | } 7 | ] { 8 | if (x) { 9 | *q = 1; 10 | } 11 | } 12 | 13 | void 14 | modify1(int *q, int x) ~ [ 15 | if (x) { 16 | setup: q = .clump(1); 17 | *q = 2; 18 | } 19 | ] { 20 | if (x) { 21 | *q = 2; 22 | } 23 | } 24 | 25 | int 26 | main() 27 | { 28 | int p; 29 | p = 0; 30 | ~ [ p == 0; ] 31 | modify0(&p, 0); 32 | ~ [ p == 0; ] 33 | modify0(&p, 1); 34 | ~ [ p == 1; ] 35 | modify1(&p, 0); 36 | ~ [ p == 1; ] 37 | modify1(&p, 1); 38 | ~ [ p == 2; ] 39 | return 0; 40 | } 41 | -------------------------------------------------------------------------------- /tests/0v/07-use-after-free/100-FAIL-lvalue-use-after-free.x: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void 4 | func() 5 | { 6 | int *p; 7 | 8 | p = malloc(1); 9 | free(p); 10 | 11 | *p = 1; /* ERROR: undefined indirection (lvalue) */ 12 | } 13 | -------------------------------------------------------------------------------- /tests/0v/07-use-after-free/100-FAIL-lvalue-use-after-free.x.EXPECTED: -------------------------------------------------------------------------------- 1 | 07-use-after-free/100-FAIL-lvalue-use-after-free.x:11:8: undefined indirection: *(p) is not an lvalue (func) 2 | -------------------------------------------------------------------------------- /tests/0v/07-use-after-free/101-FAIL-rvalue-use-after-free.x: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void 4 | func() 5 | { 6 | int *p; 7 | int q; 8 | 9 | p = malloc(1); 10 | free(p); 11 | 12 | q = *p; /* ERROR: undefined indirection (rvalue) */ 13 | } 14 | -------------------------------------------------------------------------------- /tests/0v/07-use-after-free/101-FAIL-rvalue-use-after-free.x.EXPECTED: -------------------------------------------------------------------------------- 1 | 07-use-after-free/101-FAIL-rvalue-use-after-free.x:12:8: undefined memory access: *(p) has no value (func) 2 | -------------------------------------------------------------------------------- /tests/0v/07-use-after-free/110-FAIL-freed-ptr-dangling-return.x: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int * 4 | func() 5 | { 6 | int *p; 7 | p = malloc(1); 8 | 9 | free(p); /* p dangling */ 10 | ~ [ !@p; ]; 11 | return p; /* return dangling ptr */ 12 | } 13 | 14 | int 15 | main() 16 | { 17 | int *i; 18 | int *j; 19 | 20 | i = func(); 21 | j = *i; /* ERROR: rconst not lvalue */ 22 | 23 | return 0; 24 | } 25 | -------------------------------------------------------------------------------- /tests/0v/07-use-after-free/110-FAIL-freed-ptr-dangling-return.x.EXPECTED: -------------------------------------------------------------------------------- 1 | 07-use-after-free/110-FAIL-freed-ptr-dangling-return.x:21:8: undefined indirection: *(i) is rconst not lvalue (main) 2 | -------------------------------------------------------------------------------- /tests/0v/07-use-after-free/112-FAIL-freed-ptr-dangling-false-claim.x: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int * 4 | func() ~ [ return [?]; ] /* ERROR: */ 5 | { 6 | int *p; 7 | p = malloc(1); 8 | 9 | free(p); /* p dangling */ 10 | 11 | return p; /* return dangling ptr */ 12 | } 13 | 14 | int 15 | main() 16 | { 17 | int *i; 18 | int *j; 19 | 20 | i = func(); /* should work based on func abstract? */ 21 | j = *i; 22 | 23 | return 0; 24 | } 25 | -------------------------------------------------------------------------------- /tests/0v/07-use-after-free/112-FAIL-freed-ptr-dangling-false-claim.x.EXPECTED: -------------------------------------------------------------------------------- 1 | 07-use-after-free/112-FAIL-freed-ptr-dangling-false-claim.x:21:8: undefined indirection: *(i) is rconst not lvalue (main) 2 | -------------------------------------------------------------------------------- /tests/0v/07-use-after-free/120-FAIL-freed-ptr-maybe-dangling-return.x: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int * 4 | func(int x) ~ [ 5 | int *p; 6 | p = .malloc(sizeof(int)); 7 | if (x) { 8 | .free(p); 9 | } 10 | return p; 11 | ] { 12 | int *p; 13 | p = malloc(1); 14 | 15 | if (x) { 16 | free(p); /* p dangling */ 17 | } 18 | 19 | return p; /* p not may be dangling */ 20 | } 21 | 22 | int 23 | main() 24 | { 25 | int *res1; 26 | int *res2; 27 | int *i; 28 | int *j; 29 | 30 | i = func(0); 31 | *i = 1; /* fine */ 32 | 33 | j = func(1); 34 | *j = 1; /* ERROR: undefined indirection */ 35 | 36 | return 0; 37 | } 38 | -------------------------------------------------------------------------------- /tests/0v/07-use-after-free/120-FAIL-freed-ptr-maybe-dangling-return.x.EXPECTED: -------------------------------------------------------------------------------- 1 | 07-use-after-free/120-FAIL-freed-ptr-maybe-dangling-return.x:34:8: undefined indirection: *(j) is not an lvalue (main) 2 | -------------------------------------------------------------------------------- /tests/0v/07-use-after-free/200-FAIL-stack-frame-pop-dangling-return.x: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int * 4 | dangling_return() 5 | { 6 | int p; 7 | 8 | p = 5; 9 | return &p; /* returning dangling pointer */ 10 | } 11 | 12 | int 13 | main() 14 | { 15 | int *p; 16 | int q; 17 | 18 | p = dangling_return(); 19 | q = *p; /* ERROR: undefined dereference */ 20 | } 21 | -------------------------------------------------------------------------------- /tests/0v/07-use-after-free/200-FAIL-stack-frame-pop-dangling-return.x.EXPECTED: -------------------------------------------------------------------------------- 1 | 07-use-after-free/200-FAIL-stack-frame-pop-dangling-return.x:19:8: undefined indirection: *(p) is rconst not lvalue (main) 2 | -------------------------------------------------------------------------------- /tests/0v/07-use-after-free/210-FAIL-stack-frame-pop-dangling-assign.x: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void 4 | dangling_assign(int **i) ~ [ 5 | int j; 6 | 7 | setup: i = .clump(sizeof(int *)); 8 | 9 | j = 5; 10 | *i = &j; 11 | ] { 12 | int j; 13 | 14 | j = 5; 15 | *i = &j; 16 | 17 | /* after this point i is dangling */ 18 | } 19 | 20 | int 21 | main() 22 | { 23 | int *p; 24 | int q; 25 | 26 | dangling_assign(&p); 27 | q = *p; /* ERROR: undefined dereference */ 28 | } 29 | -------------------------------------------------------------------------------- /tests/0v/07-use-after-free/210-FAIL-stack-frame-pop-dangling-assign.x.EXPECTED: -------------------------------------------------------------------------------- 1 | 07-use-after-free/210-FAIL-stack-frame-pop-dangling-assign.x:27:8: stack frame doesn't exist (main) 2 | -------------------------------------------------------------------------------- /tests/0v/07-use-after-free/300-FAIL-struct-free-ptr-dangling.x: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | struct report { 5 | int n; 6 | struct score **scores; 7 | }; 8 | 9 | struct score { 10 | char *subject; 11 | int grade; 12 | }; 13 | 14 | struct score * 15 | create_score(char *subject, int grade) ~ [ 16 | struct score *s; 17 | 18 | setup: subject = .malloc(sizeof(char *) * 100); 19 | 20 | s = .malloc(sizeof(struct score)); 21 | s->subject = subject; 22 | s->grade = grade; 23 | return s; 24 | ] { 25 | struct score *s; 26 | s = malloc(sizeof(struct score)); 27 | 28 | s->subject = subject; 29 | s->grade = grade; 30 | 31 | return s; 32 | } 33 | 34 | struct report * 35 | create_report() 36 | { 37 | struct score *s; 38 | char *sub; 39 | 40 | sub = malloc(sizeof(char) * 7); 41 | *sub = "english"; 42 | 43 | s = create_score(sub, 1); 44 | free(sub); /* dangling ptr */ 45 | puts(s->subject); 46 | } 47 | -------------------------------------------------------------------------------- /tests/0v/07-use-after-free/300-FAIL-struct-free-ptr-dangling.x.EXPECTED: -------------------------------------------------------------------------------- 1 | stdio.h:18:39: precondition failure: argument of `s' must be lvalue (puts) 2 | 07-use-after-free/300-FAIL-struct-free-ptr-dangling.x:45:18 (create_report) 3 | -------------------------------------------------------------------------------- /tests/0v/07-use-after-free/400-FAIL-conditions-in-setup.x: -------------------------------------------------------------------------------- 1 | void 2 | modify2(int *q, int x) ~ [ 3 | setup: if (x) { q = .clump(1); } /* ERROR: setup must be decidable */ 4 | if (x) { 5 | *q = 2; 6 | } 7 | ] { 8 | if (x) { 9 | *q = 2; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /tests/0v/07-use-after-free/400-FAIL-conditions-in-setup.x.EXPECTED: -------------------------------------------------------------------------------- 1 | 07-use-after-free/400-FAIL-conditions-in-setup.x:4:3: setup preconditions must be decidable (modify2) 2 | -------------------------------------------------------------------------------- /tests/0v/08-uninitialised-memory/000-FAIL-uninitialised-memory-rval.x: -------------------------------------------------------------------------------- 1 | void 2 | main() 3 | { 4 | int i; 5 | int j; 6 | 7 | i = j; 8 | } 9 | -------------------------------------------------------------------------------- /tests/0v/08-uninitialised-memory/000-FAIL-uninitialised-memory-rval.x.EXPECTED: -------------------------------------------------------------------------------- 1 | 08-uninitialised-memory/000-FAIL-uninitialised-memory-rval.x:7:7: undefined memory access: j has no value (main) 2 | -------------------------------------------------------------------------------- /tests/0v/08-uninitialised-memory/001-FAIL-uninitialised-memory-rval.x: -------------------------------------------------------------------------------- 1 | void 2 | undefined_memory1() 3 | { 4 | int *p; 5 | int *q; 6 | 7 | q = *p; 8 | } 9 | -------------------------------------------------------------------------------- /tests/0v/08-uninitialised-memory/001-FAIL-uninitialised-memory-rval.x.EXPECTED: -------------------------------------------------------------------------------- 1 | 08-uninitialised-memory/001-FAIL-uninitialised-memory-rval.x:7:8: undefined indirection: p has no value (undefined_memory1) 2 | -------------------------------------------------------------------------------- /tests/0v/08-uninitialised-memory/002-FAIL-uninitialised-memory-rval.x: -------------------------------------------------------------------------------- 1 | void 2 | undefined_memory2() 3 | { 4 | int p; 5 | int *q; 6 | int r; 7 | 8 | q = &p; 9 | r = *q; /* ERROR: undefined indirection */ 10 | } 11 | -------------------------------------------------------------------------------- /tests/0v/08-uninitialised-memory/002-FAIL-uninitialised-memory-rval.x.EXPECTED: -------------------------------------------------------------------------------- 1 | 08-uninitialised-memory/002-FAIL-uninitialised-memory-rval.x:9:8: undefined memory access: *(q) has no value (undefined_memory2) 2 | -------------------------------------------------------------------------------- /tests/0v/08-uninitialised-memory/003-FAIL-uninitialised-memory-rval.x: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void 4 | undefined_memory3() 5 | { 6 | int *p; 7 | int *q; 8 | p = malloc(5); 9 | 10 | q = *p; /* ERROR: cannot dereference wild pointer */ 11 | } 12 | -------------------------------------------------------------------------------- /tests/0v/08-uninitialised-memory/003-FAIL-uninitialised-memory-rval.x.EXPECTED: -------------------------------------------------------------------------------- 1 | 08-uninitialised-memory/003-FAIL-uninitialised-memory-rval.x:10:8: undefined memory access: *(p) has no value (undefined_memory3) 2 | -------------------------------------------------------------------------------- /tests/0v/08-uninitialised-memory/004-FAIL-uninitialised-memory-rval.x: -------------------------------------------------------------------------------- 1 | int 2 | func(int i) ~ [ 3 | return i; 4 | ]{ 5 | return i; 6 | } 7 | 8 | int 9 | main() 10 | { 11 | int i; 12 | func(i); 13 | } 14 | -------------------------------------------------------------------------------- /tests/0v/08-uninitialised-memory/004-FAIL-uninitialised-memory-rval.x.EXPECTED: -------------------------------------------------------------------------------- 1 | 08-uninitialised-memory/004-FAIL-uninitialised-memory-rval.x:12:9: undefined memory access: i has no value (main) 2 | -------------------------------------------------------------------------------- /tests/0v/09-calls/000-complex-call-expressions.x: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int 4 | f(int x, int y) ~ [ return 0; ] 5 | { 6 | return 0; 7 | } 8 | 9 | int 10 | g(int x) ~ [ return 1; ] 11 | { 12 | return 1; 13 | } 14 | 15 | int 16 | h(int x, int y) ~ [ return 2; ] 17 | { 18 | return 2; 19 | } 20 | 21 | void * 22 | test(int x, int y) ~ [ return .malloc(1); ] 23 | { 24 | if (f(g(x), h(f(x, y), f(g(x), y)))) { 25 | return malloc(1); 26 | } 27 | return malloc(1); 28 | } 29 | -------------------------------------------------------------------------------- /tests/0v/09-calls/100-FAIL-unique-rconst.x: -------------------------------------------------------------------------------- 1 | int 2 | f(int x) ~ [ return [0?2]; ] 3 | { 4 | return 0; 5 | } 6 | 7 | int 8 | g() 9 | { 10 | int a; int b; 11 | 12 | a = f(0); /* "f{0}:0" */ 13 | b = f(1); /* "f{1}:0" */ 14 | 15 | ~ [ a != b; ] 16 | } 17 | -------------------------------------------------------------------------------- /tests/0v/09-calls/100-FAIL-unique-rconst.x.EXPECTED: -------------------------------------------------------------------------------- 1 | TODO 2 | -------------------------------------------------------------------------------- /tests/0v/09-calls/110-unique-rconst.x: -------------------------------------------------------------------------------- 1 | int 2 | f(int x) ~ [ return [0?2]; ] 3 | { 4 | return 0; 5 | } 6 | 7 | int 8 | g() 9 | { 10 | int a; int b; 11 | 12 | a = f(0); 13 | b = f(0); 14 | 15 | ~ [ a == b; ] 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /tests/0v/09-calls/120-FAIL-unique-rconst.x: -------------------------------------------------------------------------------- 1 | int 2 | f(int x) ~ [ return [0?2]; ] 3 | { 4 | return 0; 5 | } 6 | 7 | int 8 | g(int x, int y) 9 | { 10 | int a; int b; 11 | 12 | a = f(x); /* "f:{($0, [?])}:0" */ 13 | b = f(y); /* "f:{($1, [?])}:0" */ 14 | 15 | ~ [ a == b; ] 16 | } 17 | -------------------------------------------------------------------------------- /tests/0v/09-calls/120-FAIL-unique-rconst.x.EXPECTED: -------------------------------------------------------------------------------- 1 | TODO 2 | -------------------------------------------------------------------------------- /tests/0v/09-calls/130-unique-rconst.x: -------------------------------------------------------------------------------- 1 | int 2 | f(int x) ~ [ return [0?2]; ] 3 | { 4 | return 0; 5 | } 6 | 7 | int 8 | g(int x, int y) ~ [ 9 | setup: { 10 | x = [0?2]; 11 | y = [0?2]; 12 | } 13 | ]{ 14 | int a; int b; 15 | 16 | if (x != y) { 17 | return 0; 18 | } 19 | 20 | a = f(x); /* "f:{($0, [?])}:0" */ 21 | b = f(y); /* "f:{($1, [?])}:0" */ 22 | 23 | ~ [ a == b; ] 24 | } 25 | -------------------------------------------------------------------------------- /tests/0v/09-calls/200-FAIL-wrong-range.x: -------------------------------------------------------------------------------- 1 | int 2 | f(int x) ~ [ return [0?2]; ] 3 | { 4 | return 4; 5 | } 6 | -------------------------------------------------------------------------------- /tests/0v/09-calls/200-FAIL-wrong-range.x.EXPECTED: -------------------------------------------------------------------------------- 1 | TODO 2 | -------------------------------------------------------------------------------- /tests/0v/09-calls/300-call-branch.x: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void * 4 | foo(int flag) ~ [ if (flag) return malloc(1); ] 5 | { 6 | int k; int *p; void *q; 7 | 8 | p = &k; 9 | if (flag) { 10 | *p = 0; 11 | } else { 12 | *p = 1; 13 | } 14 | q = malloc(1); 15 | if (k) { 16 | free(q); 17 | } 18 | return q; 19 | } 20 | 21 | void 22 | bar(int val) 23 | { 24 | void *p; 25 | 26 | p = foo(val); 27 | if (val) { 28 | free(p); 29 | } 30 | } 31 | 32 | void 33 | main() 34 | { 35 | bar(1); 36 | } 37 | -------------------------------------------------------------------------------- /tests/0v/09-calls/400-FAIL-no-return-value.x: -------------------------------------------------------------------------------- 1 | int 2 | f() 3 | { 4 | int k; 5 | 6 | return k; 7 | } 8 | -------------------------------------------------------------------------------- /tests/0v/09-calls/400-FAIL-no-return-value.x.EXPECTED: -------------------------------------------------------------------------------- 1 | 09-calls/400-FAIL-no-return-value.x:6:10: returned expression has no value (f) 2 | -------------------------------------------------------------------------------- /tests/0v/10-bounds-cbci/000-FAIL-constant.x: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void 4 | foo() 5 | { 6 | int i; int *p; 7 | p = &i; 8 | p[1] = 1; 9 | } 10 | -------------------------------------------------------------------------------- /tests/0v/10-bounds-cbci/000-FAIL-constant.x.EXPECTED: -------------------------------------------------------------------------------- 1 | 10-bounds-cbci/000-FAIL-constant.x:8:10: out of bounds (foo) 2 | -------------------------------------------------------------------------------- /tests/0v/10-bounds-cbci/010-FAIL-constant-malloc.x: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void 4 | foo() 5 | { 6 | int *p; 7 | p = malloc(5); 8 | p[0] = 5; 9 | p[1] = 4; 10 | p[2] = 3; 11 | p[3] = 2; 12 | p[4] = 1; 13 | p[5] = 0; 14 | } 15 | -------------------------------------------------------------------------------- /tests/0v/10-bounds-cbci/010-FAIL-constant-malloc.x.EXPECTED: -------------------------------------------------------------------------------- 1 | 10-bounds-cbci/010-FAIL-constant-malloc.x:13:10: out of bounds (foo) 2 | -------------------------------------------------------------------------------- /tests/0v/10-bounds-cbci/020-FAIL-2D-constant-malloc.x: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void 4 | foo() 5 | { 6 | int **p; 7 | int res; 8 | int temp; 9 | p = malloc(2); 10 | p[1] = malloc(3); 11 | 12 | *p[1] = 1; 13 | *(p[1]+1) = 2; 14 | *(p[1]+2) = 3; 15 | temp = *p[1]; 16 | ~ [ temp == 1; ] 17 | temp = *(p[1]+1); 18 | ~ [ temp == 2; ] 19 | temp = *(p[1]+2); 20 | ~ [ temp == 3; ] /* XXX: broken */ 21 | 22 | *(p[1]+3) = 3; /* ERROR: out of bounds */ 23 | } 24 | -------------------------------------------------------------------------------- /tests/0v/10-bounds-cbci/020-FAIL-2D-constant-malloc.x.EXPECTED: -------------------------------------------------------------------------------- 1 | 10-bounds-cbci/020-FAIL-2D-constant-malloc.x:22:15: out of bounds (foo) 2 | -------------------------------------------------------------------------------- /tests/0v/10-bounds-cbci/100-1D-array.x: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int 4 | foo() 5 | { 6 | char a[4]; 7 | a[2] = 7; 8 | return 0; 9 | } 10 | -------------------------------------------------------------------------------- /tests/0v/10-bounds-cbci/200-2D-array.x: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int 4 | foo() 5 | { 6 | char c; 7 | char *a[4][3]; 8 | a[0][0] = &c; 9 | a[1][7] = a[0][0]; 10 | *a[1][7] = 5; 11 | /* ~ [ *a[1][7] == 5; ]; */ /*XXX: expand verify */ 12 | return 0; 13 | } 14 | -------------------------------------------------------------------------------- /tests/0v/10-bounds-cbci/201-2D-array-odd-but-true.x: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int 4 | foo() 5 | { 6 | char c; 7 | char d; 8 | 9 | char *a[4][3]; 10 | a[0][11] = &c; 11 | a[1][8] = &d; 12 | return 0; 13 | } 14 | -------------------------------------------------------------------------------- /tests/0v/10-bounds-cbci/210-FAIL-2D-array.x: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int 4 | foo() 5 | { 6 | char c; 7 | char *a[4][3]; 8 | a[4][0] = &c; 9 | } 10 | -------------------------------------------------------------------------------- /tests/0v/10-bounds-cbci/210-FAIL-2D-array.x.EXPECTED: -------------------------------------------------------------------------------- 1 | 10-bounds-cbci/210-FAIL-2D-array.x:8:14: out of bounds (foo) 2 | -------------------------------------------------------------------------------- /tests/0v/10-bounds-cbci/220-3D-array.x: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int 4 | foo() 5 | { 6 | int *i; 7 | int *a[2][2][2]; 8 | 9 | i = malloc(1); 10 | *i = 2; 11 | a[1][1][1] = i; 12 | /* ~ [ *a[1][1][1] == 2; ] */ /* XXX: expand verify */ 13 | free(i); 14 | return 0; 15 | } 16 | -------------------------------------------------------------------------------- /tests/0v/11-bounds-cbvi/000-setup-constant-safe.x: -------------------------------------------------------------------------------- 1 | void 2 | foo(int index) ~ [ setup: index = 0; ] 3 | { 4 | int k; 5 | (&k)[index] = index; 6 | } 7 | -------------------------------------------------------------------------------- /tests/0v/11-bounds-cbvi/100-setup-range-trivial.x: -------------------------------------------------------------------------------- 1 | void 2 | foo(int index) ~ [ setup: index = [1?2]; ] 3 | { 4 | int k; 5 | (&k)[index-1] = index; 6 | } 7 | -------------------------------------------------------------------------------- /tests/0v/11-bounds-cbvi/110-setup-range-trivial.x: -------------------------------------------------------------------------------- 1 | void 2 | foo(int index) ~ [ setup: index = [0?2]; ] 3 | { 4 | int arr[2]; 5 | arr[0] = 1; 6 | arr[index] = 2; 7 | } 8 | -------------------------------------------------------------------------------- /tests/0v/11-bounds-cbvi/120-binary-index-split-constant-first.x: -------------------------------------------------------------------------------- 1 | foo(int index) ~ [ setup: index = [0?2]; ] 2 | { 3 | int arr[2]; 4 | arr[0] = 1; 5 | arr[index] = 2; 6 | if (index) { 7 | ~ [ arr[0] == 1; arr[1] == 2; ] 8 | arr[1]; 9 | } else { 10 | ~ [ arr[0] == 2; ] 11 | arr[0]; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /tests/0v/11-bounds-cbvi/121-FAIL-binary-index-split-constant-first.x: -------------------------------------------------------------------------------- 1 | foo(int index) ~ [ setup: index = [0?2]; ] 2 | { 3 | int arr[2]; 4 | arr[0] = 1; 5 | arr[index] = 2; 6 | arr[0] = arr[1]; /* potentially uninitialised */ 7 | } 8 | -------------------------------------------------------------------------------- /tests/0v/11-bounds-cbvi/121-FAIL-binary-index-split-constant-first.x.EXPECTED: -------------------------------------------------------------------------------- 1 | 11-bounds-cbvi/121-FAIL-binary-index-split-constant-first.x:6:24: undefined memory access: *(arr+1) has no value (foo | #0 ∈ {0}) 2 | -------------------------------------------------------------------------------- /tests/0v/11-bounds-cbvi/130-binary-index-split-rconst-first.x: -------------------------------------------------------------------------------- 1 | foo(int index) ~ [ setup: index = [0?2]; ] 2 | { 3 | int x; 4 | int arr[2]; 5 | arr[index] = 2; 6 | arr[0] = 1; 7 | ~ [ arr[0] == 1; ] 8 | x = arr[0]; 9 | if (index) { 10 | ~ [ arr[1] == 2; ] 11 | x = arr[1]; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /tests/0v/11-bounds-cbvi/140-binary-value-split-constant-first.x: -------------------------------------------------------------------------------- 1 | foo(int index) ~ [ setup: index = [0?2]; ] 2 | { 3 | int arr[2]; 4 | arr[0] = 0; 5 | arr[index] = 1; 6 | if (arr[0]) { 7 | ~ [ index == 0; ] 8 | } else { 9 | ~ [ index == 1; ] 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /tests/0v/11-bounds-cbvi/150-binary-value-split-constant-first.x: -------------------------------------------------------------------------------- 1 | foo(int index) ~ [ setup: index = [0?2]; ] 2 | { 3 | int k, arr[2]; 4 | arr[0] = 0; 5 | arr[1] = 1; 6 | k = arr[index]; 7 | } 8 | -------------------------------------------------------------------------------- /tests/0v/11-bounds-cbvi/151-FAIL-binary-value-split-constant-first.x: -------------------------------------------------------------------------------- 1 | foo(int index) ~ [ setup: index = [0?2]; ] 2 | { 3 | int k, arr[2]; 4 | arr[1] = 1; 5 | k = arr[index]; /* arr[0] not defined */ 6 | } 7 | -------------------------------------------------------------------------------- /tests/0v/11-bounds-cbvi/151-FAIL-binary-value-split-constant-first.x.EXPECTED: -------------------------------------------------------------------------------- 1 | 11-bounds-cbvi/151-FAIL-binary-value-split-constant-first.x:5:23: undefined memory access: *(arr+index) has no value (foo | #0 ∈ {0}) 2 | -------------------------------------------------------------------------------- /tests/0v/11-bounds-cbvi/200-FAIL-binary-binary-value-split.x: -------------------------------------------------------------------------------- 1 | foo(int i, int j) ~ [ 2 | setup: { 3 | i = [0?2]; 4 | j = [0?2]; 5 | } 6 | ]{ 7 | int k, arr[2]; 8 | arr[0] = 0; 9 | arr[i] = 2; 10 | arr[j] = 3; 11 | k = arr[0]; 12 | k = arr[1]; 13 | } 14 | -------------------------------------------------------------------------------- /tests/0v/11-bounds-cbvi/200-FAIL-binary-binary-value-split.x.EXPECTED: -------------------------------------------------------------------------------- 1 | 11-bounds-cbvi/200-FAIL-binary-binary-value-split.x:12:19: undefined memory access: *(arr+1) has no value (foo | #0 ∈ {0} | #1 ∈ {0}) 2 | -------------------------------------------------------------------------------- /tests/0v/11-bounds-cbvi/210-FAIL-overflow.x: -------------------------------------------------------------------------------- 1 | foo(int i) ~ [ setup: i = [0?5]; ] 2 | { 3 | int arr[2]; 4 | arr[i] = 0; 5 | } 6 | -------------------------------------------------------------------------------- /tests/0v/11-bounds-cbvi/210-FAIL-overflow.x.EXPECTED: -------------------------------------------------------------------------------- 1 | 11-bounds-cbvi/210-FAIL-overflow.x:4:19: out of bounds (foo) 2 | -------------------------------------------------------------------------------- /tests/0v/11-bounds-cbvi/220-less-than-restrict.x: -------------------------------------------------------------------------------- 1 | foo(int i) ~ [ setup: i = [0?5]; ] 2 | { 3 | int arr[2]; 4 | if (i < 2) { 5 | arr[i] = 0; 6 | } 7 | } 8 | 9 | bar(int i) ~ [ setup: i = [0?5]; ] 10 | { 11 | int arr[2]; 12 | if (!(i >= 2)) { 13 | arr[i] = 0; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /tests/0v/11-bounds-cbvi/221-equal-restrict.x: -------------------------------------------------------------------------------- 1 | foo(int i) ~ [ setup: i = [0?5]; ] 2 | { 3 | int arr[2]; 4 | if (i == 1) { 5 | arr[i] = 0; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /tests/0v/11-bounds-cbvi/230-less-than-equal.x: -------------------------------------------------------------------------------- 1 | foo(int i) ~ [ setup: i = [0?5]; ] 2 | { 3 | int arr[2]; 4 | if (i <= 1) { 5 | arr[i] = 0; 6 | } 7 | } 8 | 9 | foo(int i) ~ [ setup: i = [0?5]; ] 10 | { 11 | int arr[2]; 12 | if (!(i > 1)) { 13 | arr[i] = 0; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /tests/0v/11-bounds-cbvi/300-FAIL-basic.x: -------------------------------------------------------------------------------- 1 | int 2 | index() ~ [ return [0?50]; ] 3 | { 4 | return 2; 5 | } 6 | 7 | int 8 | main() 9 | { 10 | int a[3]; 11 | int i; 12 | int res; 13 | a[0] = 4; 14 | a[1] = 5; 15 | a[2] = 6; 16 | 17 | i = index(); 18 | res = a[i]; /* ERROR: `i' could be out of bounds */ 19 | } 20 | -------------------------------------------------------------------------------- /tests/0v/11-bounds-cbvi/300-FAIL-basic.x.EXPECTED: -------------------------------------------------------------------------------- 1 | 11-bounds-cbvi/300-FAIL-basic.x:18:12: out of bounds (main) 2 | -------------------------------------------------------------------------------- /tests/0v/11-bounds-cbvi/310-FAIL-less-than-restrict.x: -------------------------------------------------------------------------------- 1 | void 2 | foo(int i) ~ [ setup: i = [0?5]; ] 3 | { 4 | int arr[2]; 5 | if (i < 3) { 6 | arr[i] = 0; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /tests/0v/11-bounds-cbvi/310-FAIL-less-than-restrict.x.EXPECTED: -------------------------------------------------------------------------------- 1 | 11-bounds-cbvi/310-FAIL-less-than-restrict.x:5:3: out of bounds (foo | #0 ∈ {0?3}) 2 | -------------------------------------------------------------------------------- /tests/0v/11-bounds-cbvi/320-FAIL-less-than-equal-restrict.x: -------------------------------------------------------------------------------- 1 | foo(int i) ~ [ setup: i = [0?5]; ] 2 | { 3 | int arr[2]; 4 | if (i <= 2) { 5 | arr[i] = 0; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /tests/0v/11-bounds-cbvi/320-FAIL-less-than-equal-restrict.x.EXPECTED: -------------------------------------------------------------------------------- 1 | 11-bounds-cbvi/320-FAIL-less-than-equal-restrict.x:4:3: out of bounds (foo | #0 ∈ {2?5} | #0 ∈ {2}) 2 | -------------------------------------------------------------------------------- /tests/0v/11-bounds-cbvi/400-less-than-greater-than-restrict.x: -------------------------------------------------------------------------------- 1 | int 2 | index() 3 | { 4 | return 2; 5 | } 6 | 7 | int 8 | main() 9 | { 10 | int a[4]; 11 | int i; 12 | int res; 13 | a[0] = 4; 14 | a[1] = 5; 15 | a[2] = 6; 16 | a[3] = 7; 17 | 18 | i = index(); 19 | if (i < 0) { 20 | return 0; 21 | } 22 | if (i > 3) { 23 | return 0; 24 | } 25 | res = a[i]; 26 | ~ [ res == a[i]; ] 27 | return 0; 28 | } 29 | -------------------------------------------------------------------------------- /tests/0v/12-bounds-vbci/000-FAIL-no-setup.x: -------------------------------------------------------------------------------- 1 | void 2 | access(int *arr) 3 | { 4 | arr[0] = 1; 5 | } 6 | -------------------------------------------------------------------------------- /tests/0v/12-bounds-vbci/000-FAIL-no-setup.x.EXPECTED: -------------------------------------------------------------------------------- 1 | 12-bounds-vbci/000-FAIL-no-setup.x:4:12: cannot add to invalid pointer (access) 2 | -------------------------------------------------------------------------------- /tests/0v/12-bounds-vbci/010-FAIL-off-by-one.x: -------------------------------------------------------------------------------- 1 | void 2 | access(int *arr) ~ [ setup: arr = .clump(1); ] 3 | { 4 | arr[1] = 1; 5 | } 6 | -------------------------------------------------------------------------------- /tests/0v/12-bounds-vbci/010-FAIL-off-by-one.x.EXPECTED: -------------------------------------------------------------------------------- 1 | 12-bounds-vbci/010-FAIL-off-by-one.x:4:12: out of bounds (access) 2 | -------------------------------------------------------------------------------- /tests/0v/12-bounds-vbci/020-within-bounds.x: -------------------------------------------------------------------------------- 1 | void 2 | access(int *arr) ~ [ 3 | setup: arr = .clump(1); 4 | arr[0] = 1; 5 | ]{ 6 | arr[0] = 1; 7 | } 8 | -------------------------------------------------------------------------------- /tests/0v/12-bounds-vbci/021-within-bounds.x: -------------------------------------------------------------------------------- 1 | void 2 | access(int *arr) ~ [ 3 | setup: arr = .clump(2); 4 | arr[1] = 1; 5 | ]{ 6 | arr[1] = 1; 7 | } 8 | -------------------------------------------------------------------------------- /tests/0v/12-bounds-vbci/030-within-bounds-minus-one.x: -------------------------------------------------------------------------------- 1 | void 2 | access(int *arr) ~ [ 3 | setup: arr = .clump(1) - 1; 4 | arr[1] = 1; 5 | ]{ 6 | arr[1] = 1; 7 | } 8 | -------------------------------------------------------------------------------- /tests/0v/12-bounds-vbci/031-within-bounds-minus-one-abstract-rconst.x: -------------------------------------------------------------------------------- 1 | void 2 | access(int *arr) ~ [ 3 | setup: arr = .clump(1) - 1; 4 | arr[1] = [?]; 5 | ]{ 6 | arr[1] = 1; 7 | } 8 | -------------------------------------------------------------------------------- /tests/0v/12-bounds-vbci/040-within-bounds-minus-five.x: -------------------------------------------------------------------------------- 1 | void 2 | access(int *arr) ~ [ 3 | setup: arr = .clump(5) - 5; 4 | arr[5] = 1; 5 | arr[7] = 1; 6 | ]{ 7 | arr[5] = 1; 8 | arr[7] = 1; 9 | } 10 | -------------------------------------------------------------------------------- /tests/0v/12-bounds-vbci/100-caller-stack-variable.x: -------------------------------------------------------------------------------- 1 | void 2 | access(int *arr) ~ [ 3 | setup: arr = .clump(1) - 1; 4 | arr[1] = 1; 5 | ]{ 6 | arr[1] = 1; 7 | } 8 | 9 | void 10 | f() 11 | { 12 | int k; 13 | access(&k-1); 14 | } 15 | -------------------------------------------------------------------------------- /tests/0v/12-bounds-vbci/110-caller-stack-variable.x: -------------------------------------------------------------------------------- 1 | int 2 | getval(int *arr) ~ [ 3 | setup: { 4 | arr = .clump(1) - 1; 5 | arr[1] = [?]; 6 | } 7 | return arr[1]; 8 | ]{ 9 | return arr[1]; 10 | } 11 | 12 | void 13 | f() 14 | { 15 | int k; 16 | k = 0; 17 | getval(&k-1); 18 | } 19 | -------------------------------------------------------------------------------- /tests/0v/12-bounds-vbci/120-FAIL-spec-requires-larger-block.x: -------------------------------------------------------------------------------- 1 | int 2 | getval(int *arr) ~ [ 3 | setup: { 4 | arr = .clump(2) - 1; 5 | arr[1] = [?]; 6 | } 7 | return arr[1]; 8 | ]{ 9 | return arr[1]; 10 | } 11 | 12 | void 13 | f() 14 | { 15 | int k; 16 | k = 0; 17 | getval(&k-1); 18 | } 19 | -------------------------------------------------------------------------------- /tests/0v/12-bounds-vbci/120-FAIL-spec-requires-larger-block.x.EXPECTED: -------------------------------------------------------------------------------- 1 | 12-bounds-vbci/120-FAIL-spec-requires-larger-block.x:6:2: precondition failure: argument of `arr' must point at larger block (getval) 2 | 12-bounds-vbci/120-FAIL-spec-requires-larger-block.x:17:14 (f) 3 | -------------------------------------------------------------------------------- /tests/0v/20-declarators/000-declaration-list.x: -------------------------------------------------------------------------------- 1 | void 2 | foo() 3 | { 4 | int i, j; 5 | i = 5; 6 | j = 4; 7 | ~ [ i == 5; ] 8 | ~ [ j == 4; ] 9 | } 10 | -------------------------------------------------------------------------------- /tests/0v/20-declarators/100-declaration-init.x: -------------------------------------------------------------------------------- 1 | void 2 | foo() 3 | { 4 | int i = 5, j = 4; 5 | ~ [ i == 5; j == 4; ] 6 | } 7 | -------------------------------------------------------------------------------- /tests/0v/30-topological/000-valid-sort-empty.x: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int 5 | main() 6 | { 7 | return NULL; 8 | } 9 | 10 | -------------------------------------------------------------------------------- /tests/0v/30-topological/000-valid-sort-empty.x.EXPECTED: -------------------------------------------------------------------------------- 1 | main 2 | -------------------------------------------------------------------------------- /tests/0v/30-topological/001-valid-sort-matrix.x: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | struct matrix { 5 | int rows; int cols; 6 | int **data; 7 | }; 8 | 9 | struct matrix * 10 | matrix_create(int rows, int cols) ~ [ 11 | int i; 12 | struct matrix *m; 13 | 14 | m = .malloc(sizeof(struct matrix)); 15 | m->rows = rows; 16 | m->cols = cols; 17 | m->data = .malloc(sizeof(int *) * rows); 18 | for (i = 0; i < m->rows; i++) { 19 | m->data[i] = .malloc(1); 20 | } 21 | return m; 22 | ]; 23 | 24 | struct matrix * 25 | matrix_create(int rows, int cols) 26 | { 27 | int i; 28 | struct matrix *m; 29 | 30 | m = malloc(sizeof(struct matrix)); 31 | 32 | m->rows = rows; 33 | m->cols = cols; 34 | 35 | m->data = malloc(sizeof(int *) * rows); 36 | for (i = 0; i < m->rows; i++) ~ [ m->data[i] = .malloc(1); ] { 37 | m->data[i] = malloc(sizeof(int) * cols); 38 | } 39 | 40 | return m; 41 | } 42 | 43 | void 44 | matrix_destroy(struct matrix *m) ~ [ 45 | int i; 46 | 47 | setup: m = matrix_create([?], [?]); 48 | 49 | for (i = 0; i < m->rows; i++) { 50 | .free(m->data[i]); 51 | } 52 | .free(m->data); 53 | .free(m); 54 | ]{ 55 | int i; 56 | 57 | for (i = 0; i < m->rows; i++) ~ [ .free(m->data[i]); ] { 58 | free(m->data[i]); 59 | } 60 | free(m->data); 61 | free(m); 62 | } 63 | 64 | struct matrix * 65 | matrix_add(struct matrix *m1, struct matrix *m2) ~ [ 66 | int i; 67 | struct matrix *sum; 68 | 69 | setup: { 70 | m1 = matrix_create([?], [?]); 71 | m2 = matrix_create([?], [?]); 72 | } 73 | 74 | sum = .malloc(sizeof(struct matrix)); 75 | sum->rows = m1->rows; 76 | sum->cols = m1->cols; 77 | sum->data = .malloc(sizeof(int *) * rows); 78 | for (i = 0; i < sum->rows; i++) { 79 | sum->data[i] = .malloc(1); 80 | } 81 | return sum; 82 | ]{ 83 | int i; int j; 84 | struct matrix *res; 85 | 86 | /*assert(m1->rows == m2->rows && m1->cols == m2->cols);*/ 87 | 88 | res = matrix_create(m1->rows, m1->cols); 89 | for (i = 0; i < res->rows; i++) { 90 | for (j = 0; j < m1->cols; j++) { 91 | res->data[i][j] = m1->data[i][j] + m2->data[i][j]; 92 | } 93 | } 94 | return res; 95 | } 96 | 97 | void 98 | matrix_print(struct matrix *m) ~ [ 99 | setup: m = matrix_create([?], [?]); 100 | ] { 101 | int i; int j; int digit; 102 | 103 | for (i = 0; i < m->rows; i++) { 104 | for (j = 0; j < m->cols; j++) { 105 | digit = m->data[i][j] + '0'; 106 | putchar(digit); 107 | } 108 | puts("\n"); 109 | } 110 | puts("\n"); 111 | } 112 | 113 | int 114 | main() 115 | { 116 | struct matrix *m1; 117 | struct matrix *m2; 118 | struct matrix *sum; 119 | 120 | puts("matrix program:\n"); 121 | m1 = matrix_create(2, 2); 122 | ~ [ @m1; ] 123 | 124 | m1->data[0][0] = 1; 125 | m1->data[0][1] = 2; 126 | m1->data[1][0] = 3; 127 | m1->data[1][1] = 4; 128 | puts("m1:\n"); 129 | matrix_print(m1); 130 | 131 | m2 = matrix_create(2, 2); 132 | ~ [ @m1; @m2; ] 133 | 134 | m2->data[0][0] = 1; 135 | m2->data[0][1] = 1; 136 | m2->data[1][0] = 1; 137 | m2->data[1][1] = 1; 138 | puts("m2:\n"); 139 | matrix_print(m2); 140 | 141 | sum = matrix_add(m1, m2); 142 | ~ [ @m1; @m2; @sum; ] 143 | 144 | puts("sum:\n"); 145 | matrix_print(sum); 146 | 147 | matrix_destroy(sum); 148 | ~ [ @m1; @m2; !@sum; ] 149 | matrix_destroy(m2); 150 | ~ [ @m1; !@m2; !@sum; ] 151 | matrix_destroy(m1); 152 | ~ [ !@m1; !@m2; !@sum; ] 153 | } 154 | -------------------------------------------------------------------------------- /tests/0v/30-topological/001-valid-sort-matrix.x.EXPECTED: -------------------------------------------------------------------------------- 1 | matrix_create, matrix_print, matrix_destroy, matrix_add, main 2 | -------------------------------------------------------------------------------- /tests/0v/30-topological/002-valid-sort-parse.x.EXPECTED: -------------------------------------------------------------------------------- 1 | read_file, skipws, beginsdefs, substr, skiplinespace, pattern_create, token_create, lexer_create, pattern_print, token_print, lexer_destroy, parse_defsraw, parse_id, parse_tonewline, parse_token_literal, parse_action, parse_toeof, lexer_print, skipoptions, parse_token_id, parse_token_pattern, parse_pattern, parse_name, count_patterns, parse_defs_n, parse_token, parse_defsproper, count_tokens, parse_rules_n, parse_defs, parse_rules, parse, main 2 | -------------------------------------------------------------------------------- /tests/0v/30-topological/010-FAIL-cycle.x: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void 5 | main(); 6 | 7 | void * 8 | func2() 9 | { 10 | main(); 11 | return NULL; 12 | } 13 | 14 | void * 15 | func3(); 16 | 17 | void * 18 | main() 19 | { 20 | func3(); 21 | return NULL; 22 | } 23 | 24 | void * 25 | func3() 26 | { 27 | return func2(); 28 | } 29 | -------------------------------------------------------------------------------- /tests/0v/30-topological/010-FAIL-cycle.x.EXPECTED: -------------------------------------------------------------------------------- 1 | cycle detected in graph 2 | -------------------------------------------------------------------------------- /tests/0v/30-topological/020-FAIL-non-existant-funcname.x: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void * 5 | main2() 6 | { 7 | return NULL; 8 | } 9 | -------------------------------------------------------------------------------- /tests/0v/30-topological/020-FAIL-non-existant-funcname.x.EXPECTED: -------------------------------------------------------------------------------- 1 | function `main' is not declared 2 | -------------------------------------------------------------------------------- /tests/0v/30-topological/args: -------------------------------------------------------------------------------- 1 | -t main 2 | -------------------------------------------------------------------------------- /tests/0v/31-topological-verification/003-valid-sort-inorder-verification.x: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | char * 5 | bar() ~ [ return malloc(sizeof(char) * 10); ]; 6 | 7 | int * 8 | foo() ~ [ return malloc(sizeof(int)); ]; 9 | 10 | int 11 | main() 12 | { 13 | int *i; 14 | char *s; 15 | 16 | i = foo(); 17 | s = bar(); 18 | free(s); 19 | free(i); 20 | return 0; 21 | } 22 | 23 | int * 24 | foo() 25 | { 26 | return malloc(sizeof(int)); 27 | } 28 | 29 | int * 30 | bar() 31 | { 32 | return foo(); 33 | } 34 | -------------------------------------------------------------------------------- /tests/0v/31-topological-verification/003-valid-sort-inorder-verification.x.EXPECTED: -------------------------------------------------------------------------------- 1 | foo, bar, main 2 | qed foo 3 | qed bar 4 | qed main 5 | -------------------------------------------------------------------------------- /tests/0v/31-topological-verification/args: -------------------------------------------------------------------------------- 1 | -x main -v 2 | -------------------------------------------------------------------------------- /tests/0v/40-type-checking/000-FAIL-void-return.x: -------------------------------------------------------------------------------- 1 | void 2 | foo() 3 | { 4 | return 1; 5 | } 6 | -------------------------------------------------------------------------------- /tests/0v/40-type-checking/000-FAIL-void-return.x.EXPECTED: -------------------------------------------------------------------------------- 1 | 40-type-checking/000-FAIL-void-return.x:4:10: cannot return int as void (foo) 2 | -------------------------------------------------------------------------------- /tests/0v/99-program/.vimrc: -------------------------------------------------------------------------------- 1 | " Set the default filetype for .h files to C 2 | autocmd BufNewFile,BufRead *.h set filetype=xr0 3 | -------------------------------------------------------------------------------- /tests/0v/99-program/000-matrix.x: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | struct matrix { 5 | int rows; int cols; 6 | int **data; 7 | }; 8 | 9 | struct matrix * 10 | matrix_create(int rows, int cols) ~ [ 11 | struct matrix *m; 12 | int i; 13 | 14 | m = .malloc(sizeof(struct matrix)); 15 | m->data = .malloc(sizeof(int *) * rows); 16 | m->rows = rows; 17 | m->cols = cols; 18 | for (i = 0; i < m->rows; i++) { 19 | m->data[i] = .malloc(sizeof(int)); 20 | } 21 | return m; 22 | ]{ 23 | int i; 24 | struct matrix *m; 25 | 26 | m = malloc(sizeof(struct matrix)); 27 | 28 | m->rows = rows; 29 | m->cols = cols; 30 | 31 | m->data = malloc(sizeof(int *) * rows); 32 | for (i = 0; i < rows; i++) ~ [ m->data[i] = .malloc(sizeof(int *) * cols); ] { 33 | m->data[i] = malloc(sizeof(int *) * cols); 34 | } 35 | return m; 36 | } 37 | 38 | void 39 | matrix_destroy(struct matrix *m) ~ [ 40 | int i; 41 | 42 | setup: m = matrix_create([?], [?]); 43 | 44 | for (i = 0; i < m->rows; i++) { 45 | .free(m->data[i]); 46 | } 47 | .free(m->data); 48 | .free(m); 49 | ]{ 50 | int i; 51 | 52 | for (i = 0; i < m->rows; i++) ~ [ .free(m->data[i]); ] { 53 | free(m->data[i]); 54 | } 55 | free(m->data); 56 | free(m); 57 | } 58 | 59 | struct matrix * 60 | matrix_add(struct matrix *m1, struct matrix *m2) ~ [ 61 | int i; 62 | struct matrix *sum; 63 | 64 | setup: { 65 | m1 = matrix_create([?], [?]); 66 | m2 = matrix_create([?], [?]); 67 | } 68 | 69 | sum = .malloc(sizeof(struct matrix *)); 70 | sum->data = .malloc(sizeof(int *) * m1->rows); 71 | sum->rows = m1->rows; 72 | sum->cols = m1->cols; 73 | for (i = 0; i < sum->rows; i++) { 74 | sum->data[i] = .malloc(sizeof(int)); 75 | } 76 | return sum; 77 | ]{ 78 | int i; int j; 79 | struct matrix *res; 80 | 81 | /*assert(m1->rows == m2->rows && m1->cols == m2->cols);*/ 82 | 83 | res = matrix_create(m1->rows, m1->cols); 84 | for (i = 0; i < res->rows; i++) { 85 | for (j = 0; j < m1->cols; j++) { 86 | res->data[i][j] = m1->data[i][j] + m2->data[i][j]; 87 | } 88 | } 89 | return res; 90 | } 91 | 92 | void 93 | matrix_print(struct matrix *m) ~ [ 94 | setup: m = matrix_create([?], [?]); 95 | ] { 96 | int i; int j; int digit; 97 | 98 | for (i = 0; i < m->rows; i++) { 99 | for (j = 0; j < m->cols; j++) { 100 | digit = m->data[i][j] + '0'; 101 | putchar(digit); 102 | } 103 | puts("\n"); 104 | } 105 | puts("\n"); 106 | } 107 | 108 | int 109 | main() 110 | { 111 | struct matrix *m1; 112 | struct matrix *m2; 113 | struct matrix *sum; 114 | 115 | puts("matrix program:\n"); 116 | m1 = matrix_create(2, 2); 117 | ~ [ @m1; ] 118 | 119 | m1->data[0][0] = 1; 120 | m1->data[0][1] = 2; 121 | m1->data[1][0] = 3; 122 | m1->data[1][1] = 4; 123 | puts("m1:\n"); 124 | matrix_print(m1); 125 | 126 | m2 = matrix_create(2, 2); 127 | ~ [ @m1; @m2; ] 128 | 129 | m2->data[0][0] = 1; 130 | m2->data[0][1] = 1; 131 | m2->data[1][0] = 1; 132 | m2->data[1][1] = 1; 133 | puts("m2:\n"); 134 | matrix_print(m2); 135 | 136 | sum = matrix_add(m1, m2); 137 | ~ [ @m1; @m2; @sum; ] 138 | 139 | puts("sum:\n"); 140 | matrix_print(sum); 141 | 142 | matrix_destroy(sum); 143 | ~ [ @m1; @m2; !@sum; ] 144 | matrix_destroy(m2); 145 | ~ [ @m1; !@m2; !@sum; ] 146 | matrix_destroy(m1); 147 | ~ [ !@m1; !@m2; !@sum; ] 148 | } 149 | -------------------------------------------------------------------------------- /tests/0v/99-program/100-lex/gen.l: -------------------------------------------------------------------------------- 1 | %{ 2 | 3 | #include 4 | 5 | void 6 | printyy(); 7 | 8 | %} 9 | 10 | %option noyywrap 11 | 12 | float float 13 | other [a-zA-Z0-9 \n] 14 | 15 | %% 16 | 17 | {float} {printf("double");} 18 | {other} {printyy();} 19 | 20 | %% 21 | 22 | void 23 | printyy() 24 | { 25 | printf("%.*s", (int) yyleng, yytext); 26 | } 27 | 28 | /* read_file: reads contents of file and returns them 29 | * caller must free returned string 30 | * see https://stackoverflow.com/a/14002993 */ 31 | char * 32 | read_file(char *path) 33 | { 34 | FILE *f = fopen(path, "rb"); 35 | fseek(f, 0, SEEK_END); 36 | long fsize = ftell(f); 37 | fseek(f, 0, SEEK_SET); /* same as rewind(f); */ 38 | char *str = malloc(fsize + 1); 39 | fread(str, fsize, 1, f); 40 | fclose(f); 41 | str[fsize] = '\0'; 42 | return str; 43 | } 44 | 45 | int 46 | main(int argc, char *argv[]) 47 | { 48 | if (argc != 2) { 49 | perror("must supply input file"); 50 | exit(1); 51 | } 52 | char *infile = read_file(argv[1]); 53 | yy_scan_string(infile); 54 | free(infile); 55 | yylex(); 56 | } 57 | -------------------------------------------------------------------------------- /tests/run: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | printf 'running test suite at %s\n\n' "$(date)" 3 | start=$(date +%s) 4 | 5 | TESTDIR=$(pwd)/tests 6 | XR0=$(pwd)/bin/0v 7 | LIBX=$(pwd)/libx 8 | IGNORE_FILE=$TESTDIR/wmw-www 9 | 10 | ntests=0 11 | npass=0 12 | 13 | expected_suffix="EXPECTED" 14 | fail_prefix="FAIL" 15 | topological_folder="topological" 16 | main_func="main" 17 | 18 | fail="\e[31mFAIL\e[0m\n" 19 | pass="\e[32mPASS\e[0m\n" 20 | ignore="\e[33mIGNORE\e[0m\n" 21 | 22 | run_cmd() { 23 | f=$1 24 | folder=$(dirname "$f") 25 | tempfile=$2 26 | 27 | args="" 28 | args_file=$folder/args 29 | if [ -f $args_file ]; then 30 | args=$(cat $args_file) 31 | fi 32 | echo $XR0 -I $LIBX $args $f >> /tmp/args 33 | 34 | $XR0 -I $LIBX $args $f > "$tempfile" 2>&1 35 | } 36 | 37 | run_test() { 38 | f=$1 39 | folder=$(dirname "$f") 40 | tempfile=$2 41 | 42 | output=$(run_cmd $f $tempfile) 43 | 44 | # cases where we have an expected output to compare with 45 | if [[ "$f" == *"${fail_prefix}"* || "$folder" == *"$topological_folder"* ]] 46 | then 47 | expected_file="${f}.${expected_suffix}" 48 | 49 | echo "$(<$tempfile)" | diff - $expected_file 50 | else 51 | # silence is golden 52 | cat $tempfile 53 | fi 54 | } 55 | 56 | nignore=$(cat $IGNORE_FILE | wc -l) 57 | ignore_files=$(cat $IGNORE_FILE) 58 | 59 | for f in $ignore_files; do 60 | file=$TESTDIR/0v/$f 61 | if [ ! -f "$file" ]; then 62 | printf "error: ignored file %s not found\n" "$file" 1>&2 63 | exit 1 64 | fi 65 | done 66 | 67 | should_ignore() { 68 | for name in $ignore_files; do 69 | if [ "$name" = "$1" ]; then 70 | return 0 71 | fi 72 | done 73 | return 1 74 | } 75 | 76 | cd $TESTDIR/0v 77 | 78 | ntests=$(ls */*.x | wc -l) 79 | 80 | length=$(ls */*.x | awk '{ print length, $0 }' | sort -n -s | cut -d' ' -f2- | 81 | tail -1 | wc -c) 82 | 83 | # loop through and run tests 84 | for f in */*.x 85 | do 86 | printf "%-${length}s ..." "$f" 87 | 88 | # skip ignores 89 | if should_ignore $f; then 90 | printf "$ignore" 91 | continue 92 | fi 93 | 94 | tempfile=$(mktemp) 95 | succ=$(run_test $f $tempfile) 96 | if [[ $succ -eq 0 ]]; then 97 | npass=$((npass+1)) 98 | printf "$pass" 99 | else 100 | printf "$fail" 101 | fi 102 | rm $tempfile 103 | 104 | done 105 | 106 | cd $TESTDIR 107 | cd .. 108 | printf "%-${length}s ..." "0db/00-basic" 109 | if $TESTDIR/0db/run; then 110 | npass=$((npass+1)) 111 | printf "$pass" 112 | else 113 | printf "$fail" 114 | fi 115 | ntests=$((ntests+1)) 116 | 117 | nfail=$((ntests-(npass+nignore))) 118 | finish=$(date +%s) 119 | time=$(echo "$finish-$start" | bc) 120 | printf "\n%d tests:\t%d passed\t%d failed\t%d ignored\tin %d seconds\n" \ 121 | $ntests $npass $nfail $nignore $time 122 | if [ $nfail -ne 0 ] 123 | then 124 | exit 1 125 | fi 126 | -------------------------------------------------------------------------------- /tests/wmw-www: -------------------------------------------------------------------------------- 1 | 00-basic/500-FAIL-side-effect.x 2 | 00-basic/520-side-effect-rconst.x 3 | 02-loops/100-variable-limit.x 4 | 09-calls/100-FAIL-unique-rconst.x 5 | 09-calls/120-FAIL-unique-rconst.x 6 | 09-calls/130-unique-rconst.x 7 | 09-calls/200-FAIL-wrong-range.x 8 | 99-program/000-matrix.x 9 | 12-bounds-vbci/031-within-bounds-minus-one-abstract-rconst.x 10 | --------------------------------------------------------------------------------