├── .gitignore ├── .hgignore ├── Makefile ├── README ├── TODO ├── buildtest └── ubuntu-18.04 │ ├── Dockerfile │ ├── liballocs_diff │ ├── libcrunch_diff │ └── libsystrap_diff ├── config.mk ├── frontend ├── Makefile ├── c++ │ ├── bin │ │ ├── c++ │ │ └── crunchc++ │ ├── include │ │ └── checked_cast.hpp │ └── test │ │ ├── Makefile │ │ └── hello │ │ └── hello.cc ├── c │ ├── Makefile │ ├── alloclocals │ │ └── alloclocals.ml │ ├── base-type-equivs.txt │ ├── bin │ │ ├── Fbcc │ │ ├── Mbcc │ │ ├── Pbcc │ │ ├── Sbcc │ │ ├── Tbcc │ │ ├── bcc │ │ ├── cc │ │ ├── crunchAcc │ │ ├── crunchFbcc │ │ ├── crunchMbcc │ │ ├── crunchPbcc │ │ ├── crunchSbcc │ │ ├── crunchTbcc │ │ ├── crunchbcc │ │ ├── crunchbwscc │ │ ├── crunchcc │ │ ├── crunchfbcc │ │ ├── crunchmbcc │ │ ├── crunchpbcc │ │ ├── crunchsbcc │ │ ├── crunchtbcc │ │ ├── crunchxcc │ │ ├── fbcc │ │ ├── mbcc │ │ ├── pbcc │ │ ├── sbcc │ │ ├── tbcc │ │ └── xcc │ ├── crunchbound │ │ └── crunchbound.ml │ ├── dumpreftypes │ │ └── dumpreftypes.ml │ ├── lib │ │ ├── bounds-abi │ │ ├── bounds-config-F │ │ ├── bounds-config-M │ │ ├── bounds-config-P │ │ ├── bounds-config-S │ │ ├── bounds-config-T │ │ ├── bounds-config-f │ │ ├── bounds-config-m │ │ ├── bounds-config-p │ │ ├── bounds-config-s │ │ ├── bounds-config-t │ │ ├── bounds-warnings │ │ ├── crunchcc.py │ │ └── find-interesting-casts.sh │ ├── ptrintarith │ │ └── ptrintarith.ml │ ├── shadow │ │ └── shadow.ml │ ├── shadowprov │ │ ├── Makefile │ │ ├── gold-plugin.cpp │ │ ├── qsort.c │ │ ├── shadowprov-cflags │ │ ├── shadowprov-ldflags │ │ ├── shadowprov.ml │ │ ├── shadowprov_helpers.h │ │ ├── shadowprov_libc_wrappers.c │ │ ├── shadowprov_rtdecls.h │ │ ├── test-addrof.c │ │ ├── test-fail-materialise.c │ │ ├── test-hello.c │ │ ├── test-malloc.c │ │ ├── test-retptr.c │ │ ├── test-vprintf.c │ │ └── tools.shadowprov │ ├── src │ │ └── Makefile │ ├── trumptr │ │ └── trumptr.ml │ ├── vsimpleaddr │ │ └── vsimpleaddr.ml │ └── vsimplemem │ │ └── vsimplemem.ml ├── cilpp │ ├── Makefile │ ├── bin │ │ ├── cc │ │ ├── cc1 │ │ ├── cilpp │ │ ├── cilpp-cflags │ │ ├── cilpp-cppflags │ │ ├── cilpp-ldflags │ │ └── wrapper │ └── src │ │ ├── Makefile │ │ ├── cilpp.ml │ │ └── mkstemp_stubs.c └── fortran │ └── bin │ └── crunchfc ├── include ├── libcrunch.h ├── libcrunch_cil_inlines.h └── stubgen_softbound.h ├── kernel ├── Makefile └── dev-ones │ ├── Makefile │ └── linux │ ├── Makefile │ └── dev_ones.c ├── lib ├── Makefile └── debug-funcs.sh ├── src ├── Makefile ├── libcrunch.c ├── libcrunch_private.h ├── shadow.c ├── softbound-libc-wrappers.c └── stubs.c └── test ├── Future ├── fail-bounds-type-backin │ ├── fail-bounds-type-backin.c │ └── mk.inc └── noquery-bounds-polymorphic │ ├── mk.inc │ └── noquery-bounds-polymorphic.c ├── Makefile ├── abort-softbound-segv ├── abort-softbound-segv.c ├── frontend.mk └── mk.inc ├── bounds-actuals ├── bounds-actuals.c ├── frontend.mk └── mk.inc ├── bounds-addrtaken-arg ├── bounds-addrtaken-arg.c ├── frontend.mk └── mk.inc ├── bounds-addrtaken ├── bounds-addrtaken.c ├── frontend.mk └── mk.inc ├── bounds-arrarr ├── bounds-arrarr.c ├── frontend.mk └── mk.inc ├── bounds-diff ├── bounds-diff.c ├── frontend.mk └── mk.inc ├── bounds-extern ├── Makefile ├── bounds-extern.c ├── frontend.mk ├── lib.c └── mk.inc ├── bounds-indexzero ├── bounds-indexzero.c ├── frontend.mk └── mk.inc ├── bounds-multi-alloc ├── bounds-multi-alloc.c ├── frontend.mk └── mk.inc ├── bounds-nonlocal ├── bounds-nonlocal.c ├── frontend.mk └── mk.inc ├── bounds-pure-helper ├── bounds-pure-helper.c ├── frontend.mk └── mk.inc ├── bounds-simple ├── bounds-simple.c ├── frontend.mk └── mk.inc ├── bounds-static-init-ptr ├── bounds-static-init-ptr.c ├── frontend.mk └── mk.inc ├── bounds-struct-return ├── bounds-struct-return.c ├── frontend.mk └── mk.inc ├── bounds-struct ├── bounds-struct.c ├── frontend.mk └── mk.inc ├── bounds-trap ├── bounds-trap.c ├── frontend.mk └── mk.inc ├── bounds-type ├── bounds-type.c ├── frontend.mk └── mk.inc ├── bounds-va_arg ├── bounds-va_arg.c ├── frontend.mk └── mk.inc ├── checks.sh ├── clang-frontend └── frontend.mk ├── fail-bounds-oneprev ├── fail-bounds-oneprev.c ├── frontend.mk └── mk.inc ├── fail-bounds-segv ├── fail-bounds-segv.c └── frontend.mk ├── fail-bounds-type-simple ├── fail-bounds-type-simple.c ├── frontend.mk └── mk.inc ├── fail-bounds-type-trapped ├── fail-bounds-type-trapped.c ├── frontend.mk └── mk.inc ├── fail-funptr └── fail-funptr.c ├── fail-sloppy-gpcot ├── fail-sloppy-gpcot.c └── mk.inc ├── fail-va_arg └── fail-va_arg.c ├── fail-voidptrptr-invalid └── fail-voidptrptr-invalid.c ├── fail-voidptrptr-strict ├── fail-voidptrptr-strict.c └── mk.inc ├── function-refines └── function-refines.c ├── hello-array └── hello-array.c ├── hello-c++-static-cast ├── frontend.mk └── hello-c++-static-cast.cc ├── hello-c++ ├── frontend.mk └── hello-c++.cc ├── hello-errno └── hello-errno.c ├── hello-funptr ├── hello-funptr.c └── mk.inc ├── hello-heap └── hello-heap.c ├── hello-incomplete ├── Makefile ├── hello-incomplete.c ├── lib.c └── mk.inc ├── hello-indirect └── hello-indirect.c ├── hello-qualified-char └── hello-qualified-char.c ├── hello-sizeofness └── hello-sizeofness.c ├── hello-stack └── hello-stack.c ├── hello-stackactual └── hello-stackactual.c ├── hello-static └── hello-static.c ├── hello-stubgen ├── hello-stubgen.c └── mk.inc ├── hello-union └── hello-union.c ├── hello-void └── hello-void.c ├── hello └── hello.c ├── lazy-typing ├── lazy-typing.c └── mk.inc ├── like-a ├── like-a.c └── mk.inc ├── noquery-bounds-adjuststore ├── frontend.mk ├── mk.inc └── noquery-bounds-adjuststore.c ├── noquery-bounds-itersimple ├── frontend.mk ├── mk.inc └── noquery-bounds-itersimple.c ├── noquery-bounds-loadstore ├── frontend.mk ├── mk.inc └── noquery-bounds-loadstore.c ├── noquery-bounds-multidim ├── frontend.mk ├── mk.inc └── noquery-bounds-multidim.c ├── noquery-bounds-nofetch ├── frontend.mk ├── mk.inc └── noquery-bounds-nofetch.c ├── noquery-bounds-static-init-ptr ├── frontend.mk ├── mk.inc └── noquery-bounds-static-init-ptr.c ├── noquery-bounds-viacache ├── frontend.mk ├── mk.inc └── noquery-bounds-viacache.c ├── pointer-degree ├── mk.inc └── pointer-degree.c ├── sloppy-gpcot ├── mk.inc └── sloppy-gpcot.c ├── softbound-actuals ├── frontend.mk ├── mk.inc └── softbound-actuals.c ├── softbound-heap ├── frontend.mk ├── mk.inc └── softbound-heap.c ├── softbound-multi-alloc ├── frontend.mk ├── mk.inc └── softbound-multi-alloc.c ├── softbound-nonlocal ├── frontend.mk ├── mk.inc └── softbound-nonlocal.c ├── softbound-simple ├── frontend.mk ├── mk.inc └── softbound-simple.c ├── softbound-static-init-ptr ├── frontend.mk ├── mk.inc └── softbound-static-init-ptr.c ├── specialize-types └── specialize-types.c ├── trap-bounds-oneprev ├── frontend.mk ├── mk.inc └── trap-bounds-oneprev.c ├── trap-bounds-toint ├── frontend.mk ├── mk.inc └── trap-bounds-toint.c ├── va_arg └── va_arg.c └── voidptrptr └── voidptrptr.c /.gitignore: -------------------------------------------------------------------------------- 1 | *.cma 2 | *.cmi 3 | *.cmx 4 | *.cmxs 5 | *.o 6 | *.pyc 7 | *.d 8 | *.so 9 | *.ldopts 10 | frontend/cilpp/src/cilpp 11 | *.a 12 | local-config.mk 13 | makefile 14 | *.i 15 | test/*/*+* 16 | *.i.allocs 17 | *.i.deftypes 18 | *.i.reftypes 19 | *.allocstubs.c 20 | *.o.fixuplog 21 | -------------------------------------------------------------------------------- /.hgignore: -------------------------------------------------------------------------------- 1 | syntax: glob 2 | *.cil.c 3 | *.cil.s 4 | *.o 5 | *.i 6 | makefile 7 | *.orig 8 | logwrites.ml 9 | *.cmx 10 | *.cma 11 | *.cmo 12 | *.cmi 13 | Old/* 14 | *.allocs 15 | *.d 16 | lib/libcrunch.so 17 | src/libcrunch.so 18 | test/hello/hello 19 | test/hello/*/hello 20 | allocsites/allocsites 21 | allocsites/dumptypes 22 | allocsites/git-types.c 23 | allocsites/liballocs.a 24 | allocsites/subtle-questions.txt 25 | allocsites/test-simple.c 26 | allocsites/test-simple.out-types.c 27 | allocsites/test.out-types.c 28 | Notes/* 29 | cachegrind.out.* 30 | test/hello-errno/hello-errno 31 | test/hello-errno/*/hello-errno 32 | test/hello-heap/hello-heap 33 | test/hello-heap/*/hello-heap 34 | test/hello-stack/hello-stack 35 | test/hello-stack/*/hello-stack 36 | test/hello-static/hello-static 37 | test/hello-static/*/hello-static 38 | test/random/random 39 | test/random/*/random 40 | test/section-group/lib1.so 41 | test/section-group/lib2.so 42 | test/section-group/section-group 43 | test/section-group/*/section-group 44 | test/hello-sizeofness/hello-sizeofness 45 | test/hello-sizeofness/*/hello-sizeofness 46 | test/hello-qualified-char/hello-qualified-char 47 | test/hello-qualified-char/*/hello-qualified-char 48 | test/hello-array/hello-array 49 | test/hello-array/*/hello-array 50 | test/hello-void/hello-void 51 | test/hello-void/*/hello-void 52 | test/hello-indirect/hello-indirect 53 | test/hello-indirect/*/hello-indirect 54 | test/hello-stubgen/hello-stubgen 55 | test/hello-stubgen/*/hello-stubgen 56 | allocsites/usedtypes 57 | lib/libcrunch_noop.so 58 | lib/libcrunch_preload.so 59 | src/libcrunch_noop.so 60 | src/libcrunch_preload.so 61 | test/lazy-typing/lazy-typing 62 | test/lazy-typing/*/lazy-typing 63 | test/like-a/like-a 64 | test/like-a/*/like-a 65 | test/sloppy-dumptypes/sloppy-dumptypes 66 | test/sloppy-dumptypes/*/sloppy-dumptypes 67 | frontend/c/src/base-types-translation 68 | test/hello-union/hello-union 69 | test/hello-union/*/hello-union 70 | *.s 71 | allocsites/find-allocated-type-size 72 | test/simple-multi-alloc/simple-multi-alloc 73 | test/simple-multi-alloc/*/simple-multi-alloc 74 | test/hello-funptr/hello-funptr 75 | test/hello-funptr/*/hello-funptr 76 | src/libdumpsmaps.so 77 | test/fail-funptr/fail-funptr 78 | test/fail-funptr/*/fail-funptr 79 | frontend/c/cil-* 80 | test/hello-incomplete/hello-incomplete 81 | test/hello-incomplete/*/hello-incomplete 82 | *.o.fixuplog 83 | *.fixuplog 84 | *.bc 85 | *.allocstubs.c 86 | *.cmxs 87 | lib/libcrunch_preload.a 88 | *debuglog.txt 89 | src/libcrunch_preload.a 90 | *.ltrans.out 91 | *free.res 92 | *.ii 93 | test/fail-voidptrptr-invalid/fail-voidptrptr-invalid 94 | test/fail-voidptrptr-invalid/*/fail-voidptrptr-invalid 95 | test/fail-voidptrptr-strict/fail-voidptrptr-strict 96 | test/fail-voidptrptr-strict/*/fail-voidptrptr-strict 97 | test/function-refines/function-refines 98 | test/function-refines/*/function-refines 99 | test/pointer-degree/pointer-degree 100 | test/pointer-degree/*/pointer-degree 101 | test/voidptrptr/voidptrptr 102 | test/voidptrptr/*/voidptrptr 103 | test/abort-bounds-type-backin/abort-bounds-type-backin 104 | test/abort-bounds-type-backin/*/abort-bounds-type-backin 105 | test/bounds-actuals/bounds-actuals 106 | test/bounds-actuals/*/bounds-actuals 107 | test/bounds-diff/bounds-diff 108 | test/bounds-diff/*/bounds-diff 109 | test/bounds-simple/bounds-simple 110 | test/bounds-simple/*/bounds-simple 111 | test/fail-bounds-type-backin/fail-bounds-type-backin 112 | test/fail-bounds-type-backin/*/fail-bounds-type-backin 113 | test/fail-bounds-type-oneprev/fail-bounds-type-oneprev 114 | test/fail-bounds-type-oneprev/*/fail-bounds-type-oneprev 115 | test/fail-bounds-type-simple/fail-bounds-type-simple 116 | test/fail-bounds-type-simple/*/fail-bounds-type-simple 117 | test/fail-bounds-type-trapped/fail-bounds-type-trapped 118 | test/fail-bounds-type-trapped/*/fail-bounds-type-trapped 119 | test/noquery-bounds-itersimple/noquery-bounds-itersimple 120 | test/noquery-bounds-itersimple/*/noquery-bounds-itersimple 121 | test/noquery-bounds-multidim/noquery-bounds-multidim 122 | test/noquery-bounds-multidim/*/noquery-bounds-multidim 123 | test/noquery-bounds-nofetch/noquery-bounds-nofetch 124 | test/noquery-bounds-nofetch/*/noquery-bounds-nofetch 125 | test/trap-bounds-oneprev/fail-bounds-oneprev 126 | test/trap-bounds-oneprev/*/fail-bounds-oneprev 127 | test/trap-bounds-oneprev/trap-bounds-oneprev 128 | test/trap-bounds-oneprev/*/trap-bounds-oneprev 129 | test/trap-bounds-toint/trap-bounds-toint 130 | test/trap-bounds-toint/*/trap-bounds-toint 131 | *.i.deftypes 132 | *.i.reftypes 133 | test/*/check-stamp 134 | test/*/*/check-stamp 135 | *.pyc 136 | gdb.log 137 | *o.cmd 138 | *.mod 139 | *.ko 140 | *.mod.c 141 | kernel/dev-ones/linux/Module.symvers 142 | kernel/dev-ones/linux/modules.order 143 | */libcrunch_stubs.so 144 | src/dlmalloc.a 145 | stashed-*.patch 146 | tmp-*.patch 147 | *.memacc 148 | src/-ldlbind.res 149 | test/softbound-actuals/softbound-actuals 150 | test/softbound-actuals/*/softbound-actuals 151 | test/softbound-actuals/softbound-actuals 152 | test/softbound-actuals/*/softbound-actuals 153 | test/softbound-simple/softbound-simple 154 | test/softbound-simple/*/softbound-simple 155 | test/softbound-static-init-ptr/softbound-static-init-ptr 156 | test/softbound-static-init-ptr/*/softbound-static-init-ptr 157 | lib/wrap.ldopts 158 | */-l*.res 159 | config.log 160 | offcuts 161 | local-config.mk 162 | test/abort-softbound-segv/*/abort-softbound-segv 163 | test/bounds-indexzero/*/bounds-indexzero 164 | test/bounds-nonlocal/*/bounds-nonlocal 165 | test/bounds-static-init-ptr/*/bounds-static-init-ptr 166 | test/bounds-type/*/bounds-type 167 | test/clang-frontend/clang-frontend 168 | test/clang-frontend/*/clang-frontend 169 | test/fail-bounds-oneprev/*/fail-bounds-oneprev 170 | test/fail-bounds-segv/*/fail-bounds-segv 171 | test/fail-sloppy-gpcot/*/fail-sloppy-gpcot 172 | test/fail-va_arg/*/fail-va_arg 173 | test/hello-c++-static-cast/*/hello-c++-static-cast 174 | test/hello-c++/*/hello-c++ 175 | test/hello-stackactual/*/hello-stackactual 176 | test/noquery-bounds-adjuststore/*/noquery-bounds-adjuststore 177 | test/noquery-bounds-loadstore/*/noquery-bounds-loadstore 178 | test/sloppy-gpcot/*/sloppy-gpcot 179 | test/softbound-heap/*/softbound-heap 180 | test/softbound-nonlocal/*/softbound-nonlocal 181 | test/va_arg/*/va_arg 182 | frontend/clang/.git 183 | *.rej 184 | wrap.res 185 | *deleteme* 186 | test/bounds-addrtaken-arg/*/bounds-addrtaken-arg 187 | test/bounds-addrtaken/*/bounds-addrtaken 188 | test/bounds-arrarr/*/bounds-arrarr 189 | test/bounds-extern/*/bounds-extern 190 | test/bounds-multi-alloc/*/bounds-multi-alloc 191 | test/bounds-pure-helper/*/bounds-pure-helper 192 | test/bounds-struct/*/bounds-struct 193 | test/bounds-trap/*/bounds-trap 194 | test/bounds-va_arg/*/bounds-va_arg 195 | test/softbound-multi-alloc/*/softbound-multi-alloc 196 | test/noquery-bounds-viacache/*/noquery-bounds-viacache 197 | frontend/cilpp/src/cilpp 198 | *.backup 199 | frontend/c/shadowprov/gold-plugin.so 200 | frontend/c/shadowprov/runtime.so 201 | frontend/c/shadowprov/shadowprov_weak.so 202 | frontend/c/shadowprov/shadowtest_weak.so 203 | frontend/c/shadowprov/test-hello 204 | frontend/c/shadowprov/test-malloc 205 | frontend/c/shadowprov/test-retptr 206 | frontend/c/shadowprov/wrap.ldopts 207 | *orig 208 | stashed* 209 | massive.out.* 210 | test/*/*+* 211 | test/*/dump* 212 | frontend/c/shadowprov/defacto* 213 | frontend/c/shadowprov/test-* 214 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | default: src lib frontend test #kernel 2 | 3 | .PHONY: src 4 | src: 5 | $(MAKE) -C src 6 | 7 | .PHONY: frontend 8 | frontend: lib 9 | $(MAKE) -C frontend 10 | 11 | .PHONY: lib 12 | lib: src 13 | $(MAKE) -C lib 14 | 15 | .PHONY: kernel 16 | kernel: 17 | $(MAKE) -C kernel 18 | 19 | .PHONY: clean 20 | clean: 21 | $(MAKE) -C src clean 22 | $(MAKE) -C frontend clean 23 | $(MAKE) -C kernel clean 24 | $(MAKE) -C lib clean 25 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | libcrunch is a system for fast dynamic type and bounds checking in 2 | unsafe languages -- currently C, although languages are fairly pluggable 3 | in the design. 4 | 5 | It is somewhat inaccurately named, in that it is nowadays both a runtime 6 | library and some toolchain extensions (compiler wrapper, linker plugin, 7 | auxiliary tools). 8 | 9 | "Dynamic type checking" mostly means checking pointer casts. There is 10 | limited checking of other things like va_arg and union use; more to add 11 | in due course. 12 | 13 | Bounds checking means probably what you think it means. The innovation 14 | of libcrunch is to do fine-grained bounds checking (sensitive to 15 | subobjects, such as arrays-in-structs), over all allocators (static, 16 | stack, heap and custom), with very few false positives. The key to doing 17 | this is run-time type information and a run-time model of allocators. 18 | Currently, bounds checking performs about the same as ASan, but does 19 | finer-grained checking. It's also comparable to SoftBound, but doesn't 20 | suffer the kind of false positives that fat-pointer systems do when they 21 | lose track of bounds. 22 | 23 | I have some plans for temporal checking too, including a garbage 24 | collector (which masks errors) and a mostly-timely checker (which 25 | catches errors), but nothing concrete yet. 26 | 27 | The medium-term goal is a proof-of-concept implementation of C that is 28 | dynamically safe... and runs most source code unmodified, is 29 | binary-compatible even with uninstrumented code (albeit sacrificing 30 | safety guarantees), and performs usably well (hopefully no worse than 31 | half native speed, usually better). 32 | 33 | To get good performance, I have some plans for exploiting hardware 34 | assistance (various kinds of tagged memory that are springing up) and 35 | also speculative/dynamic optimisations. Again, nothing concrete yet (but 36 | feel free to ask). 37 | 38 | All this is built on top of my other project, liballocs, which you 39 | should build (and probably understand) first. In a nutshell, liballocs 40 | provides the type information and other dynamic run-time services; its 41 | goal is "Smalltalk-style dynamism for Unix processes". 42 | 43 | Building is non-trivial... but you can do it! Overall, the build looks 44 | something like this. 45 | 46 | $ git clone https://github.com/stephenrkell/liballocs.git 47 | $ cat liballocs/README 48 | (and follow those instructions, then...) 49 | $ export LIBALLOCS=`pwd`/liballocs 50 | $ git clone https://github.com/stephenrkell/libcrunch.git 51 | $ cd libcrunch 52 | $ make -jn # for your favourite n 53 | $ make -C test # if this succeeds, be amazed 54 | $ frontend/c/bin/crunchcc -o hello /path/to/hello.c # your code here 55 | $ LD_PRELOAD=`pwd`/lib/libcrunch_preload.so ./hello # marvel! 56 | 57 | Tips for non-Debian or non-jessie users: 58 | 59 | - You must have Dave Anderson's (ex-SGI) libdwarf, not elfutils's 60 | (libdw1) version. The libdwarfpp build will, by default, look for its 61 | dwarf.h and libdwarf.h in /usr/include. If this libdwarf's headers 62 | are not in /usr/include (some distros put them in 63 | /usr/include/libdwarf instead), set LIBDWARFPP_CONFIGURE_FLAGS to 64 | "--with-libdwarf-includes=/path/to/includes" so that liballocs's 65 | contrib build process will configure libdwarfpp appropriately. 66 | 67 | - Some problems have been reported with gcc 5.x and later. See gcc bug 68 | 78407. For now the recommended gcc is the 4.9 series, although 7.2.x 69 | fixes that bug and seems to work. Bug reports for build errors 70 | occurring on other versions are welcome. 71 | 72 | - Be careful of build skew with libelf. Again, there are two versions: 73 | libelf0 and libelf1. It doesn't much matter which you use, but you 74 | should use the same at all times. 75 | 76 | - On *BSD: you must first install g++, and build boost 1.55 from source 77 | using it. Add the relevant prefix to CFLAGS, CXXFLAGS and LDFLAGS. 78 | This is for library/symbol reasons not compiler reasons: mixing 79 | libstdc++ and libc++ in one process doesn't work, and libc++fileno 80 | doesn't work with libc++ at present (relevant feature request: a 81 | fileno() overload for ofstream/ifstream objects). Note that currently, 82 | the liballocs runtime doesn't build or run on the BSDs; however, the 83 | tools should do. 84 | 85 | - Changes with cxxabi: again, build skew with these can be problematic, 86 | especially if you're relying on a system-supplied build of some C++ 87 | library such as libboost* -- since it needn't be built using the same 88 | ABI that your currently-installed C++ compiler is using. If you get 89 | link errors with C++ symbol names, chances are you have a mismatch of 90 | ABI. This is another reason to use g++ 4.9.x for everything (including 91 | your own build of boost, as appropriate), since it predates the new 92 | cxxabi. 93 | 94 | 95 | Liballocs models programs during execution in terms of /typed 96 | allocations/. It reifies data types, providing fast access to 97 | per-allocation metadata. 98 | 99 | Libcrunch extends this with check functions, thereby allowing assertions 100 | such as 101 | 102 | assert(__is_aU(p, &__uniqtype_Widget)); 103 | 104 | to assert that p points to a Widget, and so on. 105 | 106 | For bounds errors, libcrunch instruments /pointer derivation/. This 107 | includes array indexing and pointer arithmetic, but not pointer 108 | dereference which can safely proceed unchecked. Bad pointer uses are 109 | caught and reported in a segfault handler. 110 | 111 | A compiler wrapper inserts these checks (and some others) automatically 112 | at particular points. The effect is to provide clean error messages on 113 | bad pointer casts, bad pointer uses and other operations that would 114 | otherwise be corrupting failure (undefined behaviour, in C). 115 | Language-wise, libcrunch slightly narrows standard C, such that all 116 | live, allocated storage has a well-defined type at any moment (cf. C99 117 | "effective type" which is more liberal). This can be a source of false 118 | positives in the quirkiest code; there are some mitigations. 119 | 120 | Instrumentation is currently done with CIL. There is also a clang 121 | front-end which is less mature (lacks a bounds checker) and currently 122 | rather out-of-date, but will be revived at some point. 123 | 124 | Type-checking usually only slows execution by about 5--35%. You can also 125 | run type-check-instrumented code without the library loaded; in that 126 | case the slowdown is usually minimal (a few percent at most). 127 | 128 | 129 | 130 | Usability quirks 131 | 132 | - requires manual identification of alloc functions (or rather, 133 | liballocs does) 134 | 135 | - check-on-cast is too eager for some C programming styles 136 | ("trap pointer" mechanism for casts in the works; bounds checks 137 | already work this way) 138 | 139 | - higher-order (indirect, pointer-to-function) checks are slightly 140 | conservative 141 | (i.e. a few false positives are possible in these cases) 142 | 143 | - plain crunchcc assumes memory-correct execution and checks only 144 | types (use crunchxcc for bounds checking too; 145 | temporal correctness is assumed, i.e. use-after-free can break us) 146 | 147 | 148 | Limitations of metadata 149 | 150 | - no metadata (debug info) for actual parameters passed in varargs 151 | (need to maintain a shadow stack for this; am working on it) 152 | 153 | - no metadata (debug info) for address-taken temporaries 154 | (significant for C++, but not for C; needs compiler fixes) 155 | 156 | - sizeof scraping is not completely reliable (but is pretty good!) 157 | 158 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | To do: 2 | 3 | bounds checking stuff: 4 | 5 | - refactor libcrunch_cil_inlines.h 6 | -- "primary" versus "secondary" naming confusion -- the secondary path runs a *full* check 7 | -- "residual" check perhaps? 8 | -- abort versus resume versus resume-secondary -- orthogonalise 9 | -- wordsize bounds -- avoid scattering this 10 | 11 | 12 | proper union tracking (in liballocs): monunion 13 | -- union shadow needs on-demand design: use a per-mapping spine 14 | -- just a piecewise-allocated (and effectively unbounded) deep index? 15 | -- assume e.g. one byte per union, one union per word at the first level 16 | + statically forbid (perhaps just warn) address-taken members of non-simultaneous unions 17 | 18 | (in liballocs) separate -frames.so from -types.so, to cut link time 19 | -- helpful message when stack query arrives and no -frametypes.so loaded 20 | 21 | (in liballocs) helpful messages when -types.so et al. can't be found (for user objects only) 22 | 23 | (in liballocs) -frametypes.so: merge same-offset frame members (should be type-identical) 24 | 25 | (in liballocs) -frametypes.so: omit non-address-taken locals (i.e. spills)? 26 | -- requires source-level analysis (do in dumpallocs) 27 | 28 | proper union checking (trumunion): checks *reads* from non-simultaneous unions 29 | + deal with "short" union allocations (the gcc tree_node case) by checking these *writes*? 30 | 31 | proper varargs tracking (in liballocs): monva 32 | -- shadow stack 33 | 34 | proper varargs push/pop checking: trumva 35 | 36 | support variadic function pointer casts 37 | -- requires trap values for functions 38 | 39 | generalise void** handling to structures 40 | 41 | caching done right: figure out what works best 42 | 43 | spatial checks: local bounds transformation for all indexed pointer locals 44 | -- means pulling out all pointer arith and indexing into a toplevel expression (tmpvar = expr;) 45 | -- pull in bounds via cache, noting that cache entry need only cover, not exact-match, the ptr 46 | -- actual checking when we produce the new pointer 47 | -- trap values for arrays -- nontrivial? 48 | 49 | check for well-linkedness (probably in allocscc) 50 | 51 | tighter handling of char* 52 | -- rewrite arithmetic-only use of char* to use a size-1 structure) 53 | -- cast-to-char* always okay 54 | -- read through char* always okay 55 | -- write-through-char* only valid for untyped memory 56 | 57 | memcpy handled properly 58 | 59 | in-place realloc to different type should yield warning? 60 | 61 | C++: file/chase the likely-bug in user-defined conversions 62 | 63 | C++: finish wrapper toolchain (incl. in liballocs) 64 | 65 | C++: namespace-aware typestrs 66 | 67 | Fortran: define wrappers for checking TRANSFERs 68 | 69 | C++: solve problems relating to struct/enum/union tag aliasing 70 | 71 | OCaml front-end + DWARF-scraping 72 | 73 | temporal checking: use barely-conservative GC + free()-as-hint 74 | -- force initialization of pointers (in heap alloc, in locals) 75 | -- reduce stack address re-use frequency using mapping trick + instrumentation 76 | -- fast mprotect() kernel hack? would allow mprotecting non-currect mappings 77 | -- sloppier force GC sweep on crash or cast failure (to find any bad heap-to-stack pointer responsible) 78 | -- or check pointer uses that point to the stack? seems expensive 79 | -- statically detect [most] up-the-stack pointer escapes? 80 | 81 | temporal checking: what to do about custom allocators? 82 | -------------------------------------------------------------------------------- /buildtest/ubuntu-18.04/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM liballocs_ubuntu_18 2 | 3 | RUN cd /usr/local/src/ && git clone https://github.com/stephenrkell/libcrunch.git 4 | 5 | ENV LIBALLOCS /usr/local/src/liballocs 6 | 7 | RUN cd /usr/local/src/ && git clone https://github.com/stephenrkell/libdwarf.git 8 | RUN sudo apt-get install -y cmake 9 | RUN cd /usr/local/src/libdwarf && cmake . -B_Release -DCMAKE_BUILD_TYPE=Release 10 | RUN cd /usr/local/src/libdwarf && cmake --build _Release --target dd 11 | RUN cd /usr/local/src/libdwarf && sudo cmake --build _Release --target install 12 | 13 | COPY libsystrap_diff /usr/local/src/liballocs/contrib/libsystrap/ 14 | RUN cd /usr/local/src/liballocs/contrib/libsystrap && patch -p0 < libsystrap_diff 15 | RUN cd /usr/local/src/liballocs/contrib/libsystrap && make 16 | RUN cd /usr/local/src/liballocs/contrib/libsystrap/contrib/librunt && make 17 | 18 | COPY libcrunch_diff /usr/local/src/libcrunch/ 19 | 20 | RUN cd /usr/local/src/libcrunch && patch -p0 < libcrunch_diff 21 | RUN cd /usr/local/src/libcrunch/src && make -j1 22 | RUN cd /usr/local/src/libcrunch/lib && make -j1 23 | 24 | COPY liballocs_diff /usr/local/src/liballocs/ 25 | RUN cd /usr/local/src/liballocs/ && patch -p0 < liballocs_diff 26 | 27 | RUN cd /usr/local/src/libcrunch/src && make -j1 28 | 29 | RUN cd /usr/local/src/libcrunch && make -j1 30 | -------------------------------------------------------------------------------- /buildtest/ubuntu-18.04/liballocs_diff: -------------------------------------------------------------------------------- 1 | diff --git tools/allocscompilerwrapper.py tools/allocscompilerwrapper.py 2 | index a8a7005..ddec3b9 100644 3 | --- tools/allocscompilerwrapper.py 4 | +++ tools/allocscompilerwrapper.py 5 | @@ -69,8 +69,10 @@ class AllocsCompilerWrapper(CompilerWrapper): 6 | return -1 7 | 8 | def getLibAllocsBaseDir(self): 9 | - # FIXME: don't assume we're run in-place 10 | - return os.path.dirname(__file__) + "/../" 11 | + # FIXME: To be honest, this is worse, but hey :-) 12 | + return "/usr/local/src/liballocs/" 13 | + # # FIXME: don't assume we're run in-place 14 | + # return os.path.dirname(__file__) + "/../" 15 | 16 | def getLibNameStem(self): 17 | return "allocs" 18 | @@ -508,8 +510,8 @@ class AllocsCompilerWrapper(CompilerWrapper): 19 | liballocsLinkArgs = ["-L" + self.getLinkPath()] 20 | if self.doingFinalLink() and not self.doingStaticLink() and not self.linkingSharedObject(): 21 | # we're building a dynamically linked executable 22 | - liballocsLinkArgs += ["-Wl,--dynamic-linker," + self.getRunPath() + "/allocsld.so"] 23 | - liballocsLinkArgs += [self.getRunPath() + "/interp-pad.o"] 24 | + liballocsLinkArgs += ["-Wl,--dynamic-linker," + self.getLibAllocsBaseDir() + "/lib/allocsld.so"] 25 | + liballocsLinkArgs += [self.getLibAllocsBaseDir() + "lib/interp-pad.o"] 26 | liballocsLinkArgs += ["-Wl,-rpath," + self.getRunPath()] 27 | if "LIBALLOCS_USE_PRELOAD" in os.environ and os.environ["LIBALLOCS_USE_PRELOAD"] == "no": 28 | liballocsLinkArgs += [self.getLdLibBase()] 29 | -------------------------------------------------------------------------------- /buildtest/ubuntu-18.04/libsystrap_diff: -------------------------------------------------------------------------------- 1 | diff --git src/Makefile src/Makefile 2 | index 6afec07..34c1a02 100644 3 | --- src/Makefile 4 | +++ src/Makefile 5 | @@ -34,6 +34,7 @@ else 6 | endif 7 | 8 | CFLAGS += -I/usr/include/$(shell $(CC) -dumpmachine) 9 | +CFLAGS += -I$(srcroot)/contrib/libx86emulate/src/ 10 | 11 | C_SRC := $(wildcard *.c) 12 | S_SRC := $(wildcard *.s) 13 | diff --git test/Makefile test/Makefile 14 | index 8e1b3bf..5400a89 100644 15 | --- test/Makefile 16 | +++ test/Makefile 17 | @@ -1,8 +1,8 @@ 18 | -CFLAGS += -g 19 | +CFLAGS += -g -fPIC 20 | 21 | default: hello true getpid time read write 22 | 23 | -true getpid time read write: LDFLAGS += -Wl,-nostdlib -nostartfiles -ffreestanding 24 | +true getpid time read write: LDFLAGS += -no-pie -Wl,-nostdlib -nostartfiles -ffreestanding 25 | 26 | x86-decode: CFLAGS += -I../libsystrap -std=gnu11 27 | x86-decode: LDLIBS += ../libsystrap/x86_decode.o -ludis86 28 | -------------------------------------------------------------------------------- /config.mk: -------------------------------------------------------------------------------- 1 | -include $(dir $(lastword $(MAKEFILE_LIST)))/local-config.mk 2 | 3 | SRCROOT ?= $(dir $(lastword $(MAKEFILE_LIST))) 4 | LIBALLOCS ?= $(realpath $(SRCROOT)/../liballocs) 5 | $(info LIBALLOCS is $(LIBALLOCS)) 6 | LIBALLOCSTOOL ?= $(LIBALLOCS)/contrib/liballocstool 7 | LIBCXXGEN ?= $(LIBALLOCS)/contrib/dwarfidl/contrib/libcxxgen 8 | LIBDWARFPP ?= $(LIBALLOCS)/contrib/dwarfidl/contrib/libdwarfpp 9 | LIBSRK31CXX ?= $(LIBALLOCS)/contrib/dwarfidl/contrib/libdwarfpp/contrib/libsrk31c++ 10 | LIBCXXFILENO ?= $(LIBALLOCS)/contrib/dwarfidl/contrib/libdwarfpp/contrib/libc++fileno 11 | LIBDLBIND ?= $(LIBALLOCS)/contrib/libdlbind 12 | LIBSYSTRAP ?= $(LIBALLOCS)/contrib/libsystrap 13 | LIBRUNT ?= $(LIBALLOCS)/contrib/libsystrap/contrib/librunt 14 | -------------------------------------------------------------------------------- /frontend/Makefile: -------------------------------------------------------------------------------- 1 | default: c cilpp 2 | 3 | .PHONY: c 4 | c: 5 | $(MAKE) -C c 6 | 7 | .PHONY: cilpp 8 | cilpp: 9 | $(MAKE) -C cilpp 10 | 11 | .PHONY: clean 12 | clean: 13 | $(MAKE) -C c clean 14 | $(MAKE) -C cilpp clean 15 | -------------------------------------------------------------------------------- /frontend/c++/bin/c++: -------------------------------------------------------------------------------- 1 | crunchc++ -------------------------------------------------------------------------------- /frontend/c++/bin/crunchc++: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # ... or for debugging, use something like 3 | #!/home/stephen/bin/gdbrun python 4 | 5 | # c++ compiler wrapper for libcrunch. 6 | # We identify the input source file in the commandline, 7 | # and export it as an environment variable. 8 | # We then delegate to cilly, 9 | # passing --save-temps=$( dirname "$inputfile" ) 10 | # i.e. to ensure that temporaries get created in the source file's location 11 | # FIXME: This might break some builds using a separate objdir. 12 | # The Right Thing to do is to somehow replicate the source directory structure 13 | # rooted at the current directory. But it's not clear how to do this in general. 14 | 15 | import os, sys, re, subprocess, tempfile 16 | 17 | if "LIBALLOCS" in os.environ: 18 | liballocs_base = os.path.realpath(os.environ["LIBALLOCS"]) 19 | else: 20 | liballocs_base = os.path.realpath(os.path.dirname(sys.argv[0]) + "/../../../../liballocs/") 21 | sys.path.append(liballocs_base + "/tools") 22 | sys.path.append(liballocs_base + "/tools/lang/c++/lib") 23 | from allocscxx import AllocsCxx 24 | 25 | class CrunchCxx(AllocsCxx): 26 | 27 | def fixupDotO(self, filename, errfile): 28 | with (self.makeErrFile(filename + ".fixuplog", "w+") if not errfile else errfile) as errfile: 29 | # also link the file with the uniqtypes it references 30 | cmd = [self.getLibAllocsBaseDir() + "/tools/lang/c++/bin/link-used-types", filename] 31 | self.debugMsg("Calling " + " ".join(cmd) + "\n") 32 | ret = subprocess.call(cmd) 33 | if ret != 0: 34 | return ret # give up now 35 | 36 | return AllocsCxx.fixupDotO(self, filename, errfile) 37 | 38 | def getLdLibBase(self): 39 | return "-lcrunch" 40 | 41 | def getLinkPath(self): 42 | return os.path.dirname(__file__) + "/../../../lib" 43 | 44 | def getLibNameStem(self): 45 | return "crunch" 46 | 47 | def getDummyWeakObjectNameStem(self): 48 | return "stubs" 49 | 50 | def getUnderlyingCompilerCommand(self, sourceFiles): 51 | return AllocsCxx.getUnderlyingCompilerCommand(self, sourceFiles) + ["-Wold-style-cast", \ 52 | "-std=c++11", "-include", \ 53 | os.path.realpath(os.path.dirname(__file__) + "/../include/checked_cast.hpp")] 54 | 55 | if __name__ == '__main__': 56 | wrapper = CrunchCxx() 57 | ret = wrapper.main() 58 | exit(ret) 59 | 60 | -------------------------------------------------------------------------------- /frontend/c++/test/Makefile: -------------------------------------------------------------------------------- 1 | THIS_MAKEFILE := $(realpath $(lastword $(MAKEFILE_LIST))) 2 | $(warning THIS_MAKEFILE is $(THIS_MAKEFILE)) 3 | 4 | CXX := $(dirname $(THIS_MAKEFILE)/../bin/crunchc++ 5 | 6 | # CXXFLAGS += -save-temps 7 | CXXFLAGS += -std=c++11 # -include checked_cast.hpp 8 | 9 | default: hello/hello 10 | 11 | 12 | -------------------------------------------------------------------------------- /frontend/c++/test/hello/hello.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char **argv) 4 | { 5 | unsigned long addr = reinterpret_cast(&argc); 6 | std::cerr << "Address of argc as an integer is " 7 | << std::hex << addr 8 | << std::dec << std::endl; 9 | std::cerr << "Back to pointer: " 10 | << reinterpret_cast(addr) 11 | << std::endl; 12 | 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /frontend/c/Makefile: -------------------------------------------------------------------------------- 1 | THIS_MAKEFILE := $(lastword $(MAKEFILE_LIST)) 2 | 3 | SRCROOT := $(realpath $(dir $(THIS_MAKEFILE))/../..) 4 | include $(SRCROOT)/config.mk 5 | export CXXFLAGS += \ 6 | -I$(LIBCXXGEN)/include \ 7 | -I$(LIBDWARFPP)/include \ 8 | -I$(LIBSRK31CXX)/include \ 9 | -I$(LIBCXXFILENO)/include \ 10 | -I$(LIBDLBIND)/include \ 11 | 12 | export LDFLAGS += \ 13 | -L$(LIBCXXGEN)/lib -Wl,-rpath,$(LIBCXXGEN)/lib \ 14 | -L$(LIBDWARFPP)/lib -Wl,-rpath,$(LIBDWARFPP)/lib \ 15 | -L$(LIBSRK31CXX)/lib -Wl,-rpath,$(LIBSRK31CXX)/lib \ 16 | -L$(LIBCXXFILENO)/lib -Wl,-rpath,$(LIBCXXFILENO)/lib \ 17 | -L$(LIBDLBIND)/lib -Wl,-rpath,$(LIBDLBIND)/lib 18 | 19 | CXXFLAGS += -I$(SRCROOT)/include 20 | 21 | LIBALLOCS ?= $(SRCROOT)/../liballocs 22 | LIBALLOCS_BASE ?= $(realpath $(LIBALLOCS)) 23 | 24 | OCAMLFIND ?= ocamlfind 25 | CIL_INSTALL ?= $(LIBALLOCS_BASE)/tools/lang/c/cil 26 | CILLY ?= $(CIL_INSTALL)/bin/cilly 27 | CIL_TOOLS := trumptr vsimplemem vsimpleaddr crunchbound dumpreftypes ptrintarith shadow shadowprov alloclocals 28 | OCAMLFLAGS += -package findlib -I $(CIL_INSTALL)/lib/cil 29 | OCAMLFLAGS += -I $(dir $(THIS_MAKEFILE))/lib -I $(LIBALLOCS_BASE)/tools/lang/c/cilallocs #-I $(dir $(wildcard $(shell which $(CILLY))/../lib/ocaml/*/cil)) 30 | OCAMLFLAGS += -g 31 | 32 | default: src lib cil sanity-tests shadowprov/shadowprov_weak.so shadowprov 33 | 34 | .PHONY: cil 35 | cil: $(foreach t,$(CIL_TOOLS),$(t)/$(t).cmxs $(t)/$(t).cma) 36 | 37 | %.cmxs: %.cmx 38 | $(OCAMLFIND) ocamlopt -shared -o "$@" $(OCAMLOPTFLAGS) $(OCAMLFLAGS) "$<" 39 | %.cmx %.cmi: %.ml 40 | $(OCAMLFIND) ocamlopt -o "$@" $(OCAMLOPTFLAGS) $(OCAMLFLAGS) -c "$<" 41 | %.cmo %.cmi: %.ml 42 | $(OCAMLFIND) ocamlc -o "$@" $(OCAMLFLAGS) -c "$<" 43 | %.cma: %.cmo 44 | $(OCAMLFIND) ocamlc -o "$@" $(OCAMLFLAGS) -a $+ 45 | 46 | # extra dependencies 47 | shadowprov/shadowprov.cmxs shadowprov/shadowprov.cma shadowprov/shadowprov.cmx: \ 48 | OCAMLFLAGS += -I $(dir $(THIS_MAKEFILE))/shadow 49 | shadowprov/shadowprov.cmxs: shadow/shadow.cmxs 50 | shadowprov/shadowprov.cmx: shadow/shadow.cmx 51 | 52 | .PHONY: shadowprov 53 | shadowprov: 54 | $(MAKE) -C shadowprov 55 | # tool-specific mini-runtime 56 | shadowprov/shadowprov_weak.so: shadowprov/shadowprov_rtdecls.h 57 | $(CC) -fPIC -shared -g -o "$@" -x c shadowprov/shadowprov_rtdecls.h -x none \ 58 | -Wl,-rpath,$(realpath $(dir $(THIS_MAKEFILE))/../../lib) \ 59 | $(realpath $(dir $(THIS_MAKEFILE))/../../lib)/libcrunch_stubs.so 60 | 61 | # for testing 62 | %.cil.o: %.c 63 | cd "$(dir $<)" && $(CILLY) --do$$( echo $(dir $<) | tr -d '/' ) --save-temps -c -o "$(notdir $@)" "$(notdir $<)" 64 | 65 | clean: 66 | for dir in $(CIL_TOOLS); do (cd $$dir && rm -f *.o *.cmo *.cma *.cmi *.cmx *.cmxa *.cmxs *.cil.c *.i ); done 67 | $(MAKE) -C src clean 68 | 69 | .PHONY: sanity-tests 70 | sanity-tests: | src lib cil 71 | $(MAKE) -C ../../test FRONTEND=c CONFIG=default cleanrun-hello cleanrun-hello-errno cleanrun-hello-static cleanrun-hello-stack cleanrun-hello-heap 72 | 73 | .PHONY: src 74 | src: 75 | $(MAKE) -C src 76 | -------------------------------------------------------------------------------- /frontend/c/alloclocals/alloclocals.ml: -------------------------------------------------------------------------------- 1 | (* Copyright (c) 2018, 2 | * Stephen Kell 3 | *) 4 | 5 | open Cil 6 | open Cilallocs 7 | open Pretty 8 | open Map 9 | open Str 10 | 11 | class allocLocalsVisitor 12 | = fun enclosingFile -> 13 | fun ignoreFiles -> 14 | object(self) 15 | inherit nopCilVisitor 16 | 17 | val replacedLocals : Cil.varinfo VarinfoMap.t ref = ref VarinfoMap.empty 18 | 19 | val allocationFunc : Cil.fundec = materialiseBuiltin "__builtin_alloca" 20 | val memcpyFunc : Cil.fundec = (* materialiseBuiltin "__builtin_memcpy" *) 21 | findOrCreateExternalFunctionInFile enclosingFile "memcpy" (TFun(voidPtrType, 22 | Some [ ("dest", voidPtrType, []); 23 | ("src", voidConstPtrType, []); 24 | ("n", ulongType, []) 25 | ], 26 | false, [])) 27 | 28 | val currentFunc : fundec option ref = ref None 29 | 30 | method vfunc (f: fundec) : fundec visitAction = 31 | currentFunc := Some(f); 32 | replacedLocals := VarinfoMap.empty; 33 | if List.fold_left (fun acc -> fun x -> acc || stringEndsWith f.svar.vdecl.file x) 34 | false ignoreFiles 35 | then SkipChildren 36 | else 37 | let tempAddressTakenLocalNames = ref [] in 38 | let _ = visitCilBlock (new addressTakenVisitor tempAddressTakenLocalNames) f.sbody in 39 | let localsByName : (string, Cil.varinfo * bool) Hashtbl.t ref = ref (Hashtbl.create 113) in 40 | let addLocal = (fun isFormal -> fun vi -> Hashtbl.add !localsByName vi.vname (vi, isFormal)) in 41 | List.iter (addLocal false) f.slocals; 42 | List.iter (addLocal true) f.sformals; 43 | List.iter (fun localName -> 44 | (* introduce and initialize pointers for each address-taken local *) 45 | let (vi, isFormal) = Hashtbl.find !localsByName localName in 46 | (* rewrite SizeOFE, as we do elsewhere *) 47 | let ptrTargetT = match vi.vtype with 48 | TArray(elT, Some(SizeOfE(sizeExp)), attrs) -> 49 | TArray(elT, Some(SizeOf(Cil.typeOf sizeExp)), attrs) 50 | | x -> x 51 | in 52 | let ptrT = TPtr(ptrTargetT, []) in 53 | let ptrVi = Cil.makeTempVar f ~name:(("__cil_alloclocal" ^ "_") ^ localName ^ "_") ptrT 54 | in 55 | replacedLocals := VarinfoMap.add vi ptrVi !replacedLocals; 56 | self#queueInstr ( 57 | [Call( 58 | Some(Var(ptrVi), NoOffset), 59 | Lval(Var(allocationFunc.svar), NoOffset), 60 | [SizeOf(vi.vtype)], 61 | vi.vdecl 62 | ) 63 | ] @ if isFormal then [Call( 64 | None, 65 | Lval(Var(memcpyFunc.svar), NoOffset), 66 | [Lval(Var(ptrVi), NoOffset); 67 | mkAddrOf (Var(vi), NoOffset); 68 | SizeOf(vi.vtype) 69 | ], 70 | vi.vdecl 71 | )] else 72 | (* FIXME: for the sake of our own robustness, 73 | delete the local (can't do this for formals) *) 74 | (*let _ = f.slocals in *) [] 75 | ); 76 | if not isFormal then f.slocals <- List.filter (fun v -> v != vi) f.slocals else () 77 | ) !tempAddressTakenLocalNames; 78 | DoChildren 79 | 80 | method vexp (outerE : Cil.exp) : Cil.exp visitAction = 81 | (* eliminate SizeOfE because it causes problems that we 82 | * amplify, by duplicating "sizeof"-based array type expressions 83 | * into various places (chiefly our alloca() and memcpy() calls). 84 | * The underlying problem is that apparently dereferencing exprs, 85 | *like "sizeof a->b", don't actually do derefs. It is quite hard 86 | * for clients / downstream passes to know that they're in 87 | * such a context, so rewrite as we go down. *) 88 | let initiallyChangedE = match outerE with 89 | SizeOfE(e) -> SizeOf(Cil.typeOf e) 90 | | x -> x 91 | in 92 | ChangeDoChildrenPost(initiallyChangedE, fun i -> i) 93 | 94 | method vlval ((lh,lo): Cil.lval) : Cil.lval visitAction = 95 | match lh with 96 | Var(vi) when not vi.vglob -> ( 97 | try 98 | let ptrVi = VarinfoMap.find vi !replacedLocals in 99 | ChangeDoChildrenPost((lh,lo), fun (_, loRewritten) -> 100 | Mem(Lval(Var(ptrVi), NoOffset)), loRewritten) 101 | with Not_found -> DoChildren 102 | ) 103 | | _ -> DoChildren 104 | 105 | end 106 | 107 | let feature : Feature.t = 108 | { fd_name = "alloclocals"; 109 | fd_enabled = false; 110 | fd_description = "allocate locals"; 111 | fd_extraopt = []; 112 | fd_doit = 113 | (function (fl: file) -> (* Unix.sleep 10; *) (* debugging *) 114 | visitCilFileSameGlobals (new allocLocalsVisitor fl ["liballocs_cil_inlines.h"; "libcrunch_cil_inlines.h"; "shadowprov_helpers.h"] :> cilVisitor) fl 115 | ); 116 | fd_post_check = true; 117 | } 118 | 119 | let () = Feature.register feature 120 | -------------------------------------------------------------------------------- /frontend/c/base-type-equivs.txt: -------------------------------------------------------------------------------- 1 | signed char, char, char signed 2 | unsigned char, char unsigned 3 | short int, short, int short 4 | short unsigned int, unsigned short, short unsigned, unsigned short int, int unsigned short, int short unsigned, unsigned int short, short int unsigned 5 | int, signed, signed int, int signed 6 | unsigned int, unsigned, int unsigned 7 | long int, long, int long, signed long int, int signed long, int long signed, long signed int, signed int long, long signed, signed long 8 | unsigned long int, int unsigned long, int long unsigned, long unsigned int, unsigned int long, long unsigned, unsigned long 9 | long long int, long long, long int long, int long long, long long signed, long signed long, signed long long, long long int signed, long long signed int, long signed long int, signed long long int, long int long signed, long int signed long,long signed int long,signed long int long, int long long signed, int long signed long, int signed long long, signed int long long 10 | long long unsigned int, long long unsigned, long unsigned long, unsigned long long, long long int unsigned, long unsigned long int, unsigned long long int, long int long unsigned, long int unsigned long, long unsigned int long, unsigned long int long, int long long unsigned, int long unsigned long, int unsigned long long, unsigned int long long 11 | float 12 | double 13 | long double, double long 14 | bool 15 | wchar_t 16 | -------------------------------------------------------------------------------- /frontend/c/bin/Fbcc: -------------------------------------------------------------------------------- 1 | crunchFbcc -------------------------------------------------------------------------------- /frontend/c/bin/Mbcc: -------------------------------------------------------------------------------- 1 | crunchMbcc -------------------------------------------------------------------------------- /frontend/c/bin/Pbcc: -------------------------------------------------------------------------------- 1 | crunchPbcc -------------------------------------------------------------------------------- /frontend/c/bin/Sbcc: -------------------------------------------------------------------------------- 1 | crunchSbcc -------------------------------------------------------------------------------- /frontend/c/bin/Tbcc: -------------------------------------------------------------------------------- 1 | crunchTbcc -------------------------------------------------------------------------------- /frontend/c/bin/bcc: -------------------------------------------------------------------------------- 1 | crunchbcc -------------------------------------------------------------------------------- /frontend/c/bin/cc: -------------------------------------------------------------------------------- 1 | crunchcc -------------------------------------------------------------------------------- /frontend/c/bin/crunchAcc: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # ... or for debugging, use something like 3 | #!/home/stephen/bin/gdbrun python 4 | 5 | # "Null" compiler wrapper for libcrunch. 6 | # We use cilly with vsimplemem and vsimpleaddr passes. 7 | # This wrapper exists so that we can test for slowdown introduced 8 | # by those passes, independent of the other stuff we do. 9 | import os, sys, re, subprocess, tempfile 10 | 11 | # HACK 12 | if "LIBALLOCS" in os.environ: 13 | liballocs_base = os.path.realpath(os.environ["LIBALLOCS"]) 14 | else: 15 | liballocs_base = os.path.realpath(os.path.dirname(sys.argv[0]) + "/../../../../liballocs/") 16 | sys.path.append(liballocs_base + "/tools") 17 | sys.path.append(liballocs_base + "/tools/lang/c/lib") 18 | from compilerwrapper import CompilerWrapper 19 | sys.path.append(os.path.realpath(os.path.dirname(__file__) + "/../lib")) 20 | sys.path.append(liballocs_base + "/tools") 21 | from allocscompilerwrapper import * 22 | cilly_cmd = liballocs_base + "/tools/lang/c/cil/bin/cilly" 23 | 24 | class CrunchACC(CompilerWrapper): 25 | 26 | def getCillyArgs(self, sourceFiles): 27 | # PROBLEM: we only want to -include if we're compiling a C file. 28 | # Note that normally cilly will figure out when we're compiling 29 | # a .S file, say, and only pass options that are relevant. But 30 | # it would be asking too much in this case. 31 | 32 | allSourceFilesAreC = True 33 | for sourceFile in sourceFiles: 34 | if sourceFile.lang != "c" and not sourceFile.endswith(".c"): 35 | allSourceFilesAreC = False 36 | # "--load=%s" % (os.path.dirname(sys.argv[0]) + "/../vsimplemem/vsimplemem.cmxs"), "--dovsimpleMem", \ 37 | 38 | if len(sourceFiles) > 0 and allSourceFilesAreC: 39 | # We can only do trumptr, and anything else that involves -include, 40 | # if we're compiling only C files. 41 | includeArgs = [ \ 42 | "--load=%s" % (os.path.dirname(sys.argv[0]) + "/../../../../liballocs.hg/tools/lang/c/cilallocs/cilallocs.cmxs") \ 43 | , \ 44 | ] 45 | # "--load=%s" % (os.path.dirname(sys.argv[0]) + "/../vsimpleaddr/vsimpleaddr.cmxs") \ 46 | # , "--dovsimpleAddr" ] 47 | # "--load=%s" % (os.path.dirname(sys.argv[0]) + "/../vsimplemem/vsimplemem.cmxs"), "--dovsimpleMem", \ 48 | else: 49 | self.debugMsg("No source files, or not all (only %d) are C files\n" % len(sourceFiles)) 50 | includeArgs = [] 51 | 52 | return ["--save-temps", "--keepunused", "-Wno-unused-variable", "-Wno-unused-label"] + includeArgs 53 | # We need the above -Wno-unused-... because CIL creates 54 | # some unused stuff (unavoidably, I believe) which will 55 | # make compilation done with -Werror barf if we don't 56 | # silence them. 57 | 58 | def makeObjectFileName(self, sourceFile): 59 | nameStem, nameExtension = os.path.splitext(sourceFile) 60 | if (nameExtension == ".c"): 61 | outputFilename = nameStem + ".o" 62 | self.debugMsg("Making a secret output file (from .c source) " + outputFilename + "\n") 63 | else: 64 | outputFilename = sourceFile + ".o" 65 | self.debugMsg("Making a secret output file (from unknown source) " + outputFilename + "\n") 66 | return outputFilename 67 | 68 | def getUnderlyingCompilerCommand(self, sourceFiles): 69 | return [cilly_cmd] + self.getCillyArgs(sourceFiles) 70 | 71 | def main(self): 72 | # un-export CC from the env if it's set to allocscc, because 73 | # we don't want to recursively crunchcc the -uniqtypes.c files 74 | # that this make invocation will be compiling for us. 75 | # NOTE that we really do mean CC and not CXX here, because 76 | # all the stuff we build ourselves is built from C. 77 | #if "CC" in os.environ and os.environ["CC"].endswith(os.path.basename(sys.argv[0])): 78 | if "CC" in os.environ:# and os.environ["CC"].endswith(os.path.basename(sys.argv[0])): 79 | del os.environ["CC"] 80 | self.debugMsg(sys.argv[0] + " called with args " + " ".join(sys.argv) + "\n") 81 | 82 | sourceInputFiles, objectInputFiles, outputFile = self.parseInputAndOutputFiles(sys.argv) 83 | 84 | passedThroughArgs = sys.argv[1:] 85 | 86 | if "DEBUG_CC" in os.environ: 87 | verboseArgs = ["--verbose", "--live_debug"] 88 | else: 89 | verboseArgs = [] 90 | 91 | argsToExec = verboseArgs \ 92 | + passedThroughArgs 93 | self.debugMsg("about to run cilly with args: " + " ".join(argsToExec) + "\n") 94 | self.debugMsg("passedThroughArgs is: " + " ".join(passedThroughArgs) + "\n") 95 | 96 | ret1 = self.runUnderlyingCompiler(sourceInputFiles, argsToExec) 97 | 98 | if __name__ == '__main__': 99 | wrapper = CrunchACC() 100 | ret = wrapper.main() 101 | exit(ret) 102 | 103 | -------------------------------------------------------------------------------- /frontend/c/bin/crunchFbcc: -------------------------------------------------------------------------------- 1 | crunchbcc -------------------------------------------------------------------------------- /frontend/c/bin/crunchMbcc: -------------------------------------------------------------------------------- 1 | crunchbcc -------------------------------------------------------------------------------- /frontend/c/bin/crunchPbcc: -------------------------------------------------------------------------------- 1 | crunchbcc -------------------------------------------------------------------------------- /frontend/c/bin/crunchSbcc: -------------------------------------------------------------------------------- 1 | crunchbcc -------------------------------------------------------------------------------- /frontend/c/bin/crunchTbcc: -------------------------------------------------------------------------------- 1 | crunchbcc -------------------------------------------------------------------------------- /frontend/c/bin/crunchbcc: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # ... or for debugging, use something like 3 | #!/home/stephen/bin/gdbrun python 4 | 5 | # Compiler wrapper for libcrunch. 6 | import os, sys, re, subprocess, tempfile 7 | 8 | # HACK 9 | if "LIBALLOCS" in os.environ: 10 | liballocs_base = os.path.realpath(os.environ["LIBALLOCS"]) 11 | else: 12 | liballocs_base = os.path.realpath(os.path.dirname(sys.argv[0]) + "/../../../../liballocs/") 13 | sys.path.append(liballocs_base + "/tools") 14 | sys.path.append(liballocs_base + "/tools/lang/c/lib") 15 | from allocscc import AllocsCC 16 | sys.path.append(os.path.realpath(os.path.dirname(__file__) + "/../lib")) 17 | from crunchcc import CrunchCC 18 | 19 | class CrunchBCC(CrunchCC): 20 | 21 | def getBoundsConfigLetter(self): 22 | basename = os.path.basename(sys.argv[0]) 23 | result = re.match("(crunch)?(.)bcc", basename) 24 | if result: 25 | return result.groups()[1][0] 26 | else: 27 | return 'p' 28 | 29 | def getDefines(self): 30 | to_return = [] 31 | letter = self.getBoundsConfigLetter() 32 | self.debugMsg("Bounds config: " + letter + "\n") 33 | libpath = os.path.dirname(__file__) + "/../lib/" 34 | filename = libpath + "bounds-config-" + letter 35 | try: 36 | with open(filename, 'r') as f: 37 | to_return += [l.strip() for l in f] 38 | with open(libpath + "bounds-abi") as f: 39 | to_return += [l.strip() for l in f] 40 | with open(libpath + "bounds-warnings") as f: 41 | to_return += [l.strip() for l in f] 42 | except IOError, e: 43 | sys.stderr.write("Error: no bounds config file: " + filename + "\n") 44 | exit(2) 45 | self.debugMsg("Defines are: " + str(to_return) + "\n") 46 | return to_return 47 | 48 | def doPostLinkMetadataBuild(self, outputFile): 49 | # SoftBound doesn't need metadata (er, hopefully) 50 | return 0 if "-DLIBCRUNCH_NO_POINTER_TYPE_INFO" in self.getDefines() else \ 51 | CrunchCC.doPostLinkMetadataBuild(self, outputFile) 52 | 53 | def getStubGenCompileArgs(self): 54 | # We have to include the CIL inlines with the appropriate flags 55 | # and then define the init, fini and argwise hooks 56 | # so that they do the shadow bounds stack stuff 57 | return ["-include", self.getLibAllocsBaseDir() + "/include/uniqtype.h"] \ 58 | + self.getDefines() \ 59 | + ["-include", \ 60 | os.path.dirname(__file__) + "/../../../include/libcrunch_cil_inlines.h"] \ 61 | + (["-include", \ 62 | os.path.dirname(__file__) + "/../../../include/stubgen_softbound.h"] \ 63 | if "-DLIBCRUNCH_NO_POINTER_TYPE_INFO" in self.getDefines() else []) 64 | 65 | # this one is for a final link 66 | def getExtraLinkArgs(self): 67 | return [os.path.dirname(__file__) + "/../../../lib/libcrunch_wrappers.o", \ 68 | "-Wl,@" + os.path.dirname(__file__) + "/../../../lib/wrap.ldopts"] \ 69 | if "-DLIBCRUNCH_NO_POINTER_TYPE_INFO" in self.getDefines() else [] 70 | 71 | # this one is for the *.linked.o big-object link step 72 | def getExtraRelocLinkArgs(self): 73 | return [] 74 | 75 | def getCillyArgs(self, sourceFiles): 76 | # PROBLEM: we only want to -include if we're compiling a C file. 77 | # Note that normally cilly will figure out when we're compiling 78 | # a .S file, say, and only pass options that are relevant. But 79 | # it would be asking too much in this case. 80 | 81 | allSourceFilesAreC = True 82 | for sourceFile in sourceFiles: 83 | if sourceFile.lang != "c" and not sourceFile.endswith(".c"): 84 | allSourceFilesAreC = False 85 | 86 | includeArgs = [] 87 | defines = self.getDefines() 88 | 89 | if len(sourceFiles) > 0 and allSourceFilesAreC: 90 | # We can only do trumptr, and anything else that involves -include, 91 | # if we're compiling only C files. 92 | # temporary HACK to strip line numbers after preprocess 93 | #"--commPrintLn", 94 | includeArgs = [ \ 95 | "-include", self.getLibAllocsBaseDir() + "/include/uniqtype-defs.h", \ 96 | "-include", \ 97 | os.path.dirname(__file__) + "/../../../include/libcrunch_cil_inlines.h", \ 98 | "--load=%s" % (os.path.dirname(sys.argv[0]) + "/../ptrintarith/ptrintarith.cmxs"), "--doptrintarith", \ 99 | "--load=%s" % (os.path.dirname(sys.argv[0]) + "/../crunchbound/crunchbound.cmxs"), "--docrunchbound", \ 100 | ] + (["--void-ptr-has-bounds"] if "-DLIBCRUNCH_VOID_POINTERS_HAVE_BOUNDS" in defines else []) \ 101 | + (["--no-object-type-info"] if "-DLIBCRUNCH_NO_POINTER_TYPE_INFO" in defines else []) \ 102 | + (["--skip-secondary-split"] if "-DLIBCRUNCH_NO_SPLIT_PATH" in defines else []) 103 | else: 104 | self.debugMsg("No source files, or not all (only %d) are C files\n" % len(sourceFiles)) 105 | 106 | return AllocsCC.getCillyArgs(self, sourceFiles) + \ 107 | ["--keepunused"] \ 108 | + defines + includeArgs + \ 109 | ["-Wno-unused-variable", "-Wno-unused-label"] 110 | # We need the above -Wno-unused-... because CIL creates 111 | # some unused stuff (unavoidably, I believe) which will 112 | # make compilation done with -Werror barf if we don't 113 | # silence them. 114 | 115 | if __name__ == '__main__': 116 | wrapper = CrunchBCC() 117 | ret = wrapper.main() 118 | exit(ret) 119 | 120 | -------------------------------------------------------------------------------- /frontend/c/bin/crunchbwscc: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # ... or for debugging, use something like 3 | #!/home/stephen/bin/gdbrun python 4 | 5 | # Compiler wrapper for libcrunch. 6 | import os, sys, re, subprocess, tempfile 7 | 8 | # HACK 9 | if "LIBALLOCS" in os.environ: 10 | liballocs_base = os.path.realpath(os.environ["LIBALLOCS"]) 11 | else: 12 | liballocs_base = os.path.realpath(os.path.dirname(sys.argv[0]) + "/../../../../liballocs/") 13 | sys.path.append(liballocs_base + "/tools") 14 | sys.path.append(liballocs_base + "/tools/lang/c/lib") 15 | from allocscc import AllocsCC 16 | sys.path.append(os.path.realpath(os.path.dirname(__file__) + "/../lib")) 17 | from crunchcc import CrunchCC 18 | 19 | class CrunchBWSCC(CrunchCC): 20 | 21 | def getCillyArgs(self, sourceFiles): 22 | # PROBLEM: we only want to -include if we're compiling a C file. 23 | # Note that normally cilly will figure out when we're compiling 24 | # a .S file, say, and only pass options that are relevant. But 25 | # it would be asking too much in this case. 26 | 27 | allSourceFilesAreC = True 28 | for sourceFile in sourceFiles: 29 | if sourceFile.lang != "c" and not sourceFile.endswith(".c"): 30 | allSourceFilesAreC = False 31 | 32 | includeArgs = [] 33 | # "--load=%s" % (os.path.dirname(sys.argv[0]) + "/../vsimplemem/vsimplemem.cmxs"), "--dovsimpleMem", \ 34 | # "--load=%s" % (os.path.dirname(sys.argv[0]) + "/../vsimpleaddr/vsimpleaddr.cmxs"), "--dovsimpleAddr", \ 35 | 36 | if len(sourceFiles) > 0 and allSourceFilesAreC: 37 | #"-DLIBCRUNCH_TRACE_BOUNDS_STACK", \ 38 | # We can only do trumptr, and anything else that involves -include, 39 | # if we're compiling only C files. 40 | # temporary HACK to strip line numbers after preprocess 41 | #"--commPrintLn", 42 | includeArgs = [ \ 43 | "-include", self.getLibAllocsBaseDir() + "/include/uniqtype-defs.h", \ 44 | "-DLIBCRUNCH_WORDSIZE_BOUNDS", \ 45 | "-DLIBCRUNCH_USING_TRAP_PTRS", \ 46 | "-DLIBCRUNCH_NO_DENORM_BOUNDS", \ 47 | "-DLIBCRUNCH_NO_WARN_INVALID_BOUNDS", \ 48 | "-DLIBCRUNCH_NO_WARN_BACK_IN", \ 49 | "-DLIBCRUNCH_NO_WARN_ONE_PAST", \ 50 | "-DLIBCRUNCH_NO_WARN_INVALID_BOUNDS_RETURN", \ 51 | "-include", \ 52 | os.path.dirname(__file__) + "/../../../include/libcrunch_cil_inlines.h", \ 53 | "--load=%s" % (os.path.dirname(sys.argv[0]) + "/../ptrintarith/ptrintarith.cmxs"), "--doptrintarith", \ 54 | "--load=%s" % (os.path.dirname(sys.argv[0]) + "/../crunchbound/crunchbound.cmxs"), "--docrunchbound", \ 55 | ] 56 | # temporary HACK: disable trumptr (pure bounds) 57 | #"--load=%s" % (os.path.dirname(sys.argv[0]) + "/../trumptr/trumptr.cmxs"), "--dotrumptr" \ 58 | #"--load=%s" % (os.path.dirname(sys.argv[0]) + "/../vsimplemem/vsimplemem.cmxs"), "--dovsimpleMem", \ 59 | else: 60 | self.debugMsg("No source files, or not all (only %d) are C files\n" % len(sourceFiles)) 61 | 62 | # do dumpallocs et al *and* trumptr 63 | return AllocsCC.getCillyArgs(self, sourceFiles) + \ 64 | ["--keepunused"] \ 65 | + includeArgs + \ 66 | ["-Wno-unused-variable", "-Wno-unused-label"] 67 | # We need the above -Wno-unused-... because CIL creates 68 | # some unused stuff (unavoidably, I believe) which will 69 | # make compilation done with -Werror barf if we don't 70 | # silence them. 71 | 72 | if __name__ == '__main__': 73 | wrapper = CrunchBWSCC() 74 | ret = wrapper.main() 75 | exit(ret) 76 | 77 | -------------------------------------------------------------------------------- /frontend/c/bin/crunchcc: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # ... or for debugging, use something like 3 | #!/home/stephen/bin/gdbrun python 4 | 5 | # Compiler wrapper for libcrunch. 6 | import os, sys, re, subprocess, tempfile 7 | 8 | # to find liballocs, we can either 9 | # - use the python path 10 | # - use ../liballocs from the toplevel dir 11 | # - use the LIBALLOCS env var 12 | if "LIBALLOCS" in os.environ: 13 | liballocs_base = os.path.realpath(os.environ["LIBALLOCS"]) 14 | else: 15 | liballocs_base = os.path.realpath(os.path.dirname(sys.argv[0]) + "/../../../../liballocs/") 16 | sys.path.append(liballocs_base + "/tools") 17 | sys.path.append(liballocs_base + "/tools/lang/c/lib") 18 | from allocscc import AllocsCC 19 | 20 | class CrunchCC(AllocsCC): 21 | 22 | def getIncludeArgs(self, sourceFiles): 23 | # PROBLEM: if we have a mixture of C and preprocessed-but-non-C, this will break. 24 | return AllocsCC.getIncludeArgs(self, sourceFiles) + \ 25 | (["-I" + self.getLibAllocsBaseDir() + "/include", \ 26 | "-include", self.getLibAllocsBaseDir() + "/contrib/liballocstool/include/uniqtype-defs.h", \ 27 | "-include", \ 28 | os.path.dirname(__file__) + "/../../../include/libcrunch_cil_inlines.h"] \ 29 | if (len(sourceFiles) > 0 and self.areAllSourceFilesC(sourceFiles)) else []) 30 | 31 | def getCillyArgs(self, sourceFiles): 32 | # PROBLEM: if we have a mixture of C and non-C, this will break. 33 | return AllocsCC.getCillyArgs(self, sourceFiles) + \ 34 | ["--keepunused"] \ 35 | + (["--load=%s" % (os.path.dirname(sys.argv[0]) + "/../dumpreftypes/dumpreftypes.cmxs"), "--dodumpreftypes", \ 36 | "--load=%s" % (os.path.dirname(sys.argv[0]) + "/../trumptr/trumptr.cmxs"), \ 37 | "--dotrumptr" \ 38 | ] if (len(sourceFiles) > 0 and self.areAllSourceFilesC(sourceFiles)) else []) + \ 39 | ["-Wno-unused-variable", "-Wno-unused-label"] 40 | # We need the above -Wno-unused-... because CIL creates 41 | # some unused stuff (unavoidably, I believe) which will 42 | # make compilation done with -Werror barf if we don't 43 | # silence them. 44 | 45 | def getLibNameStem(self): 46 | return "crunch" 47 | 48 | def getDummyWeakObjectNameStem(self): 49 | return "stubs" 50 | 51 | def getLinkPath(self): 52 | return os.path.dirname(__file__) + "/../../../lib" 53 | 54 | if __name__ == '__main__': 55 | wrapper = CrunchCC() 56 | ret = wrapper.main() 57 | exit(ret) 58 | 59 | -------------------------------------------------------------------------------- /frontend/c/bin/crunchfbcc: -------------------------------------------------------------------------------- 1 | crunchbcc -------------------------------------------------------------------------------- /frontend/c/bin/crunchmbcc: -------------------------------------------------------------------------------- 1 | crunchbcc -------------------------------------------------------------------------------- /frontend/c/bin/crunchpbcc: -------------------------------------------------------------------------------- 1 | crunchbcc -------------------------------------------------------------------------------- /frontend/c/bin/crunchsbcc: -------------------------------------------------------------------------------- 1 | crunchbcc -------------------------------------------------------------------------------- /frontend/c/bin/crunchtbcc: -------------------------------------------------------------------------------- 1 | crunchbcc -------------------------------------------------------------------------------- /frontend/c/bin/crunchxcc: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # ... or for debugging, use something like 3 | #!/home/stephen/bin/gdbrun python 4 | 5 | # Compiler wrapper for libcrunch. 6 | import os, sys, re, subprocess, tempfile 7 | 8 | # HACK 9 | if "LIBALLOCS" in os.environ: 10 | liballocs_base = os.path.realpath(os.environ["LIBALLOCS"]) 11 | else: 12 | liballocs_base = os.path.realpath(os.path.dirname(sys.argv[0]) + "/../../../../liballocs/") 13 | sys.path.append(liballocs_base + "/tools") 14 | sys.path.append(liballocs_base + "/tools/lang/c/lib") 15 | from allocscc import AllocsCC 16 | sys.path.append(os.path.realpath(os.path.dirname(__file__) + "/../lib")) 17 | from crunchcc import CrunchCC 18 | 19 | class CrunchXCC(CrunchCC): 20 | 21 | def getCillyArgs(self, sourceFiles): 22 | # PROBLEM: we only want to -include if we're compiling a C file. 23 | # Note that normally cilly will figure out when we're compiling 24 | # a .S file, say, and only pass options that are relevant. But 25 | # it would be asking too much in this case. 26 | 27 | allSourceFilesAreC = True 28 | for sourceFile in sourceFiles: 29 | if sourceFile.lang != "c" and not sourceFile.endswith(".c"): 30 | allSourceFilesAreC = False 31 | 32 | includeArgs = [] 33 | # "--load=%s" % (os.path.dirname(sys.argv[0]) + "/../vsimplemem/vsimplemem.cmxs"), "--dovsimpleMem", \ 34 | # "--load=%s" % (os.path.dirname(sys.argv[0]) + "/../vsimpleaddr/vsimpleaddr.cmxs"), "--dovsimpleAddr", \ 35 | 36 | if len(sourceFiles) > 0 and allSourceFilesAreC: 37 | # We can only do trumptr, and anything else that involves -include, 38 | # if we're compiling only C files. 39 | # Add temporary HACK to strip line numbers after preprocess 40 | # "--commPrintLn", \ 41 | includeArgs = [ \ 42 | "-include", self.getLibAllocsBaseDir() + "/include/uniqtype-defs.h", \ 43 | "-DLIBCRUNCH_USING_TRAP_PTRS", \ 44 | "-DLIBCRUNCH_LONG_SIZE", \ 45 | "-DLIBCRUNCH_NO_DENORM_BOUNDS", \ 46 | "-DLIBCRUNCH_NO_WARN_INVALID_BOUNDS", \ 47 | "-DLIBCRUNCH_NO_WARN_BACK_IN", \ 48 | "-DLIBCRUNCH_NO_WARN_ONE_PAST", \ 49 | "-DLIBCRUNCH_NO_WARN_INVALID_BOUNDS_RETURN", \ 50 | "-include", \ 51 | os.path.dirname(__file__) + "/../../../include/libcrunch_cil_inlines.h", \ 52 | "--load=%s" % (os.path.dirname(sys.argv[0]) + "/../ptrintarith/ptrintarith.cmxs"), "--doptrintarith", \ 53 | "--load=%s" % (os.path.dirname(sys.argv[0]) + "/../crunchbound/crunchbound.cmxs"), "--docrunchbound", \ 54 | "--load=%s" % (os.path.dirname(sys.argv[0]) + "/../trumptr/trumptr.cmxs"), "--dotrumptr" \ 55 | ] 56 | # "--load=%s" % (os.path.dirname(sys.argv[0]) + "/../vsimplemem/vsimplemem.cmxs"), "--dovsimpleMem", \ 57 | else: 58 | self.debugMsg("No source files, or not all (only %d) are C files\n" % len(sourceFiles)) 59 | 60 | # do dumpallocs et al *and* trumptr 61 | return AllocsCC.getCillyArgs(self, sourceFiles) + \ 62 | ["--keepunused"] \ 63 | + includeArgs + \ 64 | ["-Wno-unused-variable", "-Wno-unused-label"] 65 | # We need the above -Wno-unused-... because CIL creates 66 | # some unused stuff (unavoidably, I believe) which will 67 | # make compilation done with -Werror barf if we don't 68 | # silence them. 69 | 70 | if __name__ == '__main__': 71 | wrapper = CrunchXCC() 72 | ret = wrapper.main() 73 | exit(ret) 74 | 75 | -------------------------------------------------------------------------------- /frontend/c/bin/fbcc: -------------------------------------------------------------------------------- 1 | crunchfbcc -------------------------------------------------------------------------------- /frontend/c/bin/mbcc: -------------------------------------------------------------------------------- 1 | crunchmbcc -------------------------------------------------------------------------------- /frontend/c/bin/pbcc: -------------------------------------------------------------------------------- 1 | crunchpbcc -------------------------------------------------------------------------------- /frontend/c/bin/sbcc: -------------------------------------------------------------------------------- 1 | crunchsbcc -------------------------------------------------------------------------------- /frontend/c/bin/tbcc: -------------------------------------------------------------------------------- 1 | crunchtbcc -------------------------------------------------------------------------------- /frontend/c/bin/xcc: -------------------------------------------------------------------------------- 1 | crunchxcc -------------------------------------------------------------------------------- /frontend/c/dumpreftypes/dumpreftypes.ml: -------------------------------------------------------------------------------- 1 | (* Copyright (c) 2016, 2 | * Stephen Kell 3 | * 4 | * and based on logwrites.ml, which is 5 | * 6 | * Copyright (c) 2001-2002, 7 | * George C. Necula 8 | * Scott McPeak 9 | * Wes Weimer 10 | * All rights reserved. 11 | * 12 | * Redistribution and use in source and binary forms, with or without 13 | * modification, are permitted provided that the following conditions are 14 | * met: 15 | * 16 | * 1. Redistributions of source code must retain the above copyright 17 | * notice, this list of conditions and the following disclaimer. 18 | * 19 | * 2. Redistributions in binary form must reproduce the above copyright 20 | * notice, this list of conditions and the following disclaimer in the 21 | * documentation and/or other materials provided with the distribution. 22 | * 23 | * 3. The names of the contributors may not be used to endorse or promote 24 | * products derived from this software without specific prior written 25 | * permission. 26 | * 27 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 28 | * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 29 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 30 | * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 31 | * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 32 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 33 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 34 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 35 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 36 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 37 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 38 | * 39 | *) 40 | 41 | open Unix 42 | open List 43 | open Str 44 | open Pretty 45 | open Cil 46 | open Feature 47 | open Cilallocs 48 | module E = Errormsg 49 | module H = Hashtbl 50 | 51 | let isAlwaysInline vi = 52 | List.fold_left (fun acc -> fun attr -> acc || 53 | match attr with Attr("always_inline", _) -> true | _ -> false 54 | ) false vi.vattr 55 | 56 | let rec decayArrayInTypesig ts = match ts with 57 | TSArray(tsig, optSz, attrs) -> decayArrayInTypesig tsig (* recurse for multidim arrays *) 58 | | _ -> ts 59 | 60 | class dumpRefTypesVisitor = fun (fl: Cil.file) -> object(self) 61 | inherit nopCilVisitor 62 | 63 | (* where we will write our deftype/reftype data *) 64 | val refOutChannel : out_channel option ref = ref None 65 | val defOutChannel : out_channel option ref = ref None 66 | 67 | (* at construction time, open the output file *) 68 | initializer 69 | let reftypeFileName = fl.fileName ^ ".reftypes" in 70 | (refOutChannel := try begin 71 | let chan = open_out reftypeFileName in 72 | Some(chan) 73 | end 74 | with _ -> 75 | raise (Arg.Bad ("Cannot open file " ^ reftypeFileName)) 76 | ); 77 | (* DO we really need deftypes? it duplicates debugging info, 78 | * but might be a nice summary all the same. *) 79 | let deftypeFileName = fl.fileName ^ ".deftypes" in 80 | (defOutChannel := try begin 81 | let chan = open_out deftypeFileName in 82 | Some(chan) 83 | end 84 | with _ -> 85 | raise (Arg.Bad ("Cannot open file " ^ reftypeFileName)) 86 | ) 87 | 88 | method vvdec (v: varinfo) : varinfo visitAction = 89 | (* could be because of a GVar, GVarDecl, GFunc, function type varinfo, 90 | * function def formal or function def local. *) 91 | match (!refOutChannel, !defOutChannel) with 92 | (Some (refChan), Some (defChan)) -> 93 | if ( (* v.vused *) v.vglob && not (isAlwaysInline v) && v.vstorage != Static) then 94 | 95 | (* TODO 1: for reference types, only include things that are "vreferenced" 96 | after running Rmtmps.removeUnusedTemps 97 | *) 98 | let chan = if v.vstorage = Extern then refChan else defChan 99 | in 100 | (output_string chan (v.vname ^ "\t" ^ (barenameFromSig (Cil.typeSig (v.vtype))) ^ "\n")) 101 | (* Print a line consisting of its linkage name followed by its uniqtype name *) 102 | ; flush chan; SkipChildren 103 | else SkipChildren 104 | | _ -> failwith "could not open output channel(s)" 105 | 106 | end (* class dumpAllocsVisitor *) 107 | 108 | let feature : Feature.t = 109 | { fd_name = "dumpreftypes"; 110 | fd_enabled = false; 111 | fd_description = "print information about referenced globals' types"; 112 | fd_extraopt = []; 113 | fd_doit = 114 | (function (f: file) -> 115 | let drtVisitor = new dumpRefTypesVisitor f in 116 | (* Cfg.computeFileCFG f; 117 | computeAEs f; *) 118 | visitCilFileSameGlobals drtVisitor f); 119 | fd_post_check = true; 120 | } 121 | 122 | let () = Feature.register feature 123 | -------------------------------------------------------------------------------- /frontend/c/lib/bounds-abi: -------------------------------------------------------------------------------- 1 | -DLIBCRUNCH_LONG_SIZE 2 | -DLIBCRUNCH_NO_DENORM_BOUNDS 3 | -------------------------------------------------------------------------------- /frontend/c/lib/bounds-config-F: -------------------------------------------------------------------------------- 1 | -DLIBCRUNCH_USING_TRAP_PTRS 2 | -DLIBCRUNCH_CHECK_DERIVE 3 | -DLIBCRUNCH_NO_SPLIT_PATH 4 | -DLIBCRUNCH_ABORT_ON_INVALID_DERIVE 5 | -------------------------------------------------------------------------------- /frontend/c/lib/bounds-config-M: -------------------------------------------------------------------------------- 1 | -DLIBCRUNCH_USING_TRAP_PTRS 2 | -DLIBCRUNCH_CHECK_DERIVE 3 | -DLIBCRUNCH_ABORT_ON_INVALID_DERIVE 4 | -------------------------------------------------------------------------------- /frontend/c/lib/bounds-config-P: -------------------------------------------------------------------------------- 1 | -DLIBCRUNCH_USING_TRAP_PTRS 2 | -DLIBCRUNCH_CHECK_DERIVE 3 | -DLIBCRUNCH_TRAP_ONE_PAST_IN_PRIMARY_CHECK 4 | -DLIBCRUNCH_ABORT_ON_INVALID_DERIVE 5 | -------------------------------------------------------------------------------- /frontend/c/lib/bounds-config-S: -------------------------------------------------------------------------------- 1 | -DLIBCRUNCH_CHECK_DEREF 2 | -DLIBCRUNCH_VOID_POINTERS_HAVE_BOUNDS 3 | -DLIBCRUNCH_NO_POINTER_TYPE_INFO 4 | -DLIBCRUNCH_NO_SPLIT_PATH 5 | -DLIBCRUNCH_ABORT_ON_OOB_DEREF 6 | -------------------------------------------------------------------------------- /frontend/c/lib/bounds-config-T: -------------------------------------------------------------------------------- 1 | -DLIBCRUNCH_USING_TRAP_PTRS 2 | -DLIBCRUNCH_CHECK_DERIVE 3 | -DLIBCRUNCH_VOID_POINTERS_HAVE_BOUNDS 4 | -DLIBCRUNCH_NO_POINTER_TYPE_INFO 5 | -DLIBCRUNCH_NO_SPLIT_PATH 6 | -DLIBCRUNCH_ABORT_ON_INVALID_DERIVE 7 | -------------------------------------------------------------------------------- /frontend/c/lib/bounds-config-f: -------------------------------------------------------------------------------- 1 | -DLIBCRUNCH_USING_TRAP_PTRS 2 | -DLIBCRUNCH_CHECK_DERIVE 3 | -DLIBCRUNCH_NO_SPLIT_PATH 4 | -------------------------------------------------------------------------------- /frontend/c/lib/bounds-config-m: -------------------------------------------------------------------------------- 1 | -DLIBCRUNCH_USING_TRAP_PTRS 2 | -DLIBCRUNCH_CHECK_DERIVE 3 | s 4 | -------------------------------------------------------------------------------- /frontend/c/lib/bounds-config-p: -------------------------------------------------------------------------------- 1 | -DLIBCRUNCH_USING_TRAP_PTRS 2 | -DLIBCRUNCH_CHECK_DERIVE 3 | -DLIBCRUNCH_TRAP_ONE_PAST_IN_PRIMARY_CHECK 4 | -------------------------------------------------------------------------------- /frontend/c/lib/bounds-config-s: -------------------------------------------------------------------------------- 1 | -DLIBCRUNCH_CHECK_DEREF 2 | -DLIBCRUNCH_VOID_POINTERS_HAVE_BOUNDS 3 | -DLIBCRUNCH_NO_POINTER_TYPE_INFO 4 | -------------------------------------------------------------------------------- /frontend/c/lib/bounds-config-t: -------------------------------------------------------------------------------- 1 | -DLIBCRUNCH_USING_TRAP_PTRS 2 | -DLIBCRUNCH_CHECK_DERIVE 3 | -DLIBCRUNCH_VOID_POINTERS_HAVE_BOUNDS 4 | -DLIBCRUNCH_NO_POINTER_TYPE_INFO 5 | -DLIBCRUNCH_TRAP_ONE_PAST_IN_PRIMARY_CHECK 6 | -------------------------------------------------------------------------------- /frontend/c/lib/bounds-warnings: -------------------------------------------------------------------------------- 1 | -DLIBCRUNCH_NO_WARN_INVALID_BOUNDS 2 | -DLIBCRUNCH_NO_WARN_BACK_IN 3 | -DLIBCRUNCH_NO_WARN_ONE_PAST 4 | -DLIBCRUNCH_NO_WARN_INVALID_BOUNDS_RETURN 5 | -------------------------------------------------------------------------------- /frontend/c/lib/crunchcc.py: -------------------------------------------------------------------------------- 1 | ../bin/crunchcc -------------------------------------------------------------------------------- /frontend/c/lib/find-interesting-casts.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # TODO: fix regexp to exclude function signatures like "void foo(bar *);" 4 | 5 | . ~/lib/bash/util 6 | 7 | declare -a line_numbers 8 | 9 | POST=${POST:-3} 10 | PRE=${PRE:-3} 11 | 12 | find -name '*.c' | \ 13 | xargs grep -Hn '([[:blank:]]*[a-zA-Z_][a-zA-Z0-9_ ]*\([[:blank:]]*\*[[:blank:]]*\)\+)' | \ 14 | grep -v alloc | grep -vi char | less | grep -v '(void[[:blank:]]\+\*)' | cut -f1 | tr ':' '\t' | \ 15 | while read file line; do 16 | if [[ -n "$oldfile" ]] && [[ "$file" != "$oldfile" ]]; then 17 | # flush results for the file just gone 18 | regexp="$( echo $line_numbers[@] | make_match_any_line_floating_eregexp )" 19 | cat -n "$oldfile" | grep -A${POST} -B${PRE} "\t$regexp" | sed "s^.*^${file}:&^" 20 | unset line_numbers 21 | ctr=0 22 | else 23 | # append this line number 24 | line_numbers[$ctr]="${line}" 25 | ctr=$(( ${ctr:-0} + 1 )) 26 | fi 27 | #sed -n "$(( ${line} - ${PRE} )),$(( ${line} + ${POST} )) p" "$file #" 28 | oldfile="$file" 29 | done 30 | 31 | # show lines from particular contexts in a file 32 | # -- use grep for this 33 | 34 | -------------------------------------------------------------------------------- /frontend/c/ptrintarith/ptrintarith.ml: -------------------------------------------------------------------------------- 1 | (* Copyright (c) 2014--16, 2 | * Stephen Kell 3 | * 4 | * and based on logwrites.ml, which is 5 | * 6 | * Copyright (c) 2001-2002, 7 | * George C. Necula 8 | * Scott McPeak 9 | * Wes Weimer 10 | * All rights reserved. 11 | * 12 | * Redistribution and use in source and binary forms, with or without 13 | * modification, are permitted provided that the following conditions are 14 | * met: 15 | * 16 | * 1. Redistributions of source code must retain the above copyright 17 | * notice, this list of conditions and the following disclaimer. 18 | * 19 | * 2. Redistributions in binary form must reproduce the above copyright 20 | * notice, this list of conditions and the following disclaimer in the 21 | * documentation and/or other materials provided with the distribution. 22 | * 23 | * 3. The names of the contributors may not be used to endorse or promote 24 | * products derived from this software without specific prior written 25 | * permission. 26 | * 27 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 28 | * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 29 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 30 | * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 31 | * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 32 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 33 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 34 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 35 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 36 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 37 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 38 | * 39 | *) 40 | 41 | open Cil 42 | open Pretty 43 | open Map 44 | open Str 45 | open Cilallocs 46 | module E = Errormsg 47 | module H = Hashtbl 48 | 49 | class ptrIntArithVisitor = fun enclosingFile -> 50 | object(self) 51 | inherit nopCilVisitor 52 | 53 | method vexpr (outerE: exp) : exp visitAction = 54 | (* Consider a nest of (PlusPI|MinusPI) expressions. 55 | * It must be a linear nest, not a tree, because only the left subexpression is a pointer. 56 | * The innermost expression is a pointer expression that is *not* 57 | * computed by PlusPI/MinusPI. Call this the input pointer expression (IPE). 58 | * We can rewrite such a nest as a single PlusPI operation, 59 | * where all other nodes have been rewritten to do arithmetic in the integer domain. 60 | * For example, 61 | 62 | PlusPI(PlusPI(ipe, 4), 4) 63 | 64 | * becomes 65 | 66 | PlusPI(ipe, PlusII(4, 4)). 67 | 68 | * That's all there is to it! We just do it recursively, using ChangeDoChildrenPost. 69 | * One trick is that on the way down we rewrite all MinusPIs into PlusPIs. 70 | * And ditto for IndexPI. RECALL that IndexPI is semantically equivalent to PlusPI. 71 | *) 72 | ChangeDoChildrenPost( 73 | begin 74 | match outerE with 75 | BinOp(MinusPI, subEP, subEI, t) -> 76 | BinOp(PlusPI, subEP, UnOp(Neg, subEI, Cil.typeOf subEI), t) 77 | | BinOp(IndexPI, subEP, subEI, t) -> 78 | BinOp(PlusPI, subEP, subEI, t) 79 | | _ -> outerE 80 | end, fun e -> 81 | match e with 82 | BinOp(PlusPI, BinOp(PlusPI, subEP, subEI1, ptrTInner), subEI2, ptrTOuter) -> 83 | (* We can rewrite this into a single PlusPI *) 84 | BinOp(PlusPI, subEP, BinOp(PlusA, subEI1, subEI2, Cil.typeOf subEI1), ptrTOuter) 85 | | _ -> e 86 | ) 87 | end 88 | 89 | let feature : Feature.t = 90 | { fd_name = "ptrintarith"; 91 | fd_enabled = false; 92 | fd_description = "do pointer arithmetic in the integer domain as far as possible"; 93 | fd_extraopt = []; 94 | fd_doit = 95 | (function (fl: file) -> 96 | debug_print 1 ("command line args are:\n" 97 | ^ (String.concat ", " (Array.to_list Sys.argv) ) ); 98 | let piaFunVisitor = new ptrIntArithVisitor fl in 99 | visitCilFileSameGlobals piaFunVisitor fl 100 | ); 101 | fd_post_check = true; 102 | } 103 | 104 | let () = Feature.register feature 105 | -------------------------------------------------------------------------------- /frontend/c/shadowprov/Makefile: -------------------------------------------------------------------------------- 1 | # This will build any one-file C program as a test 2 | 3 | LIBCRUNCH_BASE ?= ../../.. 4 | -include $(LIBCRUNCH_BASE)/config.mk 5 | 6 | export USE_LD=ld.gold 7 | 8 | default: runtime.so stubs.o qsort.o gold-plugin.so wrap.ldopts shadowprov_weak.so 9 | 10 | C_SRC := shadowprov_libc_wrappers.c 11 | C_DEPS := $(patsubst %.c,.%.d,$(C_SRC)) 12 | $(C_DEPS): .%.d : %.c 13 | $(CC) -MM $(CFLAGS) $(CPPFLAGS) "$<" > "$@" || (rm -f "$@"; false) 14 | -include $(C_DEPS) 15 | 16 | ifeq ($(LIBRUNT),) 17 | $(error LIBRUNT not set) 18 | endif 19 | ifeq ($(LIBALLOCS),) 20 | $(error LIBALLOCS not set) 21 | endif 22 | 23 | CPPFLAGS += -I$(LIBRUNT)/include 24 | 25 | CXXFLAGS += -g -fPIC -std=c++14 26 | 27 | gold-plugin.so: LDFLAGS += -Wl,--export-dynamic 28 | gold-plugin.so: gold-plugin.cpp 29 | $(CXX) -shared -o "$@" $(CPPFLAGS) $(CXXFLAGS) -o "$@" $+ $(LDFLAGS) $(LDLIBS) 30 | 31 | stubs.o: shadowprov_libc_wrappers.o 32 | ln -sf "$<" "$@" 33 | shadowprov_libc_wrappers.o: shadowprov_libc_wrappers.c 34 | $(CC) $(CFLAGS) $(CPPFLAGS) -c -o "$@" "$<" 35 | shadowprov_libc_wrappers.o .shadowprov_libc_wrappers.d: CFLAGS += -g -fPIC -std=c11 36 | shadowprov_libc_wrappers.o .shadowprov_libc_wrappers.d: \ 37 | CFLAGS += -I$(LIBCRUNCH_BASE)/include \ 38 | -I$(LIBCRUNCH_BASE)/src \ 39 | -I$(LIBALLOCS)/include \ 40 | -I$(LIBALLOCS)/src \ 41 | -I$(LIBSYSTRAP) \ 42 | -DSHADOW_STACK_TRACE_LEVEL=0 43 | 44 | runtime.so: $(LIBCRUNCH_BASE)/lib/libcrunch_stubs.so 45 | ln -sf "$<" "$@" 46 | 47 | wrap.ldopts: stubs.o 48 | nm --format=posix "$<" | grep __wrap_ | \ 49 | sed -r 's/__wrap_([^[:blank:]]*).*/--wrap \1/' > "$@" \ 50 | || (rm -f "$@"; false) 51 | 52 | CFLAGS += -g 53 | 54 | tests := $(wildcard test-*.c) 55 | vpath %.c defacto_tarball/tests/de_facto_memory_model 56 | extra_tests := $(patsubst defacto_tarball/tests/de_facto_memory_model/%.c,%.c,$(wildcard defacto_tarball/tests/de_facto_memory_model/*.c)) 57 | $(info found extra tests $(extra_tests)) 58 | # sort to remove duplicates, for copied .c files that show up twice 59 | tests := $(sort $(tests) $(patsubst %.c,test-%.c,$(extra_tests))) 60 | $(patsubst %.c,test-%.c,$(extra_tests)): test-%.c: %.c 61 | cp "$<" "$@" 62 | # never build straight from .c -- go via .o 63 | %: %.c 64 | 65 | $(patsubst %.c,%.o,$(tests)): CFLAGS += $(shell ./shadowprov-cflags) -save-temps 66 | $(patsubst %.c,%,$(tests)): LDFLAGS += $(shell ./shadowprov-ldflags) 67 | 68 | test-fail-materialise: LDFLAGS += -Wl,-Ttext,0x410000 69 | 70 | .PHONY: gdbrun-% 71 | gdbrun-%: % 72 | LIBCRUNCH_DELAY_STARTUP=1 LD_PRELOAD=$(realpath ../../../src/libcrunch_preload.so) ./$* & gdb -p $$! 73 | run-%: % 74 | LD_PRELOAD=$(realpath ../../../src/libcrunch_preload.so) ./$* 75 | -------------------------------------------------------------------------------- /frontend/c/shadowprov/qsort.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2011 by Valentin Ochs 2 | * 3 | * Permission is hereby granted, free of charge, to any person obtaining a copy 4 | * of this software and associated documentation files (the "Software"), to 5 | * deal in the Software without restriction, including without limitation the 6 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | * sell copies of the Software, and to permit persons to whom the Software is 8 | * furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in 11 | * all copies or substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 | * IN THE SOFTWARE. 20 | */ 21 | 22 | /* Minor changes by Rich Felker for integration in musl, 2011-04-27. */ 23 | 24 | #include 25 | #include 26 | #include 27 | 28 | //#include "atomic.h" 29 | // pasted by srk 30 | static inline int a_ctz_l(unsigned long x) 31 | { 32 | __asm__( "bsf %1,%0" : "=r"(x) : "r"(x) ); 33 | return x; 34 | } 35 | 36 | #define ntz(x) a_ctz_l((x)) 37 | 38 | typedef int (*cmpfun)(const void *, const void *); 39 | 40 | static inline int pntz(size_t p[2]) { 41 | int r = ntz(p[0] - 1); 42 | if(r != 0 || (r = 8*sizeof(size_t) + ntz(p[1])) != 8*sizeof(size_t)) { 43 | return r; 44 | } 45 | return 0; 46 | } 47 | 48 | static void cycle(size_t width, unsigned char* ar[], int n) 49 | { 50 | unsigned char tmp[256]; 51 | size_t l; 52 | int i; 53 | 54 | if(n < 2) { 55 | return; 56 | } 57 | 58 | ar[n] = tmp; 59 | while(width) { 60 | l = sizeof(tmp) < width ? sizeof(tmp) : width; 61 | memcpy(ar[n], ar[0], l); 62 | for(i = 0; i < n; i++) { 63 | memcpy(ar[i], ar[i + 1], l); 64 | ar[i] += l; 65 | } 66 | width -= l; 67 | } 68 | } 69 | 70 | /* shl() and shr() need n > 0 */ 71 | static inline void shl(size_t p[2], int n) 72 | { 73 | if(n >= 8 * sizeof(size_t)) { 74 | n -= 8 * sizeof(size_t); 75 | p[1] = p[0]; 76 | p[0] = 0; 77 | } 78 | p[1] <<= n; 79 | p[1] |= p[0] >> (sizeof(size_t) * 8 - n); 80 | p[0] <<= n; 81 | } 82 | 83 | static inline void shr(size_t p[2], int n) 84 | { 85 | if(n >= 8 * sizeof(size_t)) { 86 | n -= 8 * sizeof(size_t); 87 | p[0] = p[1]; 88 | p[1] = 0; 89 | } 90 | p[0] >>= n; 91 | p[0] |= p[1] << (sizeof(size_t) * 8 - n); 92 | p[1] >>= n; 93 | } 94 | 95 | static void sift(unsigned char *head, size_t width, cmpfun cmp, int pshift, size_t lp[]) 96 | { 97 | unsigned char *rt, *lf; 98 | unsigned char *ar[14 * sizeof(size_t) + 1]; 99 | int i = 1; 100 | 101 | ar[0] = head; 102 | while(pshift > 1) { 103 | rt = head - width; 104 | lf = head - width - lp[pshift - 2]; 105 | 106 | if((*cmp)(ar[0], lf) >= 0 && (*cmp)(ar[0], rt) >= 0) { 107 | break; 108 | } 109 | if((*cmp)(lf, rt) >= 0) { 110 | ar[i++] = lf; 111 | head = lf; 112 | pshift -= 1; 113 | } else { 114 | ar[i++] = rt; 115 | head = rt; 116 | pshift -= 2; 117 | } 118 | } 119 | cycle(width, ar, i); 120 | } 121 | 122 | static void trinkle(unsigned char *head, size_t width, cmpfun cmp, size_t pp[2], int pshift, int trusty, size_t lp[]) 123 | { 124 | unsigned char *stepson, 125 | *rt, *lf; 126 | size_t p[2]; 127 | unsigned char *ar[14 * sizeof(size_t) + 1]; 128 | int i = 1; 129 | int trail; 130 | 131 | p[0] = pp[0]; 132 | p[1] = pp[1]; 133 | 134 | ar[0] = head; 135 | while(p[0] != 1 || p[1] != 0) { 136 | stepson = head - lp[pshift]; 137 | if((*cmp)(stepson, ar[0]) <= 0) { 138 | break; 139 | } 140 | if(!trusty && pshift > 1) { 141 | rt = head - width; 142 | lf = head - width - lp[pshift - 2]; 143 | if((*cmp)(rt, stepson) >= 0 || (*cmp)(lf, stepson) >= 0) { 144 | break; 145 | } 146 | } 147 | 148 | ar[i++] = stepson; 149 | head = stepson; 150 | trail = pntz(p); 151 | shr(p, trail); 152 | pshift += trail; 153 | trusty = 0; 154 | } 155 | if(!trusty) { 156 | cycle(width, ar, i); 157 | sift(head, width, cmp, pshift, lp); 158 | } 159 | } 160 | 161 | void qsort(void *base, size_t nel, size_t width, cmpfun cmp) 162 | { 163 | size_t lp[12*sizeof(size_t)]; 164 | size_t i, size = width * nel; 165 | unsigned char *head, *high; 166 | size_t p[2] = {1, 0}; 167 | int pshift = 1; 168 | int trail; 169 | 170 | if (!size) return; 171 | 172 | head = base; 173 | high = head + size - width; 174 | 175 | /* Precompute Leonardo numbers, scaled by element width */ 176 | for(lp[0]=lp[1]=width, i=2; (lp[i]=lp[i-2]+lp[i-1]+width) < size; i++); 177 | 178 | while(head < high) { 179 | if((p[0] & 3) == 3) { 180 | sift(head, width, cmp, pshift, lp); 181 | shr(p, 2); 182 | pshift += 2; 183 | } else { 184 | if(lp[pshift - 1] >= high - head) { 185 | trinkle(head, width, cmp, p, pshift, 0, lp); 186 | } else { 187 | sift(head, width, cmp, pshift, lp); 188 | } 189 | 190 | if(pshift == 1) { 191 | shl(p, 1); 192 | pshift = 0; 193 | } else { 194 | shl(p, pshift - 1); 195 | pshift = 1; 196 | } 197 | } 198 | 199 | p[0] |= 1; 200 | head += width; 201 | } 202 | 203 | trinkle(head, width, cmp, p, pshift, 0, lp); 204 | 205 | while(pshift != 1 || p[0] != 1 || p[1] != 0) { 206 | if(pshift <= 1) { 207 | trail = pntz(p); 208 | shr(p, trail); 209 | pshift += trail; 210 | } else { 211 | shl(p, 2); 212 | pshift -= 2; 213 | p[0] ^= 7; 214 | shr(p, 1); 215 | trinkle(head - lp[pshift] - width, width, cmp, p, pshift + 1, 1, lp); 216 | shl(p, 1); 217 | p[0] |= 1; 218 | trinkle(head - width, width, cmp, p, pshift, 1, lp); 219 | } 220 | head -= width; 221 | } 222 | } 223 | -------------------------------------------------------------------------------- /frontend/c/shadowprov/shadowprov-cflags: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | LIBCRUNCH_BASE="$( readlink -f "$(dirname "$0" )"/../../.. )" 4 | LIBALLOCS_BASE="$( readlink -f "$(dirname "$0" )"/../../../../liballocs )" 5 | 6 | case "$0" in 7 | (*cflags|*cppflags) 8 | "${LIBCRUNCH_BASE}"/frontend/cilpp/bin/cilpp-cflags | tr '\n' ' ' 9 | /bin/echo \ 10 | -Wp,-plugin,${LIBALLOCS_BASE}/tools/lang/c/cilallocs/cilallocs.cmxs \ 11 | -include "${LIBALLOCS_BASE}"/include/liballocs_cil_inlines.h \ 12 | -Wp,-plugin,${LIBCRUNCH_BASE}/frontend/c/alloclocals/alloclocals.cmxs \ 13 | -Wp,-fpass-alloclocals \ 14 | -Wp,-plugin,${LIBALLOCS_BASE}/tools/lang/c/monalloca/monalloca.cmxs \ 15 | -Wp,-fpass-monalloca \ 16 | -Wp,-plugin,"${LIBCRUNCH_BASE}"/frontend/c/shadow/shadow.cmxs \ 17 | -Wp,-plugin,"${LIBCRUNCH_BASE}"/frontend/c/shadowprov/shadowprov.cmxs \ 18 | -Wp,-fpass-shadowprov \ 19 | -include "${LIBCRUNCH_BASE}"/frontend/c/shadowprov/shadowprov_helpers.h \ 20 | -fno-builtin-memcpy 21 | ;; 22 | (*ldflags) 23 | /bin/echo -Wl,-plugin,"${LIBCRUNCH_BASE}"/frontend/c/shadowprov/gold-plugin.so \ 24 | -Wl,-rpath,"${LIBCRUNCH_BASE}"/lib \ 25 | -Wl,-rpath,"${LIBCRUNCH_BASE}"/frontend/c/shadowprov \ 26 | -Wl,@"${LIBCRUNCH_BASE}"/frontend/c/shadowprov/wrap.ldopts \ 27 | -Wl,--export-dynamic \ 28 | -Wl,--emit-relocs 29 | ;; 30 | (*) echo "Did not understand \$0: $0" 1>&2 31 | ;; 32 | esac 33 | -------------------------------------------------------------------------------- /frontend/c/shadowprov/shadowprov-ldflags: -------------------------------------------------------------------------------- 1 | shadowprov-cflags -------------------------------------------------------------------------------- /frontend/c/shadowprov/shadowprov_rtdecls.h: -------------------------------------------------------------------------------- 1 | /* Can we make these common symbols? */ 2 | __thread unsigned long *__shadow_sp; 3 | 4 | -------------------------------------------------------------------------------- /frontend/c/shadowprov/test-addrof.c: -------------------------------------------------------------------------------- 1 | int main(void) 2 | { 3 | int x; 4 | return (int)(unsigned long) &x % 255; 5 | } 6 | -------------------------------------------------------------------------------- /frontend/c/shadowprov/test-fail-materialise.c: -------------------------------------------------------------------------------- 1 | #include 2 | int main(void) 3 | { 4 | char *safe_byte = (char*) main; 5 | printf("Got as far as reading one byte: %d\n", *safe_byte); 6 | fflush(stdout); 7 | char *a_byte = (char*) 0x410000; 8 | char c = *a_byte; 9 | printf("We should not get *this* far\n"); 10 | return c; 11 | } 12 | -------------------------------------------------------------------------------- /frontend/c/shadowprov/test-hello.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(void) 4 | { 5 | printf("Hello, world!\n"); 6 | return 0; 7 | } 8 | -------------------------------------------------------------------------------- /frontend/c/shadowprov/test-malloc.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | char *f(void *arg) 6 | { 7 | char *pc = (char*) arg + 1; 8 | *pc = 42; 9 | return pc; 10 | } 11 | 12 | int main(void) 13 | { 14 | char *ret = f(malloc(42)); 15 | return ((intptr_t) ret) % *ret; 16 | } 17 | -------------------------------------------------------------------------------- /frontend/c/shadowprov/test-retptr.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main(void) 6 | { 7 | void *block = malloc(42); 8 | return ((intptr_t) block) % 256; 9 | } 10 | -------------------------------------------------------------------------------- /frontend/c/shadowprov/test-vprintf.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void doit(int n, ...) 5 | { 6 | va_list ap; 7 | va_start(ap, n); 8 | vprintf("%d: ", ap); 9 | va_end(ap); 10 | } 11 | 12 | int main(void) 13 | { 14 | printf("It says :"); 15 | doit(42, 42); 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /frontend/c/shadowprov/tools.shadowprov: -------------------------------------------------------------------------------- 1 | [{cmd: "gcc-4.9", 2 | args: "-O2 -std=gnu11 -Wno-unused-variable -pthread `/home/stephen/work/devel/libcrunch.hg/frontend/c/shadowprov/shadowprov-cflags` `/home/stephen/work/devel/libcrunch.hg/frontend/c/shadowprov/shadowprov-ldflags` -g -save-temps", 3 | name: "gcc-4.9-shadowprov", 4 | run_prefix: "LD_PRELOAD=/home/stephen/work/devel/libcrunch.hg/lib/libcrunch_preload.so " 5 | }] 6 | -------------------------------------------------------------------------------- /frontend/c/src/Makefile: -------------------------------------------------------------------------------- 1 | DEPS := 2 | 3 | LIBALLOCS ?= ../../../../liballocs/ 4 | ALLOCSITES ?= $(LIBALLOCS)/tools/ 5 | 6 | CXXFLAGS += -std=c++0x -g -O0 -I$(ALLOCSITES) 7 | CXXFLAGS += -Wno-deprecated-declarations # while we're using old libdwarfpp -- FIXME 8 | LDFLAGS += -L`pwd` -Wl,-R`pwd` -L$(ALLOCSITES) -Wl,-R$(realpath $(ALLOCSITES)) 9 | LDLIBS += -lallocstool -lcxxgen -ldwarfpp -ldwarf -lboost_regex -lboost_filesystem -lboost_system -lboost_serialization -lc++fileno -lsrk31c++ -lelf 10 | 11 | CPP_SRC := $(wildcard *.cpp) 12 | 13 | default: # base-types-translation #lower-typenames 14 | 15 | .PHONY: clean 16 | clean: 17 | rm -f *.o .*.d lower-typenames base-types-translation 18 | 19 | CPP_DEPS := $(patsubst %.cpp,.%.d,$(CPP_SRC)) 20 | DEPS := $(CPP_DEPS) 21 | 22 | $(CPP_DEPS): .%.d : %.cpp 23 | $(CXX) -MM $(CXXFLAGS) "$<" > "$@" 24 | 25 | ifneq ($(MAKECMDGOALS),clean) 26 | -include $(DEPS) 27 | endif 28 | 29 | # GAH... for some reason GNU Make needs this rule to avoid trying 30 | # to link the .o using $(CC) instead of $(CXX). 31 | %: %.cpp 32 | $(CXX) $(LDFLAGS) $(CXXFLAGS) -o "$@" "$<" $(LDLIBS) 33 | 34 | lower-typenames: lower-typenames.cpp $(ALLOCSITES)/liballocstool.a 35 | base-types-translation: base-types-translation.cpp $(ALLOCSITES)/liballocstool.a 36 | -------------------------------------------------------------------------------- /frontend/cilpp/Makefile: -------------------------------------------------------------------------------- 1 | THIS_MAKEFILE := $(lastword $(MAKEFILE_LIST)) 2 | SRCROOT := $(realpath $(dir $(THIS_MAKEFILE))/../..) 3 | include $(SRCROOT)/config.mk 4 | 5 | .PHONY: default 6 | default: src 7 | 8 | .PHONY: src 9 | src: 10 | $(MAKE) -C src 11 | 12 | .PHONY: clean 13 | clean: 14 | $(MAKE) -C src clean 15 | -------------------------------------------------------------------------------- /frontend/cilpp/bin/cc: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | case "$0" in 4 | (*pbcc) CRUNCH_CONFIG=p ;; 5 | (*Pbcc) CRUNCH_CONFIG=P ;; 6 | (*mbcc) CRUNCH_CONFIG=m ;; 7 | (*Mbcc) CRUNCH_CONFIG=M ;; 8 | (*tbcc) CRUNCH_CONFIG=t ;; 9 | (*Tbcc) CRUNCH_CONFIG=T ;; 10 | (*sbcc) CRUNCH_CONFIG=s ;; 11 | (*Sbcc) CRUNCH_CONFIG=S ;; 12 | (*fbcc) CRUNCH_CONFIG=f ;; 13 | (*Fbcc) CRUNCH_CONFIG=F ;; 14 | (*bcc) CRUNCH_CONFIG=p ;; 15 | (*xcc) CRUNCH_CONFIG=x ;; 16 | (*cc) CRUNCH_CONFIG=default ;; 17 | (*) echo "Unrecognised config: $0" 1>&2; exit 1 ;; 18 | esac 19 | 20 | export CRUNCH_CONFIG 21 | exec \ 22 | gcc \ 23 | -no-integrated-cpp \ 24 | -wrapper "${0%/*}"/wrapper -Wl,-plugin,"${0%/*}"/../../../../liballocs/tools/gold-plugin.so \ 25 | "$@" 26 | -------------------------------------------------------------------------------- /frontend/cilpp/bin/cc1: -------------------------------------------------------------------------------- 1 | wrapper -------------------------------------------------------------------------------- /frontend/cilpp/bin/cilpp: -------------------------------------------------------------------------------- 1 | ../src/cilpp -------------------------------------------------------------------------------- /frontend/cilpp/bin/cilpp-cflags: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # FIXME: do these properly 4 | LIBCRUNCH_BASE="$( readlink -f "$(dirname "$0" )"/../../.. )" 5 | LIBALLOCS_BASE="$( readlink -f "$(dirname "$0" )"/../../../../liballocs )" 6 | 7 | case "$0" in 8 | (*cflags|*cppflags) 9 | /bin/echo -no-integrated-cpp -wrapper "${LIBCRUNCH_BASE}"/frontend/cilpp/bin/wrapper 10 | ;; 11 | (*ldflags) # HACK: this is the liballocs-specific config, unlike the above 12 | /bin/echo -Wl,-plugin,"${LIBALLOCS_BASE}"/tools/.libs/gold-plugin.so \ 13 | -Wl,-rpath,"${LIBCRUNCH_BASE}"/lib -Wl,-rpath,"${LIBALLOCS_BASE}"/lib 14 | ;; 15 | (*) echo "Did not understand \$0: $0" 1>&2 16 | ;; 17 | esac 18 | -------------------------------------------------------------------------------- /frontend/cilpp/bin/cilpp-cppflags: -------------------------------------------------------------------------------- 1 | cilpp-cflags -------------------------------------------------------------------------------- /frontend/cilpp/bin/cilpp-ldflags: -------------------------------------------------------------------------------- 1 | cilpp-cflags -------------------------------------------------------------------------------- /frontend/cilpp/bin/wrapper: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # FIXME: rewrite this in C, or at least as a POSIX shell script. 3 | 4 | # Using gcc's -wrapper option, the compiler driver will invoke 5 | # us instead of cpp, cc1, etc., with the full command path as 6 | # $1. We want to substitute cilpp in the right places. 7 | # NOTE: this whole thing is necessary only because the driver 8 | # does not want to run `cpp' ever... it uses cc1 -E. 9 | # 10 | # clang does not (last I checked) support -wrapper, but I 11 | # imagine it's only a matter of time. 12 | 13 | # If we are symlinked under a name ending '-cflags', '-cppflags', 14 | # '-ldflags' etc, we print out the options that one should pass 15 | # to the compiler for the wrapper to be employed. So you can do 16 | # 17 | # gcc `/path/to/cilpp/cilpp-cflags` <... normal gcc args...> 18 | # 19 | # to run with cilpp. 20 | case "$0" in 21 | (*cflags|*cppflags) 22 | /bin/echo -no-integrated-cpp -wrapper "$(readlink -f "$(dirname "$0")")"/wrapper 23 | exit 0 24 | ;; 25 | (*ldflags) 26 | # we don't interfere with linking, so no extra ldflags 27 | exit 0 28 | ;; 29 | (*) # silently continue, i.e. actually act as the wrapper command 30 | ;; 31 | esac 32 | 33 | debug_print () { 34 | lvl="$1" 35 | shift 36 | if [[ "$DEBUG_CC" -ge $lvl ]]; then 37 | echo "$@" 38 | fi 39 | } 40 | 41 | is_pp () { 42 | saw_pp=0 43 | outpos=0 44 | while shift; do 45 | ctr="$(( $ctr + 1 ))" 46 | if [[ -z "$1" ]]; then continue; fi 47 | case "$1" in 48 | (-o) outfile="$2"; outpos="$(( $ctr + 1 ))";; 49 | (-E) saw_pp=1 ;; 50 | esac 51 | done 52 | # if we're only preprocessing, or if we have no explicit output file, just run cc1 53 | if [ "$saw_pp" -eq 0 ] || [ $outpos -eq 0 ]; then false; else true; fi 54 | } 55 | 56 | run_with_replacement_outfile () { 57 | replacement="$1" 58 | declare -a args 59 | ctr=0 60 | while shift; do 61 | ctr="$(( $ctr + 1 ))" 62 | if [[ -z "$1" ]]; then continue; fi 63 | case "$1" in 64 | (-o) args[$ctr]="$1"; args[$(( $ctr + 1 ))]="$replacement"; shift; ctr="$(( $ctr + 1 ))" ;; 65 | (*) args[$ctr]="$1" ;; 66 | esac 67 | done 68 | debug_print 1 "Running + replacement outfile: ${args[@]}" 1>&2 69 | "${args[@]}" 70 | } 71 | 72 | run_with_replacement_infile () { 73 | # We are running cpp 74 | # PROBLEM: how do we identify the input filename? 75 | # Doing this generally means understanding cpp's entire command-line syntax. 76 | # We instead use a HACK: 77 | # for gcc we only need understand the options -E -quiet -imultiarch x86_64-linux-gnu 78 | # ... which (1) come first, and (2) cpp *doesn't* understand. 79 | replacement="$1" 80 | debug_print 1 "Trying to replace input file given args: $@" 1>&2 81 | shift 82 | declare -a args 83 | args[1]="$1" 84 | ctr=2 85 | orig_infile="" 86 | must_read_arg="" 87 | handle_possible_infile () { 88 | if [[ -z "$orig_infile" ]]; then 89 | debug_print 1 "We think the input file is $1" 1>&2 90 | orig_infile="$1"; 91 | args[$ctr]="$replacement" 92 | else 93 | args[$ctr]="$1" 94 | fi 95 | } 96 | while shift; do 97 | ctr="$(( $ctr + 1 ))" 98 | if [[ -n "$must_read_arg" ]]; then 99 | args[$ctr]="$1" 100 | must_read_arg="" 101 | continue 102 | fi 103 | if [[ -z "$1" ]]; then continue; fi 104 | case "$1" in 105 | (-E|-quiet) ;; # skip it! 106 | (-D|-U|-include) must_read_arg=1; args[$ctr]="$1" ;; 107 | (-imultiarch) shift || break ;; # skip it and its arg! 108 | (--) no_more_options=1 ;; 109 | (-*) if [[ -z "$no_more_options" ]]; then args[$ctr]="$1"; else handle_possible_infile "$1"; fi ;; 110 | (*) handle_possible_infile "$1" ;; 111 | esac 112 | done 113 | debug_print 1 "Running + replacement infile ($replacement): ${args[@]}" 1>&2 114 | "${args[@]}" 115 | } 116 | 117 | debug_print 1 "\$1 is $1" 1>&2 118 | 119 | cmd_to_run="$1" 120 | case "$cmd_to_run" in 121 | (*/cc1) 122 | ctr=0 123 | # if we're only preprocessing, or if we have no explicit output file, just run cc1 124 | if ! is_pp "$@"; then 125 | debug_print 1 "We think we don't have to substitute preprocessing." 1>&2 126 | debug_print 1 "Running non-substituted: $@" 1>&2 127 | exec "$@" 128 | else 129 | # run cilpp, which should take care of the temporary file thing 130 | driver="$(readlink /proc/$PPID/exe)" 131 | debug_print 1 "driver binary is probably $driver" 1>&2 132 | debug_print 1 "outpos is $outpos" 1>&2 133 | debug_print 1 "outfile is $outfile" 1>&2 134 | # do the cpp, then run CIL 135 | debug_print 1 "We think we do have to substitute preprocessing; args $@" 1>&2 136 | #shift # get rid of the cc1 "argument" 137 | #run_with_replacement_infile "$tmpfile" 138 | declare -a cpp_options 139 | cpp_options[0]="-driver" 140 | cpp_options[1]="$driver" 141 | ctr=2 142 | while shift || break; do 143 | debug_print 1 "\$# is $#, \$1 is '$1'" 1>&2 144 | case "$1" in 145 | # filter out non-cpp args 146 | ("-imultiarch") shift || break ;; # skip arg too 147 | ("-quiet") ;; # skip just it 148 | ('') ;; # FIXME: this shouldn't happen! 149 | (*) 150 | debug_print 1 "Snarfing $1" 1>&2 151 | cpp_options[$ctr]="$1" 152 | ctr=$(( $ctr + 1)) 153 | ;; 154 | esac 155 | done 156 | 157 | debug_print 1 "$(dirname "$0")"/cilpp "${cpp_options[@]}" 1>&2 158 | exec "$(dirname "$0")"/cilpp "${cpp_options[@]}" 159 | #exec "$cmd_to_run" "$@" 160 | # 161 | #tmpfile="$(mktemp)" || exit 1 162 | #debug_print 1 "Substituted $tmpfile in place of $outfile" 1>&2 163 | #run_with_replacement_outfile "$tmpfile" "$@" && \ 164 | fi 165 | ;; 166 | (*) debug_print 1 "Non-wrapping: $@" 1>&2 167 | exec "$@" 168 | ;; 169 | esac 170 | -------------------------------------------------------------------------------- /frontend/cilpp/src/Makefile: -------------------------------------------------------------------------------- 1 | THIS_MAKEFILE := $(lastword $(MAKEFILE_LIST)) 2 | SRCROOT := $(realpath $(dir $(THIS_MAKEFILE))/../../..) 3 | include $(SRCROOT)/config.mk 4 | 5 | .PHONY: default 6 | default: cilpp 7 | 8 | # FIXME 9 | OCAMLFIND ?= ocamlfind 10 | LIBALLOCS ?= /home/stephen/work/devel/liballocs.hg 11 | LIBALLOCS_BASE ?= $(realpath $(LIBALLOCS)) 12 | CIL_INSTALL ?= $(LIBALLOCS)/tools/lang/c/cil 13 | #vpath %.cma $(CIL_INSTALL)/lib/cil 14 | 15 | OCAMLOPTFLAGS += -fPIC 16 | CFLAGS += -fPIC 17 | 18 | OCAMLFIND ?= ocamlfind 19 | OCAMLFLAGS += -package findlib -package dynlink -I $(CIL_INSTALL)/lib/cil 20 | OCAMLFLAGS += -I $(dir $(THIS_MAKEFILE))/lib -I $(LIBALLOCS_BASE)/tools/lang/c/cilallocs 21 | 22 | export LIBALLOCS_BASE 23 | export LIBALLOCS 24 | export OCAMLFLAGS 25 | export OCAMLFIND 26 | export CIL_INSTALL 27 | 28 | 29 | # IMPORTANT: only list cmxa files here iff they are *not* 30 | # covered by a -package argument to ocamlfind -- CHECK the 31 | # Makefile in our parent directory too (it should be clean). 32 | # 33 | # The effect of -package is to delegate to ocamlfind the 34 | # inclusion by -I of the relevant package. The effect of 35 | # -linkpkg is to delegate # to ocamlfind the inclusion of the 36 | # package cmxa on the command line. If we both use -linkpkg 37 | # with -package of a given package, and give the cmxa on the 38 | # command line, bad things can happen. 39 | # 40 | # So list only the packages whose cmxa files live in either 41 | # (1) locations we can predict from this Makefile, or 42 | # (2) locations that are "standard" so don't need specifying. 43 | # That means standard OCaml libs are okay to give as a .cmxa, 44 | # and CIL libs are okay, but findlib is not; use -package. 45 | # NOTE also that order matters: put more depended-on entries 46 | # further left (i.e. the opposite of the usual link order). 47 | OCAMLLIBS := str.cmxa nums.cmxa unix.cmxa cil.cmxa #frontc.cmxa 48 | # we use -linkall to include the whole cmxa, so that plugins can 49 | # dynlink against any of its symbols. 50 | cilpp: cilpp.ml mkstemp_stubs.o $(CIL_INSTALL)/lib/cil/cil.cmxa 51 | $(OCAMLFIND) ocamlopt -o "$@" $(OCAMLOPTFLAGS) $(OCAMLFLAGS) $(OCAMLLIBS) $(filter-out %/cil.cmxa,$+) -linkpkg -linkall 52 | 53 | %.cmxs: %.cmx 54 | $(OCAMLFIND) ocamlopt -shared -o "$@" $(OCAMLOPTFLAGS) $(OCAMLFLAGS) $+ 55 | %.cmx %.cmi: %.ml 56 | $(OCAMLFIND) ocamlopt -o "$@" $(OCAMLOPTFLAGS) $(OCAMLFLAGS) -c "$<" 57 | %.cmo %.cmi: %.ml 58 | $(OCAMLFIND) ocamlc -o "$@" $(OCAMLFLAGS) -c "$<" 59 | %.cma: %.cmo 60 | $(OCAMLFIND) ocamlc -o "$@" $(OCAMLFLAGS) -a $+ 61 | 62 | clean: 63 | rm -f *.o *.cmxa *.cmx *.cmo *.cmxs 64 | -------------------------------------------------------------------------------- /frontend/cilpp/src/mkstemp_stubs.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | // HACK: internal OCaml Unix module detail 12 | value unix_error_of_code(int code); 13 | 14 | CAMLprim value 15 | caml_mkstemp(value templ) 16 | { 17 | CAMLparam1(templ); 18 | const char *s = String_val(templ); 19 | char *s_dup = strdup(s); 20 | int fd = mkstemp(s_dup); 21 | if (fd == -1) 22 | { 23 | /* raise the Unix.Unix_error for our errno -- 24 | Leroy and Remi say 25 | (https://ocaml.github.io/ocamlunix/ocamlunix.pdf) 26 | 27 | "Unless otherwise indicated, all functions in the Unix module raise the exception 28 | Unix_error in case of error. 29 | 30 | exception Unix_error of error * string * string 31 | 32 | The second argument of the Unix_error exception is the name of the system call 33 | that raised the error. The third argument identifies, if possible, the object on 34 | which the error occurred; for example, in the case of a system call taking a file 35 | name as an argument, this file name will be in the third position in Unix_error. 36 | Finally, the first argument of the exception is an error code indicating the nature 37 | of the error. It belongs to the variant type error: 38 | 39 | type error = E2BIG | EACCES | EAGAIN | ... | EUNKNOWNERR of int 40 | */ 41 | CAMLlocal1(tup); 42 | tup = caml_alloc(3, 0); 43 | Store_field(tup, 0, unix_error_of_code(errno)); 44 | Store_field(tup, 1, caml_copy_string("mkstemp")); 45 | Store_field(tup, 2, templ); 46 | value exn = *caml_named_value("Unix.Unix_error"); 47 | 48 | free(s_dup); 49 | caml_raise_with_arg(exn, Val_int(errno)); 50 | } 51 | 52 | CAMLlocal1(out); 53 | out = caml_alloc(2, 0); 54 | Store_field(out, 0, fd); 55 | Store_field(out, 1, caml_copy_string(s_dup)); 56 | free(s_dup); 57 | CAMLreturn(out); 58 | //return out; /* HACK: assuming it's a mere int */ 59 | } 60 | 61 | CAMLprim value 62 | caml_mkstemps(value templ, value suffixlen) 63 | { 64 | CAMLparam2(templ, suffixlen); 65 | const char *s = String_val(templ); 66 | int suffixl = Int_val(suffixlen); 67 | char *s_dup = strdup(s); 68 | int fd = mkstemps(s_dup, suffixl); 69 | if (fd == -1) 70 | { 71 | /* see comment in caml_mkstemp */ 72 | CAMLlocal1(tup); 73 | tup = caml_alloc(3, 0); 74 | Store_field(tup, 0, unix_error_of_code(errno)); 75 | Store_field(tup, 1, caml_copy_string("mkstemps")); 76 | Store_field(tup, 2, templ); 77 | value exn = *caml_named_value("Unix.Unix_error"); 78 | 79 | free(s_dup); 80 | caml_raise_with_arg(exn, Val_int(errno)); 81 | } 82 | 83 | CAMLlocal1(out); 84 | out = caml_alloc(2, 0); 85 | Store_field(out, 0, fd); 86 | Store_field(out, 1, caml_copy_string(s_dup)); 87 | free(s_dup); 88 | CAMLreturn(out); 89 | //return out; /* HACK: assuming it's a mere int */ 90 | } 91 | -------------------------------------------------------------------------------- /frontend/fortran/bin/crunchfc: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # ... or for debugging, use something like 3 | #!/home/stephen/bin/gdbrun python 4 | 5 | # Compiler wrapper for libcrunch. 6 | import os, sys, re, subprocess, tempfile 7 | 8 | # HACK 9 | if "LIBALLOCS" in os.environ: 10 | liballocs_base = os.path.realpath(os.environ["LIBALLOCS"]) 11 | else: 12 | liballocs_base = os.path.realpath(os.path.dirname(sys.argv[0]) + "/../../../../liballocs/") 13 | sys.path.append(liballocs_base + "/tools") 14 | sys.path.append(liballocs_base + "/tools/lang/fortran/lib") 15 | from allocsfc import AllocsFC 16 | 17 | class CrunchFC(AllocsFC): 18 | 19 | def fixupDotO(self, filename, errfile): 20 | # no instrumentation yet, so no uniqtype refs to fix up 21 | return AllocsFC.fixupDotO(self, filename, errfile) 22 | 23 | def getLibNameStem(self): 24 | return "crunch" 25 | 26 | def getDummyWeakObjectNameStem(self): 27 | return "stubs" 28 | 29 | def getLinkPath(self): 30 | return os.path.dirname(__file__) + "/../../../lib" 31 | 32 | if __name__ == '__main__': 33 | wrapper = CrunchFC() 34 | ret = wrapper.main() 35 | exit(ret) 36 | 37 | -------------------------------------------------------------------------------- /include/libcrunch.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBCRUNCH_H_ 2 | #define LIBCRUNCH_H_ 3 | 4 | #include "liballocs.h" 5 | 6 | #if !defined(NO_PURE) && !defined(PURE) 7 | #define PURE __attribute__((pure)) 8 | #elif !defined(PURE) 9 | #define PURE 10 | #endif 11 | 12 | extern int __libcrunch_debug_level; 13 | extern _Bool __libcrunch_is_initialized __attribute__((weak)); 14 | #ifdef LIBCRUNCH_EXTENDED_COUNTS 15 | extern unsigned long __libcrunch_aborted_init __attribute__((weak)); 16 | extern unsigned long __libcrunch_trivially_succeeded __attribute__((weak)); 17 | extern unsigned long __libcrunch_checked_pointer_adjustments __attribute__((weak)); 18 | #endif 19 | extern unsigned long __libcrunch_begun __attribute__((weak)); 20 | extern unsigned long __libcrunch_aborted_typestr __attribute__((weak)); 21 | extern unsigned long __libcrunch_failed __attribute__((weak)); 22 | extern unsigned long __libcrunch_succeeded __attribute__((weak)); 23 | extern unsigned long __libcrunch_is_a_hit_cache __attribute__((weak)); 24 | extern unsigned long __libcrunch_created_invalid_pointer __attribute__((weak)); 25 | extern unsigned long __libcrunch_fetch_bounds_called __attribute__((weak)); 26 | extern unsigned long __libcrunch_fetch_bounds_missed_cache __attribute__((weak)); 27 | extern unsigned long __libcrunch_primary_secondary_transitions __attribute__((weak)); 28 | extern unsigned long __libcrunch_fault_handler_fixups __attribute__((weak)); 29 | 30 | int __libcrunch_global_init(void) __attribute__((weak)); 31 | // declare as const void *-returning, to simplify trumptr 32 | const void *__libcrunch_typestr_to_uniqtype(const char *typestr) __attribute__((weak)); 33 | void *__libcrunch_my_typeobj(void) __attribute__((weak)); 34 | int __is_a_internal(const void *obj, const void *uniqtype) __attribute__((weak)) PURE __attribute__((hot)); 35 | int __like_a_internal(const void *obj, const void *uniqtype) __attribute__((weak)) PURE __attribute__((hot));; 36 | int __named_a_internal(const void *obj, const void *typestr) __attribute__((weak)) PURE __attribute__((hot));; 37 | int __check_args_internal(const void *obj, int nargs, ...) __attribute__((weak)) PURE __attribute__((hot));; 38 | int __is_a_function_refining_internal(const void *obj, const void *uniqtype) __attribute__((weak)) PURE __attribute__((hot)); 39 | int __is_a_function_pointer_of_degree_internal(const void *obj, int d) __attribute__((weak)) PURE __attribute__((hot)); 40 | int __can_hold_pointer_internal(const void *target, const void *value) __attribute__((weak)) PURE __attribute__((hot)); 41 | 42 | /* The main public API to libcrunch is through several small functions 43 | * which are *always* inlined. NOTE: repeat these in trumptr.ml so that 44 | * the instrumentation can add them to code which doesn't include this header. */ 45 | 46 | // if we're not compiling under CIL, include the things that trumptr would define 47 | #ifndef CIL 48 | #include "libcrunch_cil_inlines.h" 49 | #endif 50 | __libcrunch_bounds_t __fetch_bounds_internal(const void *ptr, const void *derived_ptr, const struct uniqtype *u); 51 | void * __check_derive_ptr_internal(const void *derived, const void *derivedfrom, 52 | __libcrunch_bounds_t *derivedfrom_bounds, struct uniqtype *t) PURE; 53 | 54 | /* our own private assert */ 55 | static inline void 56 | (__attribute__((always_inline,gnu_inline)) __libcrunch_private_assert) (_Bool cond, const char *reason, 57 | const char *f, unsigned l, const char *fn) 58 | { 59 | #ifndef NDEBUG 60 | if (!cond) __assert_fail(reason, f, l, fn); 61 | #endif 62 | } 63 | 64 | static inline void (__attribute__((always_inline,gnu_inline)) __libcrunch_ensure_init) (void) 65 | { 66 | __libcrunch_private_assert(__libcrunch_check_init() == 0, "libcrunch init", 67 | __FILE__, __LINE__, __func__); 68 | } 69 | 70 | #endif 71 | -------------------------------------------------------------------------------- /include/stubgen_softbound.h: -------------------------------------------------------------------------------- 1 | /* These wrappers are only sane if void* carry bounds. 2 | * Otherwise there are no pointers to propagate. */ 3 | 4 | #ifdef LIBCRUNCH_VOID_POINTERS_HAVE_BOUNDS 5 | 6 | #define do_caller_wrapper_init(name) \ 7 | _Bool __caller_is_inst = __tweak_argument_bounds_cookie(__wrap_## name); \ 8 | int argi = 0; \ 9 | int argpeek_off = 0; \ 10 | int realarg_off = 0; \ 11 | unsigned long *saved_bsp = __bounds_sp; \ 12 | 13 | #define round_down_size(sz, round_to) \ 14 | ((round_to) * ((sz) / (round_to))) 15 | extern unsigned long __liballocs_get_alloc_size(const void *obj); 16 | /* It's wrong to use the size_arg, because e.g. for calloc-alikes, 17 | * that doesn't tell us how *many* of the object are being created. 18 | * So ask liballocs how big it is. Round that to a multiple of the 19 | * size arg. */ 20 | #define do_ret_p(name) \ 21 | __bounds_sp = saved_bsp; \ 22 | unsigned long result_sz = __liballocs_get_alloc_size(real_retval); \ 23 | unsigned long result_sz_rounded = round_down_size(result_sz, size_arg_ ## name); \ 24 | __libcrunch_bounds_t result_bounds = __make_bounds(real_retval, \ 25 | (char*) real_retval + result_sz_rounded ); \ 26 | __push_local_result_bounds(__caller_is_inst, result_bounds); 27 | 28 | #define do_ret_z(name) \ 29 | __bounds_sp = saved_bsp; 30 | 31 | #define do_ret_i(name) \ 32 | __bounds_sp = saved_bsp; \ 33 | 34 | #define do_ret_void(name) \ 35 | __bounds_sp = saved_bsp; 36 | 37 | #define do_arginit_p(name) \ 38 | __libcrunch_bounds_t argbound_ ## name = __peek_argument_bounds(__caller_is_inst, argpeek_off++, \ 39 | name, #name); 40 | 41 | #define do_arginit_P(name) do_arginit_p(name) 42 | 43 | /* For any pointer argument, we have to forward its bounds. */ 44 | #define pre_realarg_p(argname) \ 45 | __push_local_argument_bounds(argbound_ ## argname); 46 | 47 | #define pre_realarg_P(argname) \ 48 | pre_realarg_p(argname) 49 | 50 | #define pre_realcall(callee, ...) \ 51 | __push_argument_bounds_cookie(callee); 52 | 53 | #endif 54 | -------------------------------------------------------------------------------- /kernel/Makefile: -------------------------------------------------------------------------------- 1 | default: 2 | $(MAKE) -C dev-ones 3 | 4 | clean: 5 | $(MAKE) -C dev-ones clean 6 | -------------------------------------------------------------------------------- /kernel/dev-ones/Makefile: -------------------------------------------------------------------------------- 1 | default: 2 | $(MAKE) -C linux 3 | 4 | clean: 5 | $(MAKE) -C linux clean 6 | -------------------------------------------------------------------------------- /kernel/dev-ones/linux/Makefile: -------------------------------------------------------------------------------- 1 | obj-m += dev_ones.o 2 | KDIR ?= /lib/modules/$(shell uname -r)/build 3 | THIS_MAKEFILE := $(lastword $(MAKEFILE_LIST)) 4 | 5 | default: dev_ones.ko 6 | 7 | dev_ones.ko: 8 | $(MAKE) -C $(KDIR) M=$(realpath $(dir $(THIS_MAKEFILE))) modules 9 | 10 | clean: 11 | rm -f *.cmd *.o *.ko *.mod.c Module.symvers modules.order 12 | -------------------------------------------------------------------------------- /lib/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: default symlinks 2 | 3 | default: symlinks wrap.ldopts 4 | 5 | symlinks: 6 | ln -sf ../src/libcrunch.so ../src/libcrunch_stubs.so ../src/libcrunch_preload.so ../src/libcrunch_preload.a . 7 | ln -sf ../src/libcrunch_stubs.o libcrunch_stubs.o 8 | ln -sf ../src/libcrunch_wrappers.o libcrunch_wrappers.o 9 | 10 | clean: 11 | rm -f *.o *.so 12 | 13 | wrap.ldopts: symlinks 14 | nm --format=posix libcrunch_wrappers.o | grep __wrap_ | \ 15 | sed -r 's/__wrap_([^[:blank:]]*).*/--wrap \1/' > "$@" \ 16 | || (rm -f "$@"; false) 17 | -------------------------------------------------------------------------------- /src/libcrunch_private.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBCRUNCH_PRIVATE_H_ 2 | #define LIBCRUNCH_PRIVATE_H_ 3 | 4 | /* x86_64 only, for now */ 5 | #if !defined(__x86_64__) && !defined(X86_64) 6 | #error Unsupported architecture. 7 | #endif 8 | 9 | #include "memtable.h" 10 | #include "heap_index.h" 11 | #include "liballocs_private.h" 12 | #include 13 | #include 14 | 15 | #include "libcrunch.h" 16 | #include "systrap.h" 17 | 18 | #undef debug_printf /* from liballocs */ 19 | extern FILE *crunch_stream_err __attribute__((visibility("hidden"))); 20 | /* Primitives for printing at a debug level. They take a stream 21 | * and a format-string message, either using varargs or a va_list. */ 22 | #define debug_fprintf_to_nohdr(strm, lvl, fmt, ...) do { \ 23 | if ((lvl) <= __libcrunch_debug_level) { \ 24 | fprintf((strm), fmt, ## __VA_ARGS__ ); \ 25 | } \ 26 | } while (0) 27 | #define debug_vfprintf_to_nohdr(strm, lvl, fmt, ap) do { \ 28 | if ((lvl) <= __libcrunch_debug_level) { \ 29 | vfprintf((strm), fmt, ap); \ 30 | } \ 31 | } while (0) 32 | 33 | /* Cooked operations for printing at a debug level. These use the 34 | * default stream, and emulate warnx by prepending the exec basename 35 | * and (optionally) a newline. */ 36 | #define debug_fprintf_to(strm, lvl, fmt, ...) \ 37 | debug_fprintf_to_nohdr(strm, lvl, "%s: " fmt, get_exe_basename(), ## __VA_ARGS__ ) 38 | #define debug_vfprintf_to(strm, lvl, fmt, ap) do { \ 39 | /* first print the header, then the va_list message */ \ 40 | debug_printf_to_nohdr(strm, lvl, "%s: " , get_exe_basename()); \ 41 | debug_printf_to_nohdr(strm, lvl, fmt, ap); \ 42 | } while (0) 43 | 44 | #define debug_println(lvl, fmt, ...) debug_fprintf_to(crunch_stream_err, lvl, fmt "\n", ## __VA_ARGS__ ) 45 | #define debug_printf(lvl, fmt, ...) debug_fprintf_to(crunch_stream_err, lvl, fmt, ## __VA_ARGS__ ) 46 | #define debug_printf_bare(lvl, fmt, ...) debug_fprintf_to_nohdr(crunch_stream_err, lvl, fmt, ## __VA_ARGS__ ) 47 | #define debug_vprintf_bare(lvl, fmt, ap) debug_vfprintf_to_nohdr(crunch_stream_err, lvl, fmt, ap) 48 | #define debug_vprintf(lvl, fmt, ap) debug_vfprintf_to(crunch_stream_err, lvl, fmt, ap) 49 | #define debug_vprintf_nohdr(lvl, fmt, ap) debug_vfprintf_to_nohdr(crunch_stream_err, lvl, fmt, ap) 50 | 51 | /* avoid dependency on libc headers (in this header only) */ 52 | void __assert_fail(const char *assertion, 53 | const char *file, unsigned int line, const char *function); 54 | void warnx(const char *fmt, ...); 55 | unsigned long malloc_usable_size (void *ptr); 56 | 57 | /* counters */ 58 | extern unsigned long __libcrunch_begun; 59 | #ifdef LIBCRUNCH_EXTENDED_COUNTS 60 | extern unsigned long __libcrunch_aborted_init; 61 | extern unsigned long __libcrunch_trivially_succeeded_null; 62 | extern unsigned long __libcrunch_checked_pointer_adjustments; 63 | #endif 64 | extern unsigned long __libcrunch_aborted_typestr; 65 | extern unsigned long __libcrunch_succeeded_by_specialization; 66 | extern unsigned long __libcrunch_failed_and_suppressed; 67 | extern unsigned long __libcrunch_failed_in_alloc; 68 | extern unsigned long __libcrunch_succeeded; 69 | extern unsigned long __libcrunch_is_a_hit_cache; 70 | extern unsigned long __libcrunch_created_invalid_pointer; 71 | extern unsigned long __libcrunch_fetch_bounds_called; 72 | extern unsigned long __libcrunch_fetch_bounds_missed_cache; 73 | 74 | /* Only defined in the real libcrunch (preload version, not stubs) */ 75 | extern int __libcrunch_really_loaded __attribute__((weak)); 76 | 77 | void __libcrunch_uncache_is_a(const void *allocptr, size_t size); 78 | void __libcrunch_uncache_all(const void *allocptr, size_t size); 79 | 80 | void __libcrunch_bounds_error_at(const void *derived, const void *derivedfrom, 81 | __libcrunch_bounds_t bounds, const void *addr); 82 | void __libcrunch_soft_deref_error_at(const void *ptr, __libcrunch_bounds_t bounds, const void *addr); 83 | 84 | void mmap_replacement(struct generic_syscall *s, post_handler *post) __attribute__((visibility("hidden"))); 85 | 86 | #ifdef __libcrunch_defined_unlikely 87 | #undef unlikely 88 | #endif 89 | #ifdef __libcrunch_defined_likely 90 | #undef likely 91 | #endif 92 | #ifdef __libcrunch_defined_assert 93 | #undef assert 94 | #endif 95 | 96 | #endif 97 | -------------------------------------------------------------------------------- /src/stubs.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include 3 | #include 4 | #include 5 | #include "libcrunch_private.h" 6 | 7 | _Bool __libcrunch_is_initialized = 1; 8 | extern _Bool our_init_flag __attribute__((visibility("hidden"),alias("__libcrunch_is_initialized"))); 9 | 10 | struct __liballocs_memrange_cache __libcrunch_fake_bounds_cache; // all zeroes 11 | 12 | int __libcrunch_debug_level __attribute__((weak)); 13 | 14 | unsigned long int __libcrunch_begun = 0; 15 | unsigned long int __libcrunch_failed = 0; 16 | unsigned long int __libcrunch_succeeded = 0; 17 | unsigned long int __libcrunch_aborted_typestr = 0; 18 | unsigned long int __libcrunch_is_a_hit_cache = 0; 19 | unsigned long int __libcrunch_created_invalid_pointer = 0; 20 | unsigned long int __libcrunch_fetch_bounds_called = 0; 21 | unsigned long int __libcrunch_fetch_bounds_missed_cache = 0; 22 | unsigned long int __libcrunch_primary_secondary_transitions = 0; 23 | unsigned long int __libcrunch_fault_handler_fixups = 0; 24 | unsigned long int __libcrunch_ptr_derivations = 0; 25 | unsigned long int __libcrunch_ptr_derefs = 0; 26 | unsigned long int __libcrunch_ptr_stores = 0; 27 | 28 | void **__libcrunch_bounds_bases_region_00; 29 | void **__libcrunch_bounds_bases_region_2a; 30 | void **__libcrunch_bounds_bases_region_7a; 31 | unsigned long *__libcrunch_bounds_sizes_region_00; 32 | unsigned long *__libcrunch_bounds_sizes_region_2a; 33 | unsigned long *__libcrunch_bounds_sizes_region_7a; 34 | 35 | static void print_exit_summary(void) 36 | { 37 | if (__libcrunch_ptr_derefs == 0 38 | && !getenv("LIBCRUNCH_ALWAYS_PRINT_EXIT_SUMMARY")) return; 39 | 40 | fprintf(stderr, "======================================================\n"); 41 | fprintf(stderr, "libcrunch stub runtime summary: \n"); 42 | fprintf(stderr, "------------------------------------------------------\n"); 43 | fprintf(stderr, "pointer dereferences: % 11ld\n", __libcrunch_ptr_derefs); 44 | fprintf(stderr, " of which stored shadowed pointer values:% 11ld\n", __libcrunch_ptr_stores); 45 | fprintf(stderr, "pointer derivations instrumented: % 11ld\n", __libcrunch_ptr_derivations); 46 | fprintf(stderr, "------------------------------------------------------\n"); 47 | fprintf(stderr, "out-of-bounds pointers created: % 11ld\n", __libcrunch_created_invalid_pointer); 48 | fprintf(stderr, "accesses trapped and emulated: % 11ld\n", 0ul /* FIXME */); 49 | fprintf(stderr, "calls to __fetch_bounds: % 11ld\n", __libcrunch_fetch_bounds_called /* FIXME: remove */); 50 | fprintf(stderr, " of which missed cache: % 11ld\n", __libcrunch_fetch_bounds_missed_cache); 51 | fprintf(stderr, "calls requiring secondary checks % 11ld\n", __libcrunch_primary_secondary_transitions); 52 | fprintf(stderr, "trap-pointer fixups in fault handler % 11ld\n", __libcrunch_fault_handler_fixups); 53 | fprintf(stderr, "======================================================\n"); 54 | } 55 | 56 | void __liballocs_systrap_init(void); 57 | static void init(void) __attribute__((constructor)); 58 | static void init(void) 59 | { 60 | /* It's critical that we detect whether we're being overridden, 61 | * and skip this init if so. The preload code in liballocs wants to 62 | * initialise systrap *only* after it has scanned /proc/self/maps, 63 | * so that it can accurately track mmappings. To test for overriddenness, 64 | * we use a hidden alias for something that will be overridden by our 65 | * overrider, here the init flag. */ 66 | //if (&__libcrunch_is_initialized == &our_init_flag) __liballocs_systrap_init(); 67 | /* HACK: the above is broken by LTO on gcc 5.x onwards (see bug 78407) 68 | * so instead use the is-really-loaded trick. */ 69 | _Bool libcrunch_is_loaded = (&__libcrunch_really_loaded); 70 | if (!libcrunch_is_loaded) 71 | { 72 | __liballocs_systrap_init(); 73 | atexit(print_exit_summary); 74 | } 75 | } 76 | 77 | void __libcrunch_scan_lazy_typenames(void *blah) {} 78 | 79 | int __libcrunch_check_init(void) 80 | { 81 | return 0; 82 | } 83 | 84 | int __libcrunch_global_init(void) 85 | { 86 | return 0; 87 | } 88 | 89 | int __is_a_internal(const void *obj, const void *r) 90 | { 91 | return 1; 92 | } 93 | 94 | int __like_a_internal(const void *obj, const void *r) 95 | { 96 | return 1; 97 | } 98 | 99 | int __loosely_like_a_internal(const void *obj, const void *r) 100 | { 101 | return 1; 102 | } 103 | 104 | int __named_a_internal(const void *obj, const void *r) 105 | { 106 | return 1; 107 | } 108 | 109 | int __check_args_internal(const void *obj, int nargs, ...) 110 | { 111 | return 1; 112 | } 113 | 114 | int __is_a_function_refining_internal(const void *obj, const void *r) 115 | { 116 | return 1; 117 | } 118 | int __is_a_pointer_of_degree_internal(const void *obj, int d) 119 | { 120 | return 1; 121 | } 122 | int __can_hold_pointer_internal(const void *obj, const void *target) 123 | { 124 | return 1; 125 | } 126 | 127 | __libcrunch_bounds_t __fetch_bounds_internal(const void *ptr, const void *derived, const struct uniqtype *t) 128 | { 129 | return __libcrunch_max_bounds(ptr); 130 | } 131 | 132 | void __libcrunch_bounds_error(const void *derived, const void *derivedfrom, 133 | __libcrunch_bounds_t bounds) 134 | { 135 | } 136 | void __libcrunch_soft_deref_error_at(const void *codeptr, __libcrunch_bounds_t bounds, const void *addr) 137 | { 138 | } 139 | 140 | struct uniqtype; 141 | struct __libcrunch_bounds_s; 142 | typedef struct __libcrunch_bounds_s __libcrunch_bounds_t; 143 | 144 | __libcrunch_bounds_t __fetch_bounds_ool(const void *ptr, const void *derived_ptr, struct uniqtype *t) 145 | { 146 | return __libcrunch_max_bounds(ptr); 147 | } 148 | 149 | __libcrunch_bounds_t __fetch_bounds_ool_via_dladdr(const void *ptr, const void *derived_ptr, struct uniqtype *t) 150 | { 151 | return __libcrunch_max_bounds(ptr); 152 | } 153 | 154 | void (__attribute__((nonnull(1))) __store_pointer_nonlocal_via_voidptrptr)(const void **dest, const void *srcval, __libcrunch_bounds_t val_bounds, struct uniqtype *static_guessed_srcval_pointee_type) 155 | { 156 | /* do nothing */ 157 | } 158 | 159 | void __ensure_bounds_in_cache(unsigned long ptrval, __libcrunch_bounds_t ptr_bounds, struct uniqtype *t) 160 | {} 161 | -------------------------------------------------------------------------------- /test/Future/fail-bounds-type-backin/fail-bounds-type-backin.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | /* "bad cast before adjust" (1) 7 | for (float *pf = ((float*) i) - 1; pf >= (float*) &is[0]; --pf) 8 | 9 | - what happens: we try to do arithmetic on a bad pointer, trying to 10 | bring it back into bounds... 11 | - what should happen: 12 | pointer stays trapped and 1-bounded, 13 | generating one error report every time it does arithmetic on such a pointer, 14 | using fault handler to allow it to continue? 15 | pointer gets "rectified" when it is brought back into bounds, 16 | i.e. we fetch new bounds after the bad arithmetic and see if they are good? 17 | */ 18 | 19 | int main(void) 20 | { 21 | char pad1[200]; 22 | int is[] = { 0, 1, 2, 3, 4 }; 23 | char pad2[200]; 24 | 25 | /* If we convert a trapped pointer to int, we should get a sensible value. */ 26 | int *i1 = &is[5]; 27 | unsigned long i = (unsigned long) i1; 28 | printf("The int we got is 0x%lx\n", i); 29 | assert(i - (unsigned long) &is[4] == sizeof (int)); 30 | 31 | /* If we convert it back to a float* when *out of bounds*, it should not be usable, 32 | * but __fetch_bounds might (ideally) let us sloppily accommodate it anyway. 33 | * If we convert it back to an in-bounds float*, it should do whatever casting 34 | * &is[4] to float* would normally do. This is to continue after printing a warning. 35 | * Here we assume float and int have the same size. */ 36 | for (float *pf = ((float*) i) - 1; pf > (float*) &is[0]; --pf) // "[bad] cast before adjust" 37 | { 38 | printf("About to deref: %p\n", pf); 39 | printf("Saw a float: %f\n", *pf); 40 | } 41 | 42 | return 0; 43 | } 44 | -------------------------------------------------------------------------------- /test/Future/fail-bounds-type-backin/mk.inc: -------------------------------------------------------------------------------- 1 | export CC := $(LIBCRUNCH_BASE)/frontend/c/bin/crunchxcc 2 | -------------------------------------------------------------------------------- /test/Future/noquery-bounds-polymorphic/mk.inc: -------------------------------------------------------------------------------- 1 | export CC := $(LIBCRUNCH_BASE)/frontend/c/bin/crunchxcc 2 | 3 | -------------------------------------------------------------------------------- /test/Future/noquery-bounds-polymorphic/noquery-bounds-polymorphic.c: -------------------------------------------------------------------------------- 1 | /* We want to be able to treat pointers "polymorphically", i.e. 2 | * via a void* lens, 3 | * without breaking the shadow space in the common case. */ 4 | 5 | #include 6 | 7 | void report_void(void *p) 8 | { 9 | printf("Saw a void*: %p\n", p); 10 | } 11 | 12 | void frob_voids(void **pptr1, void **pptr2) 13 | { 14 | if ((unsigned long) *pptr2 < (unsigned long) *pptr1) 15 | { 16 | printf("Frob means swap\n"); 17 | /* swap them */ 18 | void *tmp = *pptr2; 19 | *pptr2 = *pptr1; 20 | *pptr1 = tmp; 21 | } 22 | } 23 | 24 | /* We need to be able to cache bounds for these, but *not* have them 25 | * do fetches at startup as they are initialised. So make them static-storage 26 | * but initialize inside main(). */ 27 | int xs[2] = { 42, 69105 }; 28 | int *ptrs[2]; 29 | 30 | int main(void) 31 | { 32 | report_void(main); 33 | ptrs[0] = &xs[1]; 34 | ptrs[1] = &xs[0]; 35 | /* We want to get type info about "ptrs" into the cache, so we can test 36 | * __store_pointer_nonlocal_via_voidptrptr's ability to grub around in it. 37 | * But how? We could prefill it from here, if we add an libcrunch API call. 38 | * That's a bit nasty. In practice it's likely to be in the cache anyway. 39 | * Since we can see, from here, the definition of ptrs, we can synthesise 40 | * a cache entry for it. In fact when we take the address of &ptrs[0] below, 41 | * we *should* pass the object bounds on the shadow stack. So hmm. 42 | */ 43 | 44 | frob_voids((void**) &ptrs[0], (void**) &ptrs[1]); 45 | /* Now adjust one of them -- we should still get its bounds as if it's int*. */ 46 | printf("After frobbing, *(ptrs[0] + 1) is: %d\n", *(ptrs[0] + 1)); 47 | return 0; 48 | } 49 | -------------------------------------------------------------------------------- /test/abort-softbound-segv/abort-softbound-segv.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main(void) 7 | { 8 | char pad1[200]; 9 | int is[] = { 0, 1, 2, 3, 4 }; 10 | char pad2[200]; 11 | 12 | int *oneprev = &is[-1]; 13 | printf("Got %d\n", *oneprev); 14 | 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /test/abort-softbound-segv/frontend.mk: -------------------------------------------------------------------------------- 1 | case_name := $(call get_case_name) 2 | $(call set_frontend_for_case,$(case_name),c) 3 | $(call set_configs_for_case,$(case_name),Sb) 4 | -------------------------------------------------------------------------------- /test/abort-softbound-segv/mk.inc: -------------------------------------------------------------------------------- 1 | 2 | export CFLAGS := $(CFLAGS) -DLIBCRUNCH_ABORT_ON_OOB=1 3 | -------------------------------------------------------------------------------- /test/bounds-actuals/bounds-actuals.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct ptrs 4 | { 5 | char *p1; 6 | char *p2; 7 | char *ps[3]; 8 | }; 9 | 10 | struct many_ptrs 11 | { 12 | struct ptrs many[5]; 13 | }; 14 | 15 | static void f(char *p, struct ptrs x1, struct many_ptrs xx) 16 | { 17 | printf("It says: %c%c%c%c%c%c%c%c%c%c%c\n", 18 | p[1], 19 | x1.p1[2], 20 | x1.p2[3], 21 | x1.ps[0][0], 22 | x1.ps[1][1], 23 | x1.ps[2][2], 24 | xx.many[0].p1[2], 25 | xx.many[1].p2[2], 26 | xx.many[2].ps[0][3], 27 | xx.many[3].ps[1][0], 28 | xx.many[4].ps[2][1] 29 | ); 30 | 31 | ++p; 32 | ++x1.p1; 33 | ++x1.p2; 34 | ++x1.ps[0]; 35 | ++x1.ps[1]; 36 | ++x1.ps[2]; 37 | ++xx.many[0].p1; 38 | ++xx.many[1].p2; 39 | ++xx.many[2].ps[0]; 40 | ++xx.many[3].ps[1]; 41 | ++xx.many[4].ps[2]; 42 | 43 | printf("Now it says: %c%c%c%c%c%c%c%c%c%c%c\n", 44 | p[1], 45 | x1.p1[2], 46 | x1.p2[3], 47 | x1.ps[0][0], 48 | x1.ps[1][1], 49 | x1.ps[2][2], 50 | xx.many[0].p1[2], 51 | xx.many[1].p2[2], 52 | xx.many[2].ps[0][3], 53 | xx.many[3].ps[1][0], 54 | xx.many[4].ps[2][1] 55 | ); 56 | } 57 | 58 | char msg1[] = "Hello, world!"; 59 | char msg2[] = "Hello, sailor!"; 60 | char msg3[] = "Fool!"; 61 | 62 | int main(void) 63 | { 64 | f( 65 | msg2, 66 | (struct ptrs) { msg1, msg2, { msg3, msg3, msg3 } }, 67 | (struct many_ptrs) { 68 | (struct ptrs) { msg1, msg2, { msg3, msg2, msg1 } }, 69 | (struct ptrs) { msg2, msg3, { msg2, msg3, msg2 } }, 70 | (struct ptrs) { msg3, msg1, { msg1, msg1, msg3 } }, 71 | (struct ptrs) { msg1, msg2, { msg3, msg2, msg1 } }, 72 | (struct ptrs) { msg2, msg3, { msg2, msg3, msg2 } } 73 | } 74 | ); 75 | return 0; 76 | } 77 | 78 | /* 79 | struct { 80 | char *p; 81 | } local_struct; 82 | 83 | local_struct.p = &as[-1] 84 | 85 | FIXME: local arrays of pointers 86 | */ 87 | -------------------------------------------------------------------------------- /test/bounds-actuals/frontend.mk: -------------------------------------------------------------------------------- 1 | case_name := $(call get_case_name) 2 | $(call set_frontend_for_case,$(case_name),c) 3 | $(call set_configs_for_case,$(case_name),x b pb mb fb sb tb Pb Mb Fb Sb Tb) 4 | -------------------------------------------------------------------------------- /test/bounds-actuals/mk.inc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephenrkell/libcrunch/d5710427dc1545c2473c9dc3f417a1409eb80c26/test/bounds-actuals/mk.inc -------------------------------------------------------------------------------- /test/bounds-addrtaken-arg/bounds-addrtaken-arg.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | static int is[] = { 1, 4, 9, 16 }; 5 | int f(int *dummy, int *p) 6 | { 7 | printf("Somewhere in the array %p (dummy is %p) is %p\n", &p, dummy, p + 3); 8 | /* [The compiler thinks] printf might have modified p! */ 9 | return p[3]; 10 | } 11 | 12 | int main(void) 13 | { 14 | int *local = is; 15 | int *dummy = calloc(1, sizeof (int)); 16 | printf("It says: %d\n", f(dummy, local)); 17 | free(dummy); 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /test/bounds-addrtaken-arg/frontend.mk: -------------------------------------------------------------------------------- 1 | case_name := $(call get_case_name) 2 | $(call set_frontend_for_case,$(case_name),c) 3 | $(call set_configs_for_case,$(case_name),x b pb mb fb sb tb Pb Mb Fb Sb Tb) 4 | -------------------------------------------------------------------------------- /test/bounds-addrtaken-arg/mk.inc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephenrkell/libcrunch/d5710427dc1545c2473c9dc3f417a1409eb80c26/test/bounds-addrtaken-arg/mk.inc -------------------------------------------------------------------------------- /test/bounds-addrtaken/bounds-addrtaken.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | static int is[] = { 1, 4, 9, 16 }; 4 | int f(int **p) 5 | { 6 | return (*p)[3]; 7 | } 8 | 9 | int main(void) 10 | { 11 | int *local = is; 12 | printf("It says: %d\n", f(&local)); 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /test/bounds-addrtaken/frontend.mk: -------------------------------------------------------------------------------- 1 | case_name := $(call get_case_name) 2 | $(call set_frontend_for_case,$(case_name),c) 3 | $(call set_configs_for_case,$(case_name),x b pb mb fb sb tb Pb Mb Fb Sb Tb) 4 | -------------------------------------------------------------------------------- /test/bounds-addrtaken/mk.inc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephenrkell/libcrunch/d5710427dc1545c2473c9dc3f417a1409eb80c26/test/bounds-addrtaken/mk.inc -------------------------------------------------------------------------------- /test/bounds-arrarr/bounds-arrarr.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int *g(void *p) 5 | { 6 | return (int*)p; 7 | } 8 | 9 | int main(void) 10 | { 11 | int x[2][2][47] = { { { 1, 2 }, { 3, 4 } }, 12 | { { 5, 6 }, { 7, 8 } } }; 13 | 14 | int dest[sizeof x / sizeof x[0]]; 15 | 16 | /* Here we cast x to void*, spilling an int*-typed alias to the cache. 17 | * It's essential that we collapse the type int[2][2][2] to int[8] 18 | * at this point, because we don't generate uniqtypes of the 19 | * form __uniqtype____ARRn___ARRm___x. */ 20 | printf("Got back: %d\n", g(x)[1]); 21 | 22 | memcpy(dest, x, sizeof x); 23 | printf("First element in dest: %d\n", dest[0]); 24 | 25 | return 0; 26 | } 27 | -------------------------------------------------------------------------------- /test/bounds-arrarr/frontend.mk: -------------------------------------------------------------------------------- 1 | case_name := $(call get_case_name) 2 | $(call set_frontend_for_case,$(case_name),c) 3 | $(call set_configs_for_case,$(case_name),x b pb mb fb sb tb Pb Mb Fb Sb Tb) 4 | -------------------------------------------------------------------------------- /test/bounds-arrarr/mk.inc: -------------------------------------------------------------------------------- 1 | export CFLAGS := $(CFLAGS) -save-temps -std=c11 2 | -------------------------------------------------------------------------------- /test/bounds-diff/bounds-diff.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main(void) 6 | { 7 | int is[] = { 5, 4, 3, 2 }; 8 | 9 | int *a = &is[4]; 10 | int *b = &is[0]; 11 | 12 | ptrdiff_t d = (a - b); 13 | assert(d == 4); 14 | 15 | printf("Difference is %ld\n", (long) d); 16 | 17 | return 0; 18 | } 19 | -------------------------------------------------------------------------------- /test/bounds-diff/frontend.mk: -------------------------------------------------------------------------------- 1 | case_name := $(call get_case_name) 2 | $(call set_frontend_for_case,$(case_name),c) 3 | $(call set_configs_for_case,$(case_name),x b pb mb fb sb tb Pb Mb Fb Sb Tb) 4 | -------------------------------------------------------------------------------- /test/bounds-diff/mk.inc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephenrkell/libcrunch/d5710427dc1545c2473c9dc3f417a1409eb80c26/test/bounds-diff/mk.inc -------------------------------------------------------------------------------- /test/bounds-extern/Makefile: -------------------------------------------------------------------------------- 1 | default: bounds-extern 2 | 3 | bounds-extern: bounds-extern.c lib.o 4 | $(CC) -o "$@" $(CFLAGS) $+ $(LDFLAGS) $(LDLIBS) 5 | 6 | -------------------------------------------------------------------------------- /test/bounds-extern/bounds-extern.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | extern int blah[]; 4 | 5 | int indir_func(int *p) 6 | { 7 | return p[41]; 8 | } 9 | 10 | int *indir_store; 11 | 12 | int main(void) 13 | { 14 | indir_store = blah; 15 | printf("It is: %d\n", indir_func(blah)); 16 | printf("It is: %d\n", indir_store[41]); 17 | printf("It is: %d\n", blah[41]); 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /test/bounds-extern/frontend.mk: -------------------------------------------------------------------------------- 1 | case_name := $(call get_case_name) 2 | $(call set_frontend_for_case,$(case_name),c) 3 | $(call set_configs_for_case,$(case_name),x b pb mb fb sb tb Pb Mb Fb Sb Tb) 4 | -------------------------------------------------------------------------------- /test/bounds-extern/lib.c: -------------------------------------------------------------------------------- 1 | int blah[42] = { [41] = 69105 }; 2 | -------------------------------------------------------------------------------- /test/bounds-extern/mk.inc: -------------------------------------------------------------------------------- 1 | 2 | bounds-extern: lib.o 3 | -------------------------------------------------------------------------------- /test/bounds-indexzero/bounds-indexzero.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | extern unsigned long __libcrunch_fetch_bounds_called; 5 | 6 | int xs[42] = { 0 }; 7 | extern int ys[] __attribute__((alias("xs"))); 8 | 9 | int main(int argc, char **argv) 10 | { 11 | /* We should not instrument derefs, including those signified 12 | * by indexing at zero. How can we tell whether we just did a 13 | * check? I think the way to assert that we didn't do a check is 14 | * (1) invent a check that will always do a query 15 | * (2) check that no query happened 16 | * (3) ... relying on the compiler to optimise away the unused query 17 | * But I can't think of a check that will always do a query. 18 | * Or can I? This is easier than I think. If we're in crunchb mode, 19 | * it means we don't check derefs or statically-known-zero indexing. 20 | * So we won't do any fetches that would be needed only for such checks. 21 | */ 22 | printf("argv[0] is %p\n", argv[0]); 23 | putenv("BLAHUNUSED=xyz"); 24 | char *v = getenv("BLAHUNUSED"); 25 | // if we could, we'd assert that we don't have bounds 26 | printf("ourvar[0] is %p\n", v[0]); 27 | //assert(!__libcrunch_is_initialized); 28 | printf("ys[0] is %d\n", ys[0]); 29 | assert(__libcrunch_fetch_bounds_called == 0); 30 | 31 | /* The following is testing indexing of local arrays. It is 32 | * based on a case in SPEC gcc. Previously crunchbound complained 33 | * because the index expr in "info[n]" is not statically zero, yet we 34 | * have inferred, from the use of sizeof, that we need only a singleton 35 | * local bounds var for the array. This is because the sizing expression 36 | * is in the compile-time-evaluable subset of C, but the indexing 37 | * expression is not. But we already check for in-boundsness of local 38 | * accesses, so any access to "info" will be bounds-checked, after 39 | * which we know that accesses to its localbounds will be valid. */ 40 | static const int nums[] = { 1 }; 41 | #define N (sizeof nums / sizeof (int)) 42 | struct { int *p; } *info[N]; 43 | int n = 0; 44 | 45 | for (int n = 0; n < N; ++n) 46 | { 47 | info[n] = calloc(4, sizeof *info[0]); 48 | } 49 | /* return something that is always zero, 50 | * but not statically knowably so. */ 51 | return malloc_usable_size(info[0]) / 200000; 52 | } 53 | 54 | -------------------------------------------------------------------------------- /test/bounds-indexzero/frontend.mk: -------------------------------------------------------------------------------- 1 | case_name := $(call get_case_name) 2 | $(call set_frontend_for_case,$(case_name),c) 3 | $(call set_configs_for_case,$(case_name),x b pb mb fb sb tb Pb Mb Fb Sb Tb) 4 | -------------------------------------------------------------------------------- /test/bounds-indexzero/mk.inc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephenrkell/libcrunch/d5710427dc1545c2473c9dc3f417a1409eb80c26/test/bounds-indexzero/mk.inc -------------------------------------------------------------------------------- /test/bounds-multi-alloc/bounds-multi-alloc.c: -------------------------------------------------------------------------------- 1 | /* This is based on sphinx3's ckd_alloc.c / __mymalloc__, 2 | * which creates small object pools 3 | * and links the free ones together in a free list. 4 | * This linking disrespects the type of the object, 5 | * by blatting the free-list pointers into the first word of 6 | * each object. */ 7 | 8 | #include 9 | #include 10 | 11 | void *alloc(size_t elemsize) 12 | { 13 | static char **freelist; 14 | #define NBLOCK 50 15 | /* This cast happens to be valid for our caller, because the object's first argument 16 | * is a void* and char** is a generic pointer pointer. However, we get the bounds 17 | * [cpp, cpp+8bytes).*/ 18 | char **cpp = freelist = (char **) calloc(NBLOCK, elemsize); 19 | /* We should now get the bounds of the whole allocation. */ 20 | char *cp = (char *) cpp; 21 | for (int j = NBLOCK - 1; j > 0; --j) 22 | { 23 | cp += elemsize; 24 | *cpp = cp; 25 | cpp = (char **)cp; 26 | } 27 | *cpp = NULL; 28 | 29 | // unlink one and return it 30 | cp = (char *)freelist; 31 | freelist = (char **)(*freelist); 32 | return cp; 33 | } 34 | 35 | 36 | struct myelem 37 | { 38 | void *blah; 39 | int x; 40 | }; 41 | 42 | int main(void) 43 | { 44 | struct myelem *e = alloc(sizeof (struct myelem)); 45 | e->blah = NULL; 46 | e->x = 42; 47 | printf("At %p, blah is %p and x is %d\n", e, e->blah, e->x); 48 | return 0; 49 | } 50 | -------------------------------------------------------------------------------- /test/bounds-multi-alloc/frontend.mk: -------------------------------------------------------------------------------- 1 | case_name := $(call get_case_name) 2 | $(call set_frontend_for_case,$(case_name),c) 3 | $(call set_configs_for_case,$(case_name),x b pb mb fb sb tb Pb Mb Fb Sb Tb) 4 | -------------------------------------------------------------------------------- /test/bounds-multi-alloc/mk.inc: -------------------------------------------------------------------------------- 1 | export CFLAGS := $(CFLAGS) -save-temps -std=c11 2 | export LIBALLOCS_ALLOC_FNS := alloc(Z)p 3 | -------------------------------------------------------------------------------- /test/bounds-nonlocal/bounds-nonlocal.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | const char *f(void) 4 | { 5 | static const char *s = "Blah!"; 6 | 7 | return s; 8 | } 9 | 10 | const char *temp; 11 | 12 | int main(void) 13 | { 14 | temp = f(); 15 | printf("Now I say: %s\n", temp + 2); 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /test/bounds-nonlocal/frontend.mk: -------------------------------------------------------------------------------- 1 | case_name := $(call get_case_name) 2 | $(call set_frontend_for_case,$(case_name),c) 3 | $(call set_configs_for_case,$(case_name),x b pb mb fb sb tb Pb Mb Fb Sb Tb) 4 | -------------------------------------------------------------------------------- /test/bounds-nonlocal/mk.inc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephenrkell/libcrunch/d5710427dc1545c2473c9dc3f417a1409eb80c26/test/bounds-nonlocal/mk.inc -------------------------------------------------------------------------------- /test/bounds-pure-helper/bounds-pure-helper.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | static const char mybuf[] = "The quick brown fox jumped over the lazy dog"; 8 | /* FIXME: if we use just a string literal here, we don't get bounds 9 | * because we don't get static alloc records string lits in rodata. */ 10 | 11 | char *my_pure(const char*) __attribute__((noinline,__const__)); 12 | char *my_pure(const char *needle) 13 | { 14 | static _Bool ran_once; 15 | assert(!ran_once); 16 | ran_once = 1; 17 | return strstr(mybuf, needle); 18 | } 19 | 20 | /* We must be able to call a pure function *twice*, 21 | * say strstr, and get valid bounds for what it returns 22 | * even the second time, but only make one call. 23 | * Naively the shadow stack breaks this because 24 | * the second call will appear uninstrumented. */ 25 | int ( __attribute__((optimize("O2"))) main)(void) 26 | { 27 | char *needle1 = my_pure("quick"); 28 | printf("Needle second char: %c\n", needle1[1]); 29 | char *needle2 = my_pure("quick"); 30 | printf("Needle second char: %c\n", needle2[1]); 31 | 32 | return 0; 33 | } 34 | -------------------------------------------------------------------------------- /test/bounds-pure-helper/frontend.mk: -------------------------------------------------------------------------------- 1 | case_name := $(call get_case_name) 2 | $(call set_frontend_for_case,$(case_name),c) 3 | $(call set_configs_for_case,$(case_name),x b pb mb fb sb tb Pb Mb Fb Sb Tb) 4 | -------------------------------------------------------------------------------- /test/bounds-pure-helper/mk.inc: -------------------------------------------------------------------------------- 1 | export CFLAGS := $(CFLAGS) -save-temps 2 | -------------------------------------------------------------------------------- /test/bounds-simple/bounds-simple.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(void) 4 | { 5 | /* Test that we check all the pointer derivations in the following. */ 6 | 7 | char as[42] = "abcdefghijklmnopqrstuvwxyz0123456789ABCDE"; 8 | char bs[100] = "qwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzx"; 9 | struct { 10 | int xyzzy; 11 | char *plugh; 12 | } cs[2] = { { 101, "a" }, { 102, "b" } }; 13 | 14 | char *a = &as[41]; 15 | printf("Got a: %p\n", a); 16 | 17 | char *b = &as[1]; 18 | printf("Got b: %p\n", b); 19 | 20 | char *c = &as[a - b]; // difference 40 21 | printf("Got c: %p\n", c); 22 | 23 | char *d = &bs[as[1]]; // value 'b' a.k.a. 98 24 | printf("Got d: %p\n", d); 25 | 26 | char **e = &cs[0].plugh; 27 | printf("Got e: %p\n", e); 28 | 29 | return 0; 30 | } 31 | 32 | /* 33 | struct { 34 | char *p; 35 | } local_struct; 36 | 37 | local_struct.p = &as[-1] 38 | 39 | FIXME: local arrays of pointers 40 | */ 41 | -------------------------------------------------------------------------------- /test/bounds-simple/frontend.mk: -------------------------------------------------------------------------------- 1 | case_name := $(call get_case_name) 2 | $(call set_frontend_for_case,$(case_name),c) 3 | $(call set_configs_for_case,$(case_name),x b pb mb fb sb tb Pb Mb Fb Sb Tb) 4 | -------------------------------------------------------------------------------- /test/bounds-simple/mk.inc: -------------------------------------------------------------------------------- 1 | export CFLAGS := $(CFLAGS) -save-temps 2 | -------------------------------------------------------------------------------- /test/bounds-static-init-ptr/bounds-static-init-ptr.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int vs[] = { 1, 2, 3 }; 5 | extern int other_vs[]; /* defined as an alias of vs, in mk.inc */ 6 | 7 | /* See noquery-bounds-static-init-ptr. 8 | * The difference here is that some bounds initializers *will* require a query. 9 | */ 10 | 11 | int main(void) 12 | { 13 | static int *arr[] = { &vs[0], &vs[1], &vs[2] }; 14 | static struct { int *blah; } other_container = { &other_vs[0] }; 15 | 16 | int n = rand(); 17 | int sz = (sizeof arr / sizeof arr[0]); 18 | printf("Randomly read: %d\n", *(other_container.blah + rand() % sz)); 19 | return 0; 20 | } 21 | -------------------------------------------------------------------------------- /test/bounds-static-init-ptr/frontend.mk: -------------------------------------------------------------------------------- 1 | case_name := $(call get_case_name) 2 | $(call set_frontend_for_case,$(case_name),c) 3 | # sb Sb tb Tb are excluded becase __fetch_bounds_ool_via_dladdr 4 | # finds (correctly) gets a *zero-length* alias symbol for other_vs, 5 | # so thinks the object has zero length. 6 | $(call set_configs_for_case,$(case_name),x b pb mb fb Pb Mb Fb) 7 | -------------------------------------------------------------------------------- /test/bounds-static-init-ptr/mk.inc: -------------------------------------------------------------------------------- 1 | 2 | LDFLAGS += -Wl,--defsym,other_vs=vs 3 | -------------------------------------------------------------------------------- /test/bounds-struct-return/bounds-struct-return.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct contains_ptr 4 | { 5 | int *do_not_care; 6 | long not_a_ptr; 7 | int *p; 8 | int *otherptr; 9 | }; 10 | 11 | struct contains_ptr callee(int *x) 12 | { 13 | static int is[] = { 69105, 4432 }; 14 | return (struct contains_ptr) { .do_not_care = x, .not_a_ptr = 42l, .p = is, .otherptr = x }; 15 | } 16 | 17 | struct contains_ptr l; 18 | int main(int argc, char **argv) 19 | { 20 | l = callee(&argc); 21 | printf("It says: %d; otherptr %p\n", *(l.p + 1), l.otherptr); 22 | return 0; 23 | } 24 | -------------------------------------------------------------------------------- /test/bounds-struct-return/frontend.mk: -------------------------------------------------------------------------------- 1 | case_name := $(call get_case_name) 2 | $(call set_frontend_for_case,$(case_name),c) 3 | $(call set_configs_for_case,$(case_name),x b pb mb fb sb tb Pb Mb Fb Sb Tb) 4 | -------------------------------------------------------------------------------- /test/bounds-struct-return/mk.inc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephenrkell/libcrunch/d5710427dc1545c2473c9dc3f417a1409eb80c26/test/bounds-struct-return/mk.inc -------------------------------------------------------------------------------- /test/bounds-struct/bounds-struct.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct contains_ptr 4 | { 5 | int *p; 6 | }; 7 | 8 | int callee(struct contains_ptr *p) 9 | { 10 | printf("It says: %d\n", *(p->p + 1)); 11 | return *(p->p + 1); 12 | } 13 | 14 | int main(int argc, char **argv) 15 | { 16 | int is[] = { 69105, 4432 }; 17 | struct contains_ptr l; 18 | l.p = is; 19 | return callee(&l) - 4432; 20 | } 21 | -------------------------------------------------------------------------------- /test/bounds-struct/frontend.mk: -------------------------------------------------------------------------------- 1 | case_name := $(call get_case_name) 2 | $(call set_frontend_for_case,$(case_name),c) 3 | $(call set_configs_for_case,$(case_name),x b pb mb fb sb tb Pb Mb Fb Sb Tb) 4 | -------------------------------------------------------------------------------- /test/bounds-struct/mk.inc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephenrkell/libcrunch/d5710427dc1545c2473c9dc3f417a1409eb80c26/test/bounds-struct/mk.inc -------------------------------------------------------------------------------- /test/bounds-trap/bounds-trap.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(void) 4 | { 5 | /* Test that we check all the pointer derivations in the following. 6 | * They are all made to use one-past pointers. */ 7 | 8 | char as[42] = "abcdefghijklmnopqrstuvwxyz0123456789ABCDE"; 9 | char bs[100] = "qwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzx"; 10 | struct { 11 | int xyzzy; 12 | char *plugh; 13 | } cs[2] = { { 101, "a" }, { 102, "b" } }; 14 | 15 | char *a = &as[42]; 16 | printf("Got a - 1: %p\n", a - 1); 17 | 18 | char *b = &as[42]; 19 | printf("Got b - 41: %p\n", b - 41); 20 | 21 | char *d = &bs[as[1] + 2] - 2; // value 'b' a.k.a. 98 22 | printf("Got d: %p\n", d); 23 | 24 | return 0; 25 | } 26 | -------------------------------------------------------------------------------- /test/bounds-trap/frontend.mk: -------------------------------------------------------------------------------- 1 | case_name := $(call get_case_name) 2 | $(call set_frontend_for_case,$(case_name),c) 3 | $(call set_configs_for_case,$(case_name),x b pb mb tb Pb Mb Tb) 4 | -------------------------------------------------------------------------------- /test/bounds-trap/mk.inc: -------------------------------------------------------------------------------- 1 | export CFLAGS := $(CFLAGS) -save-temps -DLIBCRUNCH_DEBUG_PRIMARY_SECONDARY_TRANSITIONS 2 | -------------------------------------------------------------------------------- /test/bounds-type/bounds-type.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | extern unsigned long int __libcrunch_fetch_bounds_missed_cache; 8 | 9 | /* This test case is showing that bounds do affect types, and correctly. 10 | * We also test performance properties: if the is-a cache is doing its job, 11 | * a malloc should not cause a fetch-bounds cache miss. This only holds with 12 | * trumptr also enabled. */ 13 | 14 | struct blah 15 | { 16 | int x[2]; 17 | float y; 18 | }; 19 | 20 | int main(void) 21 | { 22 | void *alloc = calloc(42, sizeof (struct blah)); 23 | 24 | struct blah *p_zs = (struct blah *) alloc; 25 | assert(__libcrunch_fetch_bounds_missed_cache == 0); 26 | /* After this we're allowed to miss the cache, but *only* for 27 | * char*! And perhaps GPP types that are not always checked. 28 | * The other target types should be cached from trumptr, as before. */ 29 | 30 | printf("An integer: %d\n", *((p_zs->x + 42) - 42)); // #3: non-error: via out-of-bounds intermediate 31 | 32 | printf("A float: %f\n", ((struct blah *) p_zs->x)->y); // #4: non-error: after bounds-widening cast 33 | 34 | printf("An integer: %d\n", *(int*)(intptr_t)p_zs->x); // #5: non-error: via integer 35 | 36 | char *a_y = (char*) &p_zs[41].y; 37 | printf("A pointer ranging over the whole allocation: %p\n", a_y); 38 | 39 | /* Coup de grace: use char* arithmetic to recover a float* starting from an int*, 40 | * all without complaint from libcrunch. */ 41 | printf("An integer: %d\n", *(int *)( 42 | a_y 43 | - offsetof(struct blah, y) 44 | - 41 * sizeof (struct blah) 45 | )); 46 | 47 | return 0; 48 | } 49 | -------------------------------------------------------------------------------- /test/bounds-type/frontend.mk: -------------------------------------------------------------------------------- 1 | case_name := $(call get_case_name) 2 | $(call set_frontend_for_case,$(case_name),c) 3 | $(call set_configs_for_case,$(case_name),x) 4 | -------------------------------------------------------------------------------- /test/bounds-type/mk.inc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephenrkell/libcrunch/d5710427dc1545c2473c9dc3f417a1409eb80c26/test/bounds-type/mk.inc -------------------------------------------------------------------------------- /test/bounds-va_arg/bounds-va_arg.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void my_interp(const char *str, ...) 5 | { 6 | va_list va; 7 | va_start(va, str); 8 | char c; 9 | int i; 10 | double d; 11 | while ('\0' != (c = *str++)) 12 | { 13 | switch (c) 14 | { 15 | case 'i': 16 | i = va_arg(va, int); 17 | fprintf(stdout, "Seen in interp program: %d\n", i); 18 | break; 19 | case 'f': 20 | d = va_arg(va, double); 21 | fprintf(stdout, "Seen in interp program: %f\n", d); 22 | break; 23 | default: 24 | i = va_arg(va, int); 25 | fprintf(stdout, "Unrecognised char in interp program: '%c'\n", c); 26 | break; 27 | } 28 | } 29 | va_end(va); 30 | } 31 | 32 | int main(void) 33 | { 34 | int i = 42; 35 | int j = 69105; 36 | double e = 2.71828; 37 | my_interp("ifi", i, e, j); 38 | return 0; 39 | } 40 | -------------------------------------------------------------------------------- /test/bounds-va_arg/frontend.mk: -------------------------------------------------------------------------------- 1 | case_name := $(call get_case_name) 2 | $(call set_frontend_for_case,$(case_name),c) 3 | $(call set_configs_for_case,$(case_name),x b pb mb fb sb tb Pb Mb Fb Sb Tb) 4 | -------------------------------------------------------------------------------- /test/bounds-va_arg/mk.inc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephenrkell/libcrunch/d5710427dc1545c2473c9dc3f417a1409eb80c26/test/bounds-va_arg/mk.inc -------------------------------------------------------------------------------- /test/checks.sh: -------------------------------------------------------------------------------- 1 | match () { 2 | line="$1" 3 | count_pattern="$2" 4 | 5 | input="$(cat)" 6 | 7 | # if we get no input, we fail! 8 | if [ -z "$input" ]; then 9 | false 10 | else 11 | 12 | matched="$( echo "$input" | grep "$line" )" 13 | nlines_matched="$( echo "$matched" | wc -l )" 14 | 15 | if ! [ $nlines_matched -eq 1 ]; then 16 | echo "Unexpectedly matched $nlines_matched lines" 1>&2 17 | exit 1 18 | fi 19 | 20 | echo "$matched" | sed 's/.*[^0-9]\([0-9]*\)$/\1/' | grep "$count_pattern" 21 | 22 | if [ $? -eq 0 ]; then 23 | # only chain if we succeeded 24 | echo "$input" 25 | else 26 | echo "Count for \"$line\" did not match '$count_pattern'" 1>&2; false 27 | fi 28 | fi 29 | } 30 | -------------------------------------------------------------------------------- /test/clang-frontend/frontend.mk: -------------------------------------------------------------------------------- 1 | case_name := $(call get_case_name) 2 | $(call set_frontend_for_case,$(case_name),clang) 3 | $(call set_configs_for_case,$(case_name),default) 4 | -------------------------------------------------------------------------------- /test/fail-bounds-oneprev/fail-bounds-oneprev.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | /* PROBLEMS exposed by this test case and its variants: 7 | * 8 | * "bad cast before adjust" 9 | for (float *pf = ((float*) i) - 1; pf >= (float*) &is[0]; --pf) 10 | -- see fail-bounds-type-backin 11 | 12 | * "bad cast after adjust" 13 | for (float *pf = (float*) (i - sizeof (float)); pf > (float*) &is[0]; --pf) 14 | -- see bounds-type-simple 15 | 16 | * "compare one-prev with bad-cast" 17 | for (float *pf = (float*) (i - sizeof (float)); pf >= (float*) &is[0]; --pf) 18 | - i.e. the same as above but with ">=" and not ">" ^-^ here 19 | 20 | - what happens: we trap the pointer from the last "--pf", because it's one-prev. 21 | 22 | + OTHER small problems: 23 | 1. "max_bounds" (in libcrunch.c) might not be sensible 24 | 2. stack frame types are unions, i.e. have repeated offsets -- is this correct? 25 | 26 | - what should happen: sloppily accommodate the one-prev, like with bounds-type-simple, 27 | iff the users asks for it 28 | 29 | * "cast trapped pointer": 30 | for (float *pf = (float*) (i - 5 * sizeof (float)); pf < (float*) &is[5]; ++pf) 31 | -- see fail-bounds-type-trapped 32 | 33 | - what happens: we call __is_aU on a trapped ptr, confusing things 34 | ... giving storage and/or invalid-stackframe liballocs errors 35 | but (consequently) no libcrunch errors 36 | - what should happen: always de-trap calls to __is_aU? 37 | flag up the liballocs errors more explicitly? 38 | make crunchbound rewrite all pointer arithmetic to be on char* ? 39 | -- would this help? if we did (char*)(float*)oob, it still does the cast. 40 | just give up? 41 | */ 42 | 43 | int main(void) 44 | { 45 | char pad1[200]; 46 | int is[] = { 0, 1, 2, 3, 4 }; 47 | char pad2[200]; 48 | 49 | /* If we convert a trapped pointer to int, we should get a sensible value. */ 50 | int *i1 = &is[5]; 51 | unsigned long i = (unsigned long) i1; 52 | printf("The int we got is 0x%lx\n", i); 53 | assert(i - (unsigned long) &is[4] == sizeof (int)); 54 | 55 | /* If we convert it back to a float* when *out of bounds*, it should not be usable, 56 | * but __fetch_bounds might (ideally) let us sloppily accommodate it anyway. 57 | * If we convert it back to an in-bounds float*, it should do whatever casting 58 | * &is[4] to float* would normally do. This is to continue after printing a warning. 59 | * Here we assume float and int have the same size. */ 60 | // for (float *pf = ((float*) i) - 1; pf >= (float*) &is[0]; --pf) // "[bad] cast before adjust" 61 | for (float *pf = (float*) (i - sizeof (float)); pf >= (float*) &is[0]; --pf) // "adjust before [good] cast" 62 | // for (float *pf = (float*) (i - 5 * sizeof (float)); pf < (float*) &is[5]; ++pf) // "adjust before [good] cast" 63 | // for (float *pf = (float*) (i - 5 * sizeof (float)); pf < (float*) &is[5]; ++pf) // "adjust before [good] cast" 64 | { 65 | printf("About to deref: %p\n", pf); 66 | printf("Saw a float: %f\n", *pf); 67 | } 68 | 69 | /* HMM. What should happen here? 70 | * We convert the one-past pointer to an integer. 71 | * Then we convert it back to a float*. 72 | * It isn't pointing at a float, so the cast fails. 73 | * The code is arguably correct, though, because we're not going to use it 74 | * until we've decremented it. 75 | * Decrementing it currently doesn't work, because 76 | * doing arithmetic on the untrapped pointer confuses __fetch_bounds, 77 | * -- it's not pointing at a float-typed area, and it's not a one-past trapped case. 78 | * 79 | * We need to trap the bad pointer *at the site of the cast*. 80 | * Probably we should use a new kind of trapped pointer (LIBCRUNCH_TRAP_WRONG_TYPE). 81 | * 82 | * Then we ideally want __fetch_bounds to handle the case where 83 | * arithmetic is used to bring a bad-type pointer back in bounds. 84 | * This is *sloppy* and should only be enabled on request. 85 | * This is "[bad] cast,then adjust" instead of "adjust, then [good] cast". 86 | * If we'd written 87 | * float *pf = (float*) (i - sizeof (float)) 88 | * we'd be okay. 89 | * 90 | * Bad-type trapping would reduce our ability to continue running code that 91 | * does bad casts, UNLESS we also catch SEGV and emulate those accesses. 92 | * That is probably the right thing to do. 93 | * For the moment, we don't have many false positives, so we should I think 94 | * suck it up and maybe even not bother with the SEGV handler. 95 | * 96 | * Casting a pointer should de-trap it first -- even (especially for) 97 | * casts whose target type means they need no check? 98 | * HMM. "Same type" means leave trappedness. 99 | * "New type, checked" means clear trappedness. 100 | * "New type, void* or integer" means clear trappedness 101 | * "New type, char*" means... what? Okay to leave, I think (we ignore 102 | * trappedness when comparing pointers for <= < == != >= >). 103 | * "New type, GPP" means... what? again, we clear its trappedness. 104 | * 105 | * Should we emulate all such uses of trapped pointers? YES, probably. 106 | * For now, doing arithmetic on a bad-cast pointer aborts the program. */ 107 | 108 | return 0; 109 | } 110 | -------------------------------------------------------------------------------- /test/fail-bounds-oneprev/frontend.mk: -------------------------------------------------------------------------------- 1 | case_name := $(call get_case_name) 2 | $(call set_frontend_for_case,$(case_name),c) 3 | # FIXME: sb/Sb and tb/Tb are excluded because they don't "fail"-, they "abort"- 4 | $(call set_configs_for_case,$(case_name),x b pb mb fb Pb Mb Fb) 5 | -------------------------------------------------------------------------------- /test/fail-bounds-oneprev/mk.inc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephenrkell/libcrunch/d5710427dc1545c2473c9dc3f417a1409eb80c26/test/fail-bounds-oneprev/mk.inc -------------------------------------------------------------------------------- /test/fail-bounds-segv/fail-bounds-segv.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main(void) 7 | { 8 | char pad1[200]; 9 | int is[] = { 0, 1, 2, 3, 4 }; 10 | char pad2[200]; 11 | 12 | int *oneprev = &is[-1]; 13 | printf("Got %d\n", *oneprev); 14 | 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /test/fail-bounds-segv/frontend.mk: -------------------------------------------------------------------------------- 1 | case_name := $(call get_case_name) 2 | $(call set_frontend_for_case,$(case_name),c) 3 | # FIXME: sb/Sb and tb/Tb are excluded because they don't "fail"-, they "abort"- 4 | $(call set_configs_for_case,$(case_name),x b pb mb fb Pb Mb Fb) 5 | -------------------------------------------------------------------------------- /test/fail-bounds-type-simple/fail-bounds-type-simple.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | /* "bad cast after adjust" 7 | for (float *pf = (float*) (i - sizeof (float)); pf > (float*) &is[0]; --pf) 8 | - what happens: we do arithmetic on a bad-type pointer, 9 | but since the size matches (float vs int), 10 | we get away with it 11 | */ 12 | 13 | int main(void) 14 | { 15 | char pad1[200]; 16 | int is[] = { 0, 1, 2, 3, 4 }; 17 | char pad2[200]; 18 | /* If we convert a trapped pointer to int, we should get a sensible value. */ 19 | int *i1 = &is[5]; 20 | unsigned long i = (unsigned long) i1; 21 | printf("The int we got is 0x%lx\n", i); 22 | assert(i - (unsigned long) &is[4] == sizeof (int)); 23 | /* If we convert it back to a float* when *out of bounds*, it should not be usable, 24 | * but __fetch_bounds might (ideally) let us sloppily accommodate it anyway. 25 | * If we convert it back to an in-bounds float*, it should do whatever casting 26 | * &is[4] to float* would normally do. This is to continue after printing a warning. 27 | * Here we assume float and int have the same size. */ 28 | for (float *pf = (float*) (i - sizeof (float)); pf > (float*) &is[0]; --pf) // "adjust before [good] cast" 29 | { 30 | printf("About to deref: %p\n", pf); 31 | printf("Saw a float: %f\n", *pf); 32 | } 33 | return 0; 34 | } 35 | -------------------------------------------------------------------------------- /test/fail-bounds-type-simple/frontend.mk: -------------------------------------------------------------------------------- 1 | case_name := $(call get_case_name) 2 | $(call set_frontend_for_case,$(case_name),c) 3 | $(call set_configs_for_case,$(case_name),x) 4 | -------------------------------------------------------------------------------- /test/fail-bounds-type-simple/mk.inc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephenrkell/libcrunch/d5710427dc1545c2473c9dc3f417a1409eb80c26/test/fail-bounds-type-simple/mk.inc -------------------------------------------------------------------------------- /test/fail-bounds-type-trapped/fail-bounds-type-trapped.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | /* "cast trapped pointer": 7 | for (float *pf = (float*) (i - 5 * sizeof (float)); pf < (float*) &is[5]; ++pf) 8 | -- see fail-bounds-type-trapped 9 | 10 | - what happens: we call __is_aU on a trapped ptr, confusing things 11 | ... giving storage and/or invalid-stackframe liballocs errors 12 | but (consequently) no libcrunch errors 13 | - what should happen: always de-trap calls to __is_aU? 14 | flag up the liballocs errors more explicitly? 15 | make crunchbound rewrite all pointer arithmetic to be on char* ? 16 | -- would this help? if we did (char*)(float*)oob, it still does the cast. 17 | just give up? 18 | */ 19 | 20 | int main(void) 21 | { 22 | char pad1[200]; 23 | int is[] = { 0, 1, 2, 3, 4 }; 24 | char pad2[200]; 25 | 26 | /* If we convert a trapped pointer to int, we should get a sensible value. */ 27 | int *i1 = &is[5]; 28 | unsigned long i = (unsigned long) i1; 29 | printf("The int we got is 0x%lx\n", i); 30 | assert(i - (unsigned long) &is[4] == sizeof (int)); 31 | 32 | /* If we convert it back to a float* when *out of bounds*, it should not be usable, 33 | * but __fetch_bounds might (ideally) let us sloppily accommodate it anyway. 34 | * If we convert it back to an in-bounds float*, it should do whatever casting 35 | * &is[4] to float* would normally do. This is to continue after printing a warning. 36 | * Here we assume float and int have the same size. */ 37 | // for (float *pf = ((float*) i) - 1; pf >= (float*) &is[0]; --pf) // "[bad] cast before adjust" 38 | for (float *pf = (float*) (i - 5 * sizeof (float)); pf < (float*) &is[5]; ++pf) // "adjust before [good] cast" 39 | { 40 | printf("About to deref: %p\n", pf); 41 | printf("Saw a float: %f\n", *pf); 42 | } 43 | 44 | return 0; 45 | } 46 | -------------------------------------------------------------------------------- /test/fail-bounds-type-trapped/frontend.mk: -------------------------------------------------------------------------------- 1 | case_name := $(call get_case_name) 2 | $(call set_frontend_for_case,$(case_name),c) 3 | $(call set_configs_for_case,$(case_name),x) 4 | -------------------------------------------------------------------------------- /test/fail-bounds-type-trapped/mk.inc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephenrkell/libcrunch/d5710427dc1545c2473c9dc3f417a1409eb80c26/test/fail-bounds-type-trapped/mk.inc -------------------------------------------------------------------------------- /test/fail-funptr/fail-funptr.c: -------------------------------------------------------------------------------- 1 | ../hello-funptr/hello-funptr.c -------------------------------------------------------------------------------- /test/fail-sloppy-gpcot/fail-sloppy-gpcot.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct ObjA 4 | { 5 | int *hdr; 6 | struct 7 | { 8 | void **other; 9 | } rest; 10 | }; 11 | 12 | struct ObjB 13 | { 14 | float *hdr; 15 | struct 16 | { 17 | int **other; 18 | } rest; 19 | long more; 20 | }; 21 | 22 | struct View // even a good view can be used badly... 23 | { 24 | void *hdr; 25 | struct 26 | { 27 | void **other; 28 | } rest; 29 | }; 30 | struct BadView1 31 | { 32 | void **hdr; 33 | int **other; 34 | }; 35 | 36 | int *x = NULL; 37 | int *y = NULL; 38 | float *z = NULL; 39 | 40 | int main(void) 41 | { 42 | struct ObjA o1; 43 | struct ObjB o2; 44 | 45 | ((struct BadView1 *) &o1)->other = &x; 46 | ((struct BadView1 *) &o2)->other = &y; 47 | ((struct View *) &o1)->rest.other = &z; 48 | 49 | return 0; 50 | 51 | } 52 | -------------------------------------------------------------------------------- /test/fail-sloppy-gpcot/mk.inc: -------------------------------------------------------------------------------- 1 | export LIBCRUNCH_USE_LOOSELY_LIKE_A_FOR_TYPES := View 2 | 3 | -------------------------------------------------------------------------------- /test/fail-va_arg/fail-va_arg.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void my_interp(const char *str, ...) 5 | { 6 | va_list va; 7 | va_start(va, str); 8 | char c; 9 | void *p; 10 | int *pi; 11 | float *pf; 12 | while ('\0' != (c = *str++)) 13 | { 14 | switch (c) 15 | { 16 | case 'i': 17 | pi = va_arg(va, int*); 18 | fprintf(stdout, "Seen in interp program: %d\n", *pi); 19 | break; 20 | case 'f': 21 | pf = va_arg(va, float*); 22 | fprintf(stdout, "Seen in interp program: %f\n", *pf); 23 | break; 24 | default: 25 | p = va_arg(va, void*); 26 | fprintf(stdout, "Unrecognised char in interp program: '%c'\n", c); 27 | break; 28 | } 29 | } 30 | va_end(va); 31 | } 32 | 33 | int main(void) 34 | { 35 | int i = 42; 36 | int j = 69105; 37 | float e = 2.71828; 38 | 39 | my_interp("fif", &i, &e, &j); 40 | 41 | return 0; 42 | } 43 | -------------------------------------------------------------------------------- /test/fail-voidptrptr-invalid/fail-voidptrptr-invalid.c: -------------------------------------------------------------------------------- 1 | static void swap_ptrs(void **p1, void **p2) 2 | { 3 | void *temp = *p1; 4 | *p1 = *p2; 5 | *p2 = temp; 6 | } 7 | 8 | int main(void) 9 | { 10 | /* Here we do stuff that's genuinely invalid. Example: 1 11 | * use our swap function to swap two unsigned longs. */ 12 | int c = 42; 13 | int d = 69105; 14 | unsigned long long blah = (unsigned long long) &c; 15 | unsigned long long foo = (unsigned long long) &d; 16 | swap_ptrs(&blah, &foo); 17 | 18 | /* Any more? */ 19 | 20 | return 0; 21 | } 22 | -------------------------------------------------------------------------------- /test/fail-voidptrptr-strict/fail-voidptrptr-strict.c: -------------------------------------------------------------------------------- 1 | ../voidptrptr/voidptrptr.c -------------------------------------------------------------------------------- /test/fail-voidptrptr-strict/mk.inc: -------------------------------------------------------------------------------- 1 | export LIBCRUNCH_STRICT_GENERIC_POINTERS := 1 2 | -------------------------------------------------------------------------------- /test/function-refines/function-refines.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | long f(long int i, void *arg) 5 | { 6 | return i + (unsigned long long) arg; 7 | } 8 | 9 | int main(void) 10 | { 11 | void *fake = &f; 12 | 13 | /* Want a cast that will NOT exercise check_args but will hit the case of 14 | * __is_a_function_refining. 15 | * 16 | * In this case we're creating function ptr whose use will do 17 | * - implicit cast of arg1 from void* to long int, which is okay; 18 | * - implicit cast of arg2 from long* to void*, which is okay; 19 | * - implicit cast of long return value to void*, which is okay. */ 20 | void *(*fake_fun)(void *, long *) = (void *(*)(void*, long *)) fake; 21 | 22 | long l = 42; 23 | 24 | void *recovered = fake_fun(&fake, &l); 25 | 26 | printf("It says: %p\n", recovered); 27 | 28 | return 0; 29 | } 30 | -------------------------------------------------------------------------------- /test/hello-array/hello-array.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int is_a(void *obj, const char *typestr); 5 | 6 | struct foo 7 | { 8 | int a; 9 | double b; 10 | } blah[42]; 11 | 12 | int main(void) 13 | { 14 | void *fake1 = &blah[41]; 15 | 16 | struct foo *recovered1 = (struct foo *) fake1; 17 | 18 | void *fake2 = &blah[41].b; 19 | 20 | double *recovered2 = (double *) fake2; 21 | 22 | printf("Recovered %d\n", *recovered2); 23 | 24 | return 0; 25 | } 26 | -------------------------------------------------------------------------------- /test/hello-c++-static-cast/frontend.mk: -------------------------------------------------------------------------------- 1 | case_name := $(call get_case_name) 2 | $(call set_frontend_for_case,$(case_name),c++) 3 | $(call set_configs_for_case,$(case_name),default) 4 | -------------------------------------------------------------------------------- /test/hello-c++-static-cast/hello-c++-static-cast.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct blah 4 | { 5 | const char *b; 6 | } s = { "Hello, world!" }; 7 | 8 | int main(void) 9 | { 10 | void *p = &s; 11 | // HACK: temporarily disabled this test case 12 | std::cout << static_cast(p)->b << std::endl; 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /test/hello-c++/frontend.mk: -------------------------------------------------------------------------------- 1 | case_name := $(call get_case_name) 2 | $(call set_frontend_for_case,$(case_name),c++) 3 | $(call set_configs_for_case,$(case_name),default) 4 | -------------------------------------------------------------------------------- /test/hello-c++/hello-c++.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(void) 4 | { 5 | std::cout << "Hello, world!" << std::endl; 6 | 7 | return 0; 8 | } 9 | -------------------------------------------------------------------------------- /test/hello-errno/hello-errno.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main(void) 5 | { 6 | printf("Hello, world!\n"); 7 | errno = 0; 8 | 9 | return errno; 10 | } 11 | -------------------------------------------------------------------------------- /test/hello-funptr/hello-funptr.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | long f(long i, long *arg) 5 | { 6 | return i + (unsigned long long) arg; 7 | } 8 | 9 | int main(void) 10 | { 11 | void *fake = &f; 12 | 13 | /* Want a cast that will exercise check_args but nevertheless succeed 14 | * *iff* we're using sloppy function pointers. */ 15 | long (*fake_fun)(void *, void *) = (long(*)(void*, void*)) fake; 16 | 17 | long l = 42; 18 | 19 | /* We're allowed to pass a pointer as the first arg; it's effectively 20 | * cast to a long, but without a syntactic cast -- just by calling a 21 | * type-mismatched function. However, there's no harm done, so no error. */ 22 | long recovered = fake_fun(&fake, &l); 23 | 24 | printf("It says: %lx\n", recovered); 25 | 26 | return 0; 27 | } 28 | -------------------------------------------------------------------------------- /test/hello-funptr/mk.inc: -------------------------------------------------------------------------------- 1 | export LIBCRUNCH_SLOPPY_FUNCTION_POINTERS := 1 2 | -------------------------------------------------------------------------------- /test/hello-heap/hello-heap.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int is_a(void *obj, const char *typestr); 6 | 7 | int main() 8 | { 9 | int *blah = (int *) malloc(200 * sizeof (int)); 10 | for (int i = 0; i < 200; ++i) blah[i] = 42; 11 | 12 | void *fake = blah; 13 | 14 | int *recovered = (int *) fake; 15 | 16 | printf("It says: %d\n", recovered[0]); 17 | 18 | free(blah); 19 | 20 | return 0; 21 | } 22 | -------------------------------------------------------------------------------- /test/hello-incomplete/Makefile: -------------------------------------------------------------------------------- 1 | default: hello-incomplete 2 | 3 | hello-incomplete: hello-incomplete.c lib.o 4 | $(CC) -o "$@" $(CFLAGS) $+ $(LDFLAGS) $(LDLIBS) 5 | -------------------------------------------------------------------------------- /test/hello-incomplete/hello-incomplete.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | /* Our incomplete handling should handle correctly the case 7 | * where a library, allocating a non-incomplete type, passes 8 | * it to a client where said type is incomplete, and the client 9 | * does checks on it. */ 10 | 11 | struct Foo; // defined in library 12 | void *create_foo(void); 13 | 14 | int main(void) 15 | { 16 | __libcrunch_check_init(); 17 | 18 | struct Foo *f = create_foo(); 19 | 20 | return 0; 21 | } 22 | -------------------------------------------------------------------------------- /test/hello-incomplete/lib.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct Foo 4 | { 5 | int a; 6 | float b; 7 | }; 8 | 9 | /* GRR: we have to disable optimisation because gcc will turn 10 | * the malloc call into a jmp, and that means the *caller* will 11 | * show up as the allocation site. We could make create_foo an 12 | * allocation function, but that is displeasing in other ways. 13 | */ 14 | void *create_foo(void) __attribute__((optimize("O0"))); 15 | void *create_foo(void) 16 | { 17 | return malloc(sizeof(struct Foo)); 18 | } 19 | -------------------------------------------------------------------------------- /test/hello-incomplete/mk.inc: -------------------------------------------------------------------------------- 1 | hello-incomplete: lib.o 2 | hello-incomplete: 3 | -------------------------------------------------------------------------------- /test/hello-indirect/hello-indirect.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | /* Disable optimization to prevent compiler from un-indirecting 6 | * our indirect calls. */ 7 | 8 | struct S 9 | { 10 | void *(*fn)(size_t); 11 | } s; 12 | 13 | void *(*fs[2])(size_t); 14 | 15 | int (__attribute__((optimize("O0"))) main)() 16 | { 17 | void *(*fn)(size_t) = &malloc; 18 | 19 | int *blah = (int *) fn(200 * sizeof (int)); 20 | 21 | for (int i = 0; i < 200; ++i) blah[i] = 42; 22 | 23 | void *fake = blah; 24 | 25 | int *recovered = (int *) fake; 26 | 27 | printf("It says: %d\n", recovered[0]); 28 | 29 | free(blah); 30 | 31 | void *(**fn2)(size_t) = &fn; 32 | 33 | blah = (int *) (*fn2)(200 * sizeof (int)); 34 | 35 | fake = blah; 36 | recovered = (int *) fake; 37 | free(blah); 38 | 39 | void *(***fn3)(size_t) = &fn2; 40 | 41 | blah = (int *) (***fn3)(200 * sizeof (int)); 42 | fake = blah; 43 | recovered = (int *) fake; 44 | free(blah); 45 | 46 | s.fn = &malloc; 47 | blah = s.fn(200 * sizeof (int)); 48 | fake = blah; 49 | recovered = (int *) fake; 50 | free(blah); 51 | 52 | fs[1] = &malloc; 53 | blah = fs[1](200 * sizeof (int)); 54 | fake = blah; 55 | recovered = (int *) fake; 56 | free(blah); 57 | 58 | return 0; 59 | } 60 | -------------------------------------------------------------------------------- /test/hello-qualified-char/hello-qualified-char.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "libcrunch.h" 4 | 5 | static char blah[] = "blah!"; 6 | 7 | int main(void) 8 | { 9 | void *fake = &blah; 10 | 11 | const char *recovered = (const char *) fake; 12 | 13 | printf("It says: %s\n", recovered); 14 | 15 | /* The point of this test used to be that libcrunch should 16 | * NOT be inited. Now that __libcrunch_global_init is a 17 | * constructor, we need some other way. */ 18 | assert(__libcrunch_begun == 0); 19 | 20 | return 0; 21 | } 22 | -------------------------------------------------------------------------------- /test/hello-sizeofness/hello-sizeofness.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | /* Here we do an allocation which can only be correctly classified 6 | * by a sizeofness-propagating malloc scraper.*/ 7 | 8 | static void *alloc(void) 9 | { 10 | size_t size_to_allocate = sizeof (long); 11 | return malloc(size_to_allocate); 12 | } 13 | 14 | int main() 15 | { 16 | void *my_obj = alloc(); 17 | *(long *)my_obj = 42; 18 | printf("My obj is %ld\n", *(long *)my_obj); 19 | 20 | return 0; 21 | } 22 | -------------------------------------------------------------------------------- /test/hello-stack/hello-stack.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int is_a(void *obj, const char *typestr); 5 | 6 | // this overridable function ensures we don't get our padding optimised out 7 | void twiddle(char *blah) 8 | { 9 | 10 | } 11 | 12 | int main() 13 | { 14 | const char padding1[42]; 15 | int blah[] = { 42, 42, 42 }; 16 | const char padding2[42]; 17 | twiddle(padding1); 18 | twiddle(padding2); 19 | 20 | void *fake_start = &blah; 21 | 22 | int *recovered_start = (int *) fake_start; 23 | 24 | printf("It says: %d\n", recovered_start[0]); 25 | 26 | // also try from the middle 27 | void *fake_middle = &blah[2]; 28 | int *recovered_middle = (int *) fake_middle; 29 | assert(*recovered_middle == 42); 30 | 31 | return 0; 32 | } 33 | -------------------------------------------------------------------------------- /test/hello-stackactual/hello-stackactual.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | static int called(int blah) 5 | { 6 | void *fake_blah = &blah; 7 | return *(int *)fake_blah; 8 | } 9 | 10 | int main() 11 | { 12 | int b = 42; 13 | int got = called(b); 14 | assert(got == b); 15 | 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /test/hello-static/hello-static.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int is_a(void *obj, const char *typestr); 5 | 6 | static int blah = 42; 7 | 8 | int main(void) 9 | { 10 | void *fake = &blah; 11 | 12 | int *recovered = (int *) fake; 13 | 14 | printf("It says: %d\n", *recovered); 15 | 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /test/hello-stubgen/hello-stubgen.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | /* Disable optimization to prevent compiler from inlining our 6 | * xmalloc call. This doesn't usually happen for malloc wrappers; 7 | * only because we're in the same file (and linking an executable?). 8 | * ALSO, note that --wrap won't work for us; recall that --wrap will 9 | * 10 | * - change an undefined symbol X to __wrap_X; 11 | * - change an undefined symbol __real_X to X. 12 | * 13 | * It does nothing for defined symbols! Which is what we really want to 14 | * have here, i.e. having the wrapper and its client in the same file. 15 | * So to hack around this, we leave xmalloc undefined, but define 16 | * __my_xmalloc here, then use a magic --defsym option (in mk.inc) to fix 17 | * up the xmalloc-> reference later. NOTE: calling it __real_xmalloc 18 | * doesn't work, because the --defsym,xmalloc=__real_xmalloc will 19 | * bizarrely cause xmalloc to take the value zero. */ 20 | 21 | void *(__attribute__((optimize("O0"))) __my_xmalloc)(size_t s) 22 | { 23 | return malloc(s); 24 | } 25 | 26 | void *xmalloc(size_t s); 27 | 28 | int (__attribute__((optimize("O0"))) main)(void) 29 | { 30 | int *blah = (int *) xmalloc(200 * sizeof (int)); 31 | for (int i = 0; i < 200; ++i) blah[i] = 42; 32 | 33 | void *fake = blah; 34 | 35 | int *recovered = (int *) fake; 36 | 37 | printf("It says: %d\n", recovered[0]); 38 | 39 | free(blah); 40 | 41 | return 0; 42 | } 43 | -------------------------------------------------------------------------------- /test/hello-stubgen/mk.inc: -------------------------------------------------------------------------------- 1 | export LIBALLOCS_ALLOC_FNS := xmalloc(Z)p 2 | LDFLAGS += -Wl,--defsym,xmalloc=__my_xmalloc 3 | -------------------------------------------------------------------------------- /test/hello-union/hello-union.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct r 4 | { 5 | union s 6 | { 7 | struct t 8 | { 9 | union u 10 | { 11 | int v; 12 | float w; 13 | } u; 14 | int x; 15 | } t; 16 | union y 17 | { 18 | double z; 19 | int a; 20 | } y; 21 | } s; 22 | } r; 23 | 24 | void my_bzero(void *ptr, size_t s) 25 | { 26 | for (size_t i = 0; i < s; ++i) 27 | { 28 | ((char*) ptr)[i] = 0; 29 | } 30 | } 31 | 32 | int main(void) 33 | { 34 | void *p_v1 = &r.s.t.u.v; 35 | int v1 = *(int*) p_v1; 36 | 37 | void *p_v2 = &r.s.t.u.w; 38 | float v2 = *(float*) p_v2; 39 | 40 | void *p_v3 = &r.s.t.u.w; 41 | float v3 = *(float*) p_v3; 42 | 43 | void *p_v4 = &r.s.y.z; 44 | double v4 = *(double*) p_v4; 45 | 46 | void *p_v5 = &r.s.y.a; 47 | int v5 = *(int*) p_v5; 48 | 49 | printf("Success! %d %f %f %f %i\n", v1, v2, v3, (float) v4, v5); 50 | 51 | return 0; 52 | } 53 | -------------------------------------------------------------------------------- /test/hello-void/hello-void.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "libcrunch.h" 4 | 5 | int main(void) 6 | { 7 | /* NOTE: the point of this test case is that libcrunch SHOULD 8 | * be inited, because the strengthening of void is checked. */ 9 | struct foo { 10 | int bar; 11 | } *blah = malloc(sizeof (struct foo)); 12 | 13 | assert(__libcrunch_is_initialized); 14 | 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /test/hello/hello.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(void) 4 | { 5 | printf("Hello, world!\n"); 6 | return 0; 7 | } 8 | -------------------------------------------------------------------------------- /test/lazy-typing/lazy-typing.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "libcrunch.h" 7 | 8 | void *test_void_ptr; 9 | struct sockaddr test_sockaddr; 10 | 11 | int main(void) 12 | { 13 | struct foo { 14 | int bar; 15 | } **blah = malloc(sizeof (void*)); 16 | 17 | assert(__libcrunch_is_initialized); 18 | 19 | //struct sockaddr_in *p_mysock = malloc(sizeof (struct sockaddr)); 20 | /* FIXME: reinstate this once we have arbitrary type abstraction. */ 21 | struct sockaddr_in *p_mysock = malloc(sizeof (struct sockaddr_in)); 22 | 23 | fprintf(stderr, "Allocated a sockaddr_in at %p\n", p_mysock); 24 | 25 | return 0; 26 | } 27 | -------------------------------------------------------------------------------- /test/lazy-typing/mk.inc: -------------------------------------------------------------------------------- 1 | # FIXME: this will break if we change the type digest logic 2 | export LIBCRUNCH_LAZY_HEAP_TYPES := __PTR_void sockaddr 3 | -------------------------------------------------------------------------------- /test/like-a/like-a.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "libcrunch.h" 9 | 10 | void *test_void_ptr; 11 | struct sockaddr test_sockaddr; 12 | 13 | int main(void) 14 | { 15 | /* HACK: want to "abstract" arbitrary types, so that we can go back 16 | * to sockaddr here -- FIXME FIXME FIXME. */ 17 | struct sockaddr_in *p_mysock = malloc(sizeof (struct sockaddr_in)); 18 | 19 | fprintf(stderr, "Allocated a sockaddr_in at %p\n", p_mysock); 20 | 21 | const void *sockaddr_type = dlsym(RTLD_DEFAULT, "__uniqtype__sockaddr"); 22 | assert(sockaddr_type); 23 | 24 | assert(__like_aU(p_mysock, sockaddr_type)); 25 | 26 | return 0; 27 | } 28 | -------------------------------------------------------------------------------- /test/like-a/mk.inc: -------------------------------------------------------------------------------- 1 | export LIBCRUNCH_USE_LIKE_A_FOR_TYPES := sockaddr 2 | export LIBCRUNCH_LAZY_HEAP_TYPES := sockaddr 3 | -------------------------------------------------------------------------------- /test/noquery-bounds-adjuststore/frontend.mk: -------------------------------------------------------------------------------- 1 | case_name := $(call get_case_name) 2 | $(call set_frontend_for_case,$(case_name),c) 3 | $(call set_configs_for_case,$(case_name),x b pb mb fb sb tb Pb Mb Fb Sb Tb) 4 | -------------------------------------------------------------------------------- /test/noquery-bounds-adjuststore/mk.inc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephenrkell/libcrunch/d5710427dc1545c2473c9dc3f417a1409eb80c26/test/noquery-bounds-adjuststore/mk.inc -------------------------------------------------------------------------------- /test/noquery-bounds-adjuststore/noquery-bounds-adjuststore.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | /* Check we can adjust a pointer and store it somewhere 6 | * without the __store_pointer_nonlocal causing a call to __fetch_bounds_ool. 7 | * This is about picking up the locally cached bounds for the 8 | * __cil_adjexpr_NN temporary. */ 9 | 10 | extern unsigned long __libcrunch_fetch_bounds_called; 11 | 12 | int main(void) 13 | { 14 | int x[20] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 15 | 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 }; 16 | int *px[20]; 17 | int **p_xs = px; 18 | 19 | p_xs[0] = &x[0]; 20 | for (int i = 1; i < 20; ++i) 21 | { 22 | p_xs[i] = p_xs[i-1] + 1; 23 | } 24 | 25 | printf("The 20th integer is: %d\n", *p_xs[19]); 26 | assert(__libcrunch_fetch_bounds_called == 0); 27 | return 0; 28 | } 29 | -------------------------------------------------------------------------------- /test/noquery-bounds-itersimple/frontend.mk: -------------------------------------------------------------------------------- 1 | case_name := $(call get_case_name) 2 | $(call set_frontend_for_case,$(case_name),c) 3 | $(call set_configs_for_case,$(case_name),b pb mb fb sb tb Pb Mb Fb Sb Tb) 4 | -------------------------------------------------------------------------------- /test/noquery-bounds-itersimple/mk.inc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephenrkell/libcrunch/d5710427dc1545c2473c9dc3f417a1409eb80c26/test/noquery-bounds-itersimple/mk.inc -------------------------------------------------------------------------------- /test/noquery-bounds-itersimple/noquery-bounds-itersimple.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(void) 4 | { 5 | /* Test that we can iterate through a large array while only doing 6 | * a *single* query. */ 7 | 8 | int is[100] = { 9 | [0] = 100, 10 | [99] = 1 11 | }; 12 | int *pi = &is[0]; 13 | 14 | while (pi != &is[100]) 15 | { 16 | if (*pi != 0) 17 | { 18 | printf("Found a nonzero: %d at %d\n", *pi, (int) (pi - &is[0])); 19 | } 20 | 21 | ++pi; 22 | } 23 | 24 | /* How many queries should the above do? 25 | * We get the bounds of pi locally, because it's from a local array 26 | * (address-takenness is irrelevant). 27 | * We should locally check and trap the creation of &is[100]. 28 | * In short, I think no queries at all. 29 | * Even the __check_local_bounds should be optimised away by the compiler, 30 | * I reckon. 31 | */ 32 | 33 | return 0; 34 | } 35 | -------------------------------------------------------------------------------- /test/noquery-bounds-loadstore/frontend.mk: -------------------------------------------------------------------------------- 1 | case_name := $(call get_case_name) 2 | $(call set_frontend_for_case,$(case_name),c) 3 | $(call set_configs_for_case,$(case_name),x b pb mb fb sb tb Pb Mb Fb Sb Tb) 4 | -------------------------------------------------------------------------------- /test/noquery-bounds-loadstore/mk.inc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephenrkell/libcrunch/d5710427dc1545c2473c9dc3f417a1409eb80c26/test/noquery-bounds-loadstore/mk.inc -------------------------------------------------------------------------------- /test/noquery-bounds-loadstore/noquery-bounds-loadstore.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int *outside; 4 | int *another; 5 | int **indirect = &another; 6 | 7 | int main(void) 8 | { 9 | #ifndef LIBCRUNCH_NO_SHADOW_SPACE 10 | /* Test that we can store a pointer, load it again, and do some arithmetic 11 | * on it, without hitting the slow path. */ 12 | 13 | int is[100] = { 14 | [0] = 100, 15 | [99] = 1 16 | }; 17 | int *pi = &is[0]; 18 | 19 | outside = pi; 20 | printf("Having an effect for the sake of it...\n"); 21 | int *loaded = outside; 22 | printf("Found: %d at loaded[99]\n", loaded[99]); 23 | 24 | *indirect = pi + 42; 25 | printf("Having an effect for the sake of it...\n"); 26 | loaded = another; 27 | printf("Found: %d at another[-42]\n", another[-42]); 28 | 29 | #endif 30 | return 0; 31 | } 32 | -------------------------------------------------------------------------------- /test/noquery-bounds-multidim/frontend.mk: -------------------------------------------------------------------------------- 1 | case_name := $(call get_case_name) 2 | $(call set_frontend_for_case,$(case_name),c) 3 | $(call set_configs_for_case,$(case_name),x b pb mb fb sb tb Pb Mb Fb Sb Tb) 4 | -------------------------------------------------------------------------------- /test/noquery-bounds-multidim/mk.inc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephenrkell/libcrunch/d5710427dc1545c2473c9dc3f417a1409eb80c26/test/noquery-bounds-multidim/mk.inc -------------------------------------------------------------------------------- /test/noquery-bounds-multidim/noquery-bounds-multidim.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(void) 4 | { 5 | int is[42][23] = { [0] = { [0] = 0 } }; 6 | 7 | /* Annoyingly, CIL expands the definition above 8 | * into 9 | * - 42 pointers to arrays of 23 elements 10 | * - a 23-iteration while loop, each deriving a pointer to a 42-integer array 11 | * - a 42-iteration while loop, each iteration doing the following: 12 | * - zeroing out the first element of is[i] 13 | * - re-derive the pointer to is[i], and check that derivation 14 | * - for k in 1..22 (unrolled), check-derive *(&is[i]) + k 15 | * and write 0 into that pointer. 16 | * 17 | * We want this all to collapse away to nothingness. How? 18 | * 19 | * - each __check_derive call must pass bounds. 20 | * - those bounds come from the size of the array 21 | * - we can do this, with some fiddling. 22 | * 23 | * We also currently fail the computation of is[i] for i == 1 24 | * 25 | 26 | bounds-multidim: code at 0x407cf5 generated an out-of-bounds pointer 0x7fffffffbe58 27 | (from 0x7fffffffbda0; difference 184; lb 0x7fffffffbda0; ub 0x7fffffffbe48) 28 | 29 | (gdb) print &is 30 | $4 = (int (*)[42][23]) 0x7fffffffbda0 31 | (gdb) print &is[0][0] 32 | $5 = (int *) 0x7fffffffbda0 33 | (gdb) print &is[1][0] 34 | $6 = (int *) 0x7fffffffbdfc 35 | (gdb) print &is[2][0] 36 | $6 = (int *) 0x7fffffffbe58 37 | 38 | * i.e. the first one is okay because it's one-past; 39 | * the second one is not okay because it's far out. 40 | */ 41 | 42 | 43 | int *p = &is[0][0]; 44 | 45 | p += 43; 46 | 47 | // this one is okay to dereference 48 | fprintf(stderr, "Got address %p, value %d\n", p, *p); 49 | 50 | return 0; 51 | } 52 | -------------------------------------------------------------------------------- /test/noquery-bounds-nofetch/frontend.mk: -------------------------------------------------------------------------------- 1 | case_name := $(call get_case_name) 2 | $(call set_frontend_for_case,$(case_name),c) 3 | $(call set_configs_for_case,$(case_name),x b pb mb fb sb tb Pb Mb Fb Sb Tb) 4 | -------------------------------------------------------------------------------- /test/noquery-bounds-nofetch/mk.inc: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /test/noquery-bounds-nofetch/noquery-bounds-nofetch.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | struct B 6 | { 7 | int a[4]; 8 | unsigned *pis[2]; 9 | float c[1]; 10 | int y; 11 | }; 12 | 13 | struct A 14 | { 15 | struct B bs[4]; 16 | int x; 17 | struct B another; 18 | }; 19 | 20 | static unsigned blah = 42; 21 | 22 | int main(void) 23 | { 24 | /* We should be able to index into these arrays 25 | * using a non-constant index expression 26 | * and still not generate any bounds fetches, 27 | * because we're indexing inside a local object. 28 | * Instead, we'll generate checks that the expression 29 | * is within the local bounds. */ 30 | 31 | struct A as[3] = { 32 | [0] = { /* an A starts here */ 33 | { [0] = { /* a B starts here */ 34 | /* a */ { [0] = 0 }, 35 | /* pis */ { [0] = &blah }, 36 | /* c */ { [0] = 0.0 }, 37 | /* y */ 0 38 | } 39 | }, 40 | /* x */ 1, 41 | /* another B starts here */ 42 | { { [0] = 0 }, { [0] = NULL }, { [0] = 0.0 }, 0 } 43 | }, 44 | [1] = { /* an A starts here */ 45 | { [3] = { /* a B starts here */ 46 | /* a */ { [0] = 0 }, 47 | /* pis */ { [0] = &blah }, 48 | /* c */ { [0] = 0.0 }, 49 | /* y */ 1 50 | } 51 | }, 52 | /* x */ 0, 53 | /* another B starts here */ 54 | { { [0] = 0 }, { [0] = NULL }, { [0] = 0.0 }, 0 } 55 | }, 56 | [2] = { /* an A starts here */ 57 | { [3] = { /* a B starts here */ 58 | /* a */ { [0] = 0 }, 59 | /* pis */ { [0] = &blah }, 60 | /* c */ { [0] = 0.0 }, 61 | /* y */ 0 62 | } 63 | }, 64 | /* x */ 0, 65 | /* another B starts here */ 66 | { { [0] = 0 }, { [0] = &blah }, { [0] = 0.0 }, 0 } 67 | } 68 | }; 69 | /* GAH. Don't do memset, because it makes the storage address-taken. 70 | * FIXME: might want to make an exception for memset in the 71 | * address-taken analysis done by CIL. */ 72 | // memset(as, 0, sizeof as); 73 | 74 | /* In total, this local array 75 | * contains 76 | * 77 | * 3 * (4 + 1) * 2 = 30 78 | * 79 | * bounds objects. */ 80 | printf("Some numbers from in-bounds accesses: %d %d %d\n", 81 | as[(int) (drand48() * 2)].x, 82 | as[1].bs[(int) (drand48() * 2)].y, 83 | as[2].bs[3].a[(int) (drand48() * 4)]); 84 | printf("Some pointers from in-bounds accesses: %p %p %p\n", 85 | as[0].bs[(int) (drand48() * 2)].pis[0], 86 | as[1].bs[3].pis[(int) (drand48() * 2)], 87 | as[2].another.pis[(int) (drand48() * 2)]); 88 | 89 | return 0; 90 | } 91 | -------------------------------------------------------------------------------- /test/noquery-bounds-static-init-ptr/frontend.mk: -------------------------------------------------------------------------------- 1 | case_name := $(call get_case_name) 2 | $(call set_frontend_for_case,$(case_name),c) 3 | $(call set_configs_for_case,$(case_name),x b pb mb fb sb tb Pb Mb Fb Sb Tb) 4 | -------------------------------------------------------------------------------- /test/noquery-bounds-static-init-ptr/mk.inc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephenrkell/libcrunch/d5710427dc1545c2473c9dc3f417a1409eb80c26/test/noquery-bounds-static-init-ptr/mk.inc -------------------------------------------------------------------------------- /test/noquery-bounds-static-init-ptr/noquery-bounds-static-init-ptr.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int vs[] = { 1, 2, 3 }; 5 | 6 | /* Here we are testing the path in libcrunch.c which initializes the shadow space 7 | * with bounds for all statically initialized pointers. If it succeeds, it will 8 | * be possible to do adjustments on such a pointer without resorting to a liballocs 9 | * query. */ 10 | 11 | int main(void) 12 | { 13 | static int *arr[] = { &vs[0], &vs[1], &vs[2] }; 14 | static struct { int *blah; } container = { &vs[0] }; 15 | 16 | int n = rand(); 17 | int sz = (sizeof arr / sizeof arr[0]); 18 | int idx = n % sz; 19 | printf("Randomly read: %d\n", *(arr[idx] + rand() % (sz - idx))); 20 | printf("Randomly read: %d\n", *(container.blah + rand() % sz)); 21 | return 0; 22 | } 23 | -------------------------------------------------------------------------------- /test/noquery-bounds-viacache/frontend.mk: -------------------------------------------------------------------------------- 1 | case_name := $(call get_case_name) 2 | $(call set_frontend_for_case,$(case_name),c) 3 | $(call set_configs_for_case,$(case_name),b pb mb fb Pb Mb Fb) 4 | -------------------------------------------------------------------------------- /test/noquery-bounds-viacache/mk.inc: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /test/noquery-bounds-viacache/noquery-bounds-viacache.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | struct B 7 | { 8 | unsigned *pis[2]; 9 | }; 10 | 11 | struct A 12 | { 13 | struct B bs[4]; 14 | }; 15 | 16 | void do_it(void* p) 17 | { 18 | unsigned **recovered = (unsigned**) ((uintptr_t) p - sizeof (unsigned **)); 19 | struct B *blah = (struct B *) recovered; 20 | printf("We got: (recovered) %u, (indexed) %u\n", *blah->pis[0], *recovered[1]); 21 | } 22 | 23 | int main(void) 24 | { 25 | /* Here we are using a pattern (a bit like that in milc from SPEC CPU2006) 26 | * where we do some casts with funky address arithmetic. 27 | * 28 | * What should happen: 29 | * 30 | * When we do the cast to char*, we prefill the cache with the *old* type 31 | * info. We have this from two sources: the static type of the cast-from 32 | * pointer, and its bounds information. 33 | * 34 | * This allocation may already be in the cache, of course. We use an out- 35 | * -of-line helper, mostly dual to __fetch_bounds_from_cache. 36 | * 37 | * Short summary: we try not to lose information. 38 | */ 39 | 40 | unsigned first = 1; 41 | unsigned second = 2; 42 | unsigned third = 3; 43 | unsigned fourth = 4; 44 | 45 | struct A a = { .bs = { [0] = (struct B) { .pis = { [0] = &first, [1] = &second } }, 46 | [1] = (struct B) { .pis = { [0] = &third, [1] = &fourth } } } }; 47 | 48 | /* NOTE: I initially had the "generic pointer" be char*. 49 | * This causes two cache-missing queries. 50 | * One is to get the bounds of the allocation. 51 | * The other is to do the same... because the stack is not a cacheable allocator. BAH. 52 | */ 53 | do_it((void*) &a.bs[0].pis[1]); 54 | do_it((void*) &a.bs[1].pis[1]); 55 | return 0; 56 | } 57 | -------------------------------------------------------------------------------- /test/pointer-degree/mk.inc: -------------------------------------------------------------------------------- 1 | # while we use the side-effecting __libcrunch_failed to detect failure 2 | CFLAGS += -DNO_PURE 3 | -------------------------------------------------------------------------------- /test/pointer-degree/pointer-degree.c: -------------------------------------------------------------------------------- 1 | #include "libcrunch.h" 2 | 3 | extern unsigned long __libcrunch_failed; 4 | 5 | int main(void) 6 | { 7 | void *blah1; 8 | void **blah2; 9 | void ***blah3; 10 | void ****blah4; 11 | int i; 12 | 13 | /* HACK: because our assertions always evaluate true 14 | * at the moment, we can't write them as we'd like to. 15 | * Instead, assert the failure count. */ 16 | _Bool b0 = __is_a_pointer_of_degree_internal(&i, 0); 17 | assert(__libcrunch_failed == 1); 18 | _Bool b1 = __is_a_pointer_of_degree_internal(&i, 1); 19 | assert(__libcrunch_failed == 2); 20 | _Bool b2 = __is_a_pointer_of_degree_internal(&i, 2); 21 | assert(__libcrunch_failed == 3); 22 | 23 | assert(__is_a_pointer_of_degree_internal(&blah1, 1)); 24 | 25 | assert(__is_a_pointer_of_degree_internal(&blah2, 1)); 26 | assert(__is_a_pointer_of_degree_internal(&blah2, 2)); 27 | 28 | assert(__is_a_pointer_of_degree_internal(&blah3, 1)); 29 | assert(__is_a_pointer_of_degree_internal(&blah3, 2)); 30 | assert(__is_a_pointer_of_degree_internal(&blah3, 3)); 31 | 32 | assert(__is_a_pointer_of_degree_internal(&blah4, 1)); 33 | assert(__is_a_pointer_of_degree_internal(&blah4, 2)); 34 | assert(__is_a_pointer_of_degree_internal(&blah4, 3)); 35 | assert(__is_a_pointer_of_degree_internal(&blah4, 4)); 36 | 37 | _Bool p2 = __is_a_pointer_of_degree_internal(&blah1, 2); 38 | assert(__libcrunch_failed == 4); 39 | _Bool p3 = __is_a_pointer_of_degree_internal(&blah2, 3); 40 | assert(__libcrunch_failed == 5); 41 | _Bool p4 = __is_a_pointer_of_degree_internal(&blah3, 4); 42 | assert(__libcrunch_failed == 6); 43 | _Bool p5 = __is_a_pointer_of_degree_internal(&blah4, 5); 44 | assert(__libcrunch_failed == 7); 45 | 46 | return 0; 47 | 48 | } 49 | -------------------------------------------------------------------------------- /test/sloppy-gpcot/mk.inc: -------------------------------------------------------------------------------- 1 | export LIBCRUNCH_ABSTRACT_LVALUE_TYPES := View 2 | 3 | -------------------------------------------------------------------------------- /test/sloppy-gpcot/sloppy-gpcot.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct ObjA 4 | { 5 | int *hdr; 6 | void **other; 7 | }; 8 | 9 | struct ObjB 10 | { 11 | float *hdr; 12 | int **other; 13 | long more; 14 | }; 15 | 16 | struct View 17 | { 18 | void *hdr; 19 | void **other; 20 | }; 21 | 22 | int *x = NULL; 23 | int *y = NULL; 24 | 25 | int main(void) 26 | { 27 | struct ObjA o1; 28 | struct ObjB o2; 29 | 30 | ((struct View *) &o1)->other = &x; 31 | ((struct View *) &o2)->other = &y; 32 | 33 | return 0; 34 | } 35 | -------------------------------------------------------------------------------- /test/softbound-actuals/frontend.mk: -------------------------------------------------------------------------------- 1 | case_name := $(call get_case_name) 2 | $(call set_frontend_for_case,$(case_name),c) 3 | $(call set_configs_for_case,$(case_name),sb tb Sb Tb) 4 | -------------------------------------------------------------------------------- /test/softbound-actuals/mk.inc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephenrkell/libcrunch/d5710427dc1545c2473c9dc3f417a1409eb80c26/test/softbound-actuals/mk.inc -------------------------------------------------------------------------------- /test/softbound-actuals/softbound-actuals.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct ptrs 4 | { 5 | char *p1; 6 | char *p2; 7 | char *ps[3]; 8 | }; 9 | 10 | struct many_ptrs 11 | { 12 | struct ptrs many[5]; 13 | }; 14 | 15 | static void f(char *p, struct ptrs x1, struct many_ptrs xx) 16 | { 17 | printf("It says: %c%c%c%c%c%c%c%c%c%c%c\n", 18 | p[1], 19 | x1.p1[2], 20 | x1.p2[3], 21 | x1.ps[0][0], 22 | x1.ps[1][1], 23 | x1.ps[2][2], 24 | xx.many[0].p1[2], 25 | xx.many[1].p2[2], 26 | xx.many[2].ps[0][3], 27 | xx.many[3].ps[1][0], 28 | xx.many[4].ps[2][1] 29 | ); 30 | 31 | ++p; 32 | ++x1.p1; 33 | ++x1.p2; 34 | ++x1.ps[0]; 35 | ++x1.ps[1]; 36 | ++x1.ps[2]; 37 | ++xx.many[0].p1; 38 | ++xx.many[1].p2; 39 | ++xx.many[2].ps[0]; 40 | ++xx.many[3].ps[1]; 41 | ++xx.many[4].ps[2]; 42 | 43 | printf("Now it says: %c%c%c%c%c%c%c%c%c%c%c\n", 44 | p[1], 45 | x1.p1[2], 46 | x1.p2[3], 47 | x1.ps[0][0], 48 | x1.ps[1][1], 49 | x1.ps[2][2], 50 | xx.many[0].p1[2], 51 | xx.many[1].p2[2], 52 | xx.many[2].ps[0][3], 53 | xx.many[3].ps[1][0], 54 | xx.many[4].ps[2][1] 55 | ); 56 | } 57 | 58 | char msg1[] = "Hello, world!"; 59 | char msg2[] = "Hello, sailor!"; 60 | char msg3[] = "Fool!"; 61 | 62 | int main(void) 63 | { 64 | f( 65 | msg2, 66 | (struct ptrs) { msg1, msg2, { msg3, msg3, msg3 } }, 67 | (struct many_ptrs) { 68 | (struct ptrs) { msg1, msg2, { msg3, msg2, msg1 } }, 69 | (struct ptrs) { msg2, msg3, { msg2, msg3, msg2 } }, 70 | (struct ptrs) { msg3, msg1, { msg1, msg1, msg3 } }, 71 | (struct ptrs) { msg1, msg2, { msg3, msg2, msg1 } }, 72 | (struct ptrs) { msg2, msg3, { msg2, msg3, msg2 } } 73 | } 74 | ); 75 | return 0; 76 | } 77 | 78 | /* 79 | struct { 80 | char *p; 81 | } local_struct; 82 | 83 | local_struct.p = &as[-1] 84 | 85 | FIXME: local arrays of pointers 86 | */ 87 | -------------------------------------------------------------------------------- /test/softbound-heap/frontend.mk: -------------------------------------------------------------------------------- 1 | case_name := $(call get_case_name) 2 | $(call set_frontend_for_case,$(case_name),c) 3 | $(call set_configs_for_case,$(case_name),sb tb Sb Tb,blah) 4 | -------------------------------------------------------------------------------- /test/softbound-heap/mk.inc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephenrkell/libcrunch/d5710427dc1545c2473c9dc3f417a1409eb80c26/test/softbound-heap/mk.inc -------------------------------------------------------------------------------- /test/softbound-heap/softbound-heap.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main(void) 5 | { 6 | /* Test that we check all the pointer derivations in the following. */ 7 | char *buf = calloc(1, 42); 8 | buf[41] = '\0'; 9 | 10 | *(int*)&buf[20] = 42; 11 | 12 | return 0; 13 | } 14 | -------------------------------------------------------------------------------- /test/softbound-multi-alloc/frontend.mk: -------------------------------------------------------------------------------- 1 | case_name := $(call get_case_name) 2 | $(call set_frontend_for_case,$(case_name),c) 3 | $(call set_configs_for_case,$(case_name),sb tb Sb Tb) 4 | -------------------------------------------------------------------------------- /test/softbound-multi-alloc/mk.inc: -------------------------------------------------------------------------------- 1 | export CFLAGS := $(CFLAGS) -save-temps -std=c11 -DLIBCRUNCH_TRACE_BOUNDS_STACK 2 | export LIBALLOCS_ALLOC_FNS := alloc(Z)p 3 | -------------------------------------------------------------------------------- /test/softbound-multi-alloc/softbound-multi-alloc.c: -------------------------------------------------------------------------------- 1 | /* This is based on sphinx3's ckd_alloc.c / __mymalloc__, 2 | * which creates small object pools 3 | * and links the free ones together in a free list. 4 | * This linking disrespects the type of the object, 5 | * by blatting the free-list pointers into the first word of 6 | * each object. */ 7 | 8 | #include 9 | #include 10 | 11 | void *alloc(size_t elemsize) 12 | { 13 | static char **freelist; 14 | #define NBLOCK 50 15 | /* This cast happens to be valid for our caller, because the object's first argument 16 | * is a void* and char** is a generic pointer pointer. However, we get the bounds 17 | * [cpp, cpp+8bytes).*/ 18 | char **cpp = freelist = (char **) calloc(NBLOCK, elemsize); 19 | /* We should now get the bounds of the whole allocation. */ 20 | char *cp = (char *) cpp; 21 | for (int j = NBLOCK - 1; j > 0; --j) 22 | { 23 | cp += elemsize; 24 | *cpp = cp; 25 | cpp = (char **)cp; 26 | } 27 | *cpp = NULL; 28 | 29 | // unlink one and return it 30 | cp = (char *)freelist; 31 | freelist = (char **)(*freelist); 32 | return cp; 33 | } 34 | 35 | 36 | struct myelem 37 | { 38 | void *blah; 39 | int x; 40 | }; 41 | 42 | int main(void) 43 | { 44 | struct myelem *e = alloc(sizeof (struct myelem)); 45 | e->blah = NULL; 46 | e->x = 42; 47 | printf("At %p, blah is %p and x is %d\n", e, e->blah, e->x); 48 | return 0; 49 | } 50 | -------------------------------------------------------------------------------- /test/softbound-nonlocal/frontend.mk: -------------------------------------------------------------------------------- 1 | case_name := $(call get_case_name) 2 | $(call set_frontend_for_case,$(case_name),c) 3 | $(call set_configs_for_case,$(case_name),sb tb Sb Tb) 4 | -------------------------------------------------------------------------------- /test/softbound-nonlocal/mk.inc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephenrkell/libcrunch/d5710427dc1545c2473c9dc3f417a1409eb80c26/test/softbound-nonlocal/mk.inc -------------------------------------------------------------------------------- /test/softbound-nonlocal/softbound-nonlocal.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | const char *f(void) 4 | { 5 | static const char *s = "Blah!"; 6 | 7 | return s; 8 | } 9 | 10 | const char *temp; 11 | 12 | int main(void) 13 | { 14 | temp = f(); 15 | printf("Now I say: %s\n", temp + 2); 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /test/softbound-simple/frontend.mk: -------------------------------------------------------------------------------- 1 | case_name := $(call get_case_name) 2 | $(call set_frontend_for_case,$(case_name),c) 3 | $(call set_configs_for_case,$(case_name),sb tb Sb Tb) 4 | -------------------------------------------------------------------------------- /test/softbound-simple/mk.inc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephenrkell/libcrunch/d5710427dc1545c2473c9dc3f417a1409eb80c26/test/softbound-simple/mk.inc -------------------------------------------------------------------------------- /test/softbound-simple/softbound-simple.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(void) 4 | { 5 | /* Test that we check all the pointer derivations in the following. */ 6 | 7 | char as[42] = "abcdefghijklmnopqrstuvwxyz0123456789ABCDE"; 8 | char bs[100] = "qwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzx"; 9 | struct { 10 | int xyzzy; 11 | char *plugh; 12 | } cs[2] = { { 101, "a" }, { 102, "b" } }; 13 | 14 | char *a = &as[41]; 15 | printf("Got a: %p\n", a); 16 | 17 | char *b = &as[1]; 18 | printf("Got b: %p\n", b); 19 | 20 | char *c = &as[a - b]; // difference 40 21 | printf("Got c: %p\n", c); 22 | 23 | char *d = &bs[as[2]]; // value 'b' a.k.a. 98 24 | printf("Got d: %p\n", d); 25 | 26 | char **e = &cs[0].plugh; 27 | printf("Got e: %p\n", e); 28 | 29 | return 0; 30 | } 31 | 32 | /* 33 | struct { 34 | char *p; 35 | } local_struct; 36 | 37 | local_struct.p = &as[-1] 38 | 39 | FIXME: local arrays of pointers 40 | */ 41 | -------------------------------------------------------------------------------- /test/softbound-static-init-ptr/frontend.mk: -------------------------------------------------------------------------------- 1 | case_name := $(call get_case_name) 2 | $(call set_frontend_for_case,$(case_name),c) 3 | $(call set_configs_for_case,$(case_name),sb tb Sb Tb) 4 | -------------------------------------------------------------------------------- /test/softbound-static-init-ptr/mk.inc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephenrkell/libcrunch/d5710427dc1545c2473c9dc3f417a1409eb80c26/test/softbound-static-init-ptr/mk.inc -------------------------------------------------------------------------------- /test/softbound-static-init-ptr/softbound-static-init-ptr.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int vs[] = { 1, 2, 3 }; 5 | extern int other_vs[] __attribute__((alias("vs"))); 6 | __asm__(".size other_vs, 12"); /* HACK: we depend on the size of the alias */ 7 | 8 | /* See noquery-bounds-static-init-ptr. 9 | * The difference here is that some bounds initializers *will* require a query. 10 | */ 11 | 12 | int main(void) 13 | { 14 | static int *arr[] = { &vs[0], &vs[1], &vs[2] }; 15 | static struct { int *blah; } other_container = { &other_vs[0] }; 16 | 17 | int n = rand(); 18 | int sz = (sizeof arr / sizeof arr[0]); 19 | printf("Randomly read: %d\n", *(other_container.blah + rand() % sz)); 20 | return 0; 21 | } 22 | -------------------------------------------------------------------------------- /test/specialize-types/specialize-types.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | static void copy_ptr(void **dst, int **src) 4 | { 5 | *dst = *src; 6 | } 7 | 8 | int main(void) 9 | { 10 | // allocate an array of void* 11 | void **p = malloc(8 * sizeof (void*)); 12 | // make an int** point to it -- specializing it to int* 13 | // (specialization by pointing-something-at) 14 | int **pi = p; 15 | //assert(__liballocs_get_type(pi) == &__uniqtype____PTR_int); 16 | // use a generic function to manipulate the int* as if they were void* 17 | // (specialization by storing-into... but, hmm, storing into a void** is okay??) 18 | void **buf = malloc(sizeof (void*)); 19 | copy_ptr(buf, pi); 20 | // specialization by casting 21 | int **x = (int**) malloc(2 * sizeof (void*)); 22 | printf("It was: %p\n", x); 23 | return 0; 24 | } 25 | -------------------------------------------------------------------------------- /test/trap-bounds-oneprev/frontend.mk: -------------------------------------------------------------------------------- 1 | case_name := $(call get_case_name) 2 | $(call set_frontend_for_case,$(case_name),c) 3 | $(call set_configs_for_case,$(case_name),x b pb mb fb tb Pb Mb Fb Tb) 4 | -------------------------------------------------------------------------------- /test/trap-bounds-oneprev/mk.inc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephenrkell/libcrunch/d5710427dc1545c2473c9dc3f417a1409eb80c26/test/trap-bounds-oneprev/mk.inc -------------------------------------------------------------------------------- /test/trap-bounds-oneprev/trap-bounds-oneprev.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main(void) 5 | { 6 | /* Test that we check all the pointer derivations in the following. */ 7 | 8 | int is[2] = { 42, 43 }; 9 | 10 | uintptr_t sneaky = (uintptr_t) &is[0]; 11 | sneaky -= sizeof (int); 12 | int *i_sneaky = (int *) sneaky; 13 | int *i_post = &is[2]; 14 | int *i_pre = &is[-1]; 15 | 16 | return 0; 17 | } 18 | 19 | /* 20 | struct { 21 | char *p; 22 | } local_struct; 23 | 24 | local_struct.p = &as[-1] 25 | 26 | FIXME: local arrays of pointers 27 | */ 28 | -------------------------------------------------------------------------------- /test/trap-bounds-toint/frontend.mk: -------------------------------------------------------------------------------- 1 | case_name := $(notdir $(realpath $(dir $(realpath $(lastword $(MAKEFILE_LIST)))))) 2 | CASES_c := $(CASES_c) $(case_name) 3 | CASES_CONFIG_x := $(CASES_CONFIG_x) $(case_name) 4 | case_name := $(call get_case_name) 5 | $(call set_frontend_for_case,$(case_name),c) 6 | $(call set_configs_for_case,$(case_name),x b pb mb fb Pb Mb Fb) 7 | -------------------------------------------------------------------------------- /test/trap-bounds-toint/mk.inc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephenrkell/libcrunch/d5710427dc1545c2473c9dc3f417a1409eb80c26/test/trap-bounds-toint/mk.inc -------------------------------------------------------------------------------- /test/trap-bounds-toint/trap-bounds-toint.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main(void) 7 | { 8 | char pad1[200]; 9 | int is[] = { 0, 1, 2, 3, 4 }; 10 | char pad2[200]; 11 | 12 | /* If we convert a trapped pointer to int, we should get a sensible value. */ 13 | int *i1 = &is[5]; 14 | unsigned long i = (unsigned long) i1; 15 | printf("The int we got is 0x%lx\n", i); 16 | assert(i - (unsigned long) &is[4] == sizeof (int)); 17 | 18 | /* If we convert it back to a char*, it should be usable. 19 | * ACTUALLY it's not obvious that this is true. Our cast 20 | * logic needs to detect when we're casting to the "edge" 21 | * of something, if there's no abutting object. */ 22 | for (char *pc = (char*) i - sizeof (int); pc >= (char*) &is[0]; --pc) 23 | { 24 | printf("Saw a byte: %x\n", *pc); 25 | } 26 | 27 | /* If we convert a cleanly in-bounds integer value back to int*, 28 | * we should also get something that works. Note that the termination 29 | * of this loop makes a totally out-of-bounds pointer, which is not 30 | * okay. It should yield a trap pointer, but not terminate the program. */ 31 | for (int *pi = (int*) (i - sizeof (int)); pi >= &is[0]; --pi) 32 | { 33 | printf("Saw an int: %d\n", *pi); 34 | } 35 | 36 | return 0; 37 | } 38 | 39 | /* 40 | struct { 41 | char *p; 42 | } local_struct; 43 | 44 | local_struct.p = &as[-1] 45 | 46 | FIXME: local arrays of pointers 47 | */ 48 | -------------------------------------------------------------------------------- /test/va_arg/va_arg.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void my_interp(const char *str, ...) 5 | { 6 | va_list va; 7 | va_start(va, str); 8 | char c; 9 | void *p; 10 | int *pi; 11 | float *pf; 12 | while ('\0' != (c = *str++)) 13 | { 14 | switch (c) 15 | { 16 | case 'i': 17 | pi = va_arg(va, int*); 18 | fprintf(stdout, "Seen in interp program: %d\n", *pi); 19 | break; 20 | case 'f': 21 | pf = va_arg(va, float*); 22 | fprintf(stdout, "Seen in interp program: %f\n", *pf); 23 | break; 24 | default: 25 | p = va_arg(va, void*); 26 | fprintf(stdout, "Unrecognised char in interp program: '%c'\n", c); 27 | break; 28 | } 29 | } 30 | va_end(va); 31 | } 32 | 33 | int main(void) 34 | { 35 | int i = 42; 36 | int j = 69105; 37 | float e = 2.71828; 38 | 39 | my_interp("ifi", &i, &e, &j); 40 | 41 | return 0; 42 | } 43 | -------------------------------------------------------------------------------- /test/voidptrptr/voidptrptr.c: -------------------------------------------------------------------------------- 1 | static void swap_ptrs(void **p1, void **p2) 2 | { 3 | void *temp = *p1; 4 | *p1 = *p2; 5 | *p2 = temp; 6 | } 7 | 8 | int main(void) 9 | { 10 | int c = 42; 11 | int d = 69105; 12 | int *blah = &c; 13 | int *foo = &d; 14 | swap_ptrs(&blah, &foo); 15 | 16 | return 0; 17 | } 18 | --------------------------------------------------------------------------------