Code Monkey home page Code Monkey logo

staticafi / symbiotic Goto Github PK

View Code? Open in Web Editor NEW
306.0 12.0 56.0 2.14 MB

Symbiotic is a tool for finding bugs in computer programs based on instrumentation, program slicing and KLEE

Home Page: http://staticafi.github.io/symbiotic/

License: MIT License

Shell 9.56% Python 55.07% C 10.62% CMake 0.76% C++ 23.53% Makefile 0.01% SWIG 0.12% Dockerfile 0.11% Assembly 0.23%
verification verification-toolchain symbolic-execution program-slicing slicing klee llvm instrumentation slice llvm-ir program-verification software-verification

symbiotic's Introduction

Build - Linux CI

Symbiotic is an open-source framework for program analysis integrating instrumentation, static program slicing and various program analysis tools. Symbiotic is highly modular and most of its components are self-standing programs or LLVM passes that have their own repositories at https://github.com/staticafi.

Getting started

Downloading Symbiotic

Tarballs with Symbiotic distribution can be downloaded from https://github.com/staticafi/symbiotic/releases. The latest release is the fixed version of Symbiotic archive that competed in SV-COMP 21. Alternatively, you can download archives used in SV-COMP 2021 (compiled on Ubuntu 20) or SV-COMP 2020 (compiled on Ubuntu 18).

After unpacking, Symbiotic should be ready to go.

Docker image

WARNING: is not up-to-date.

You can use also the docker image, but we do not keep them up to date:

docker pull mchalupa/symbiotic
docker run -ti mchalupa/symbiotic

Building Symbiotic from Sources

First of all you must clone the repository:

$ git clone https://github.com/staticafi/symbiotic

Run build.sh or system-build.sh script to compile Symbiotic:

$ cd symbiotic
$ ./build.sh -j2

The difference betwee build.sh and system-build.sh is that system-build.sh will try to build only the components of Symbiotic, using the system's packages. build.sh, on the other hand, tries to build also the most of the missing dependencies, including LLVM, z3, etc.

The scripts should complain about missing dependencies if any. You can try using scripts/install-system-dependencies.sh script to install the main dependencies (or at least check the names of packages). If the build script continues to complain, you must install the dependencies manually.

Possible options for the build.sh script include:

  • build-type=TYPE (TYPE one of Release, Debug)
  • llvm-version=VERSION (the default VERSION is 10.0.1, other versions are rather experimental)
  • with-llvm=, with-llvm-src=, with-llvm-dir= This set of options orders the script to use already built external LLVM (the build script will build LLVM otherwise if it has not been built already in this folder)
  • no-llvm Do not try building LLVM

There are many other options, but they are not properly documented (check the script). Actually, the whole build script should be rather a guidance of what is needed and how to build the components, but is not guaranteed to work on any system.

As you can see from the example, you can pass also arguments for make, e.g. -j2, to the build script. If you need to specify paths to header files or libraries, you can do it by passing CFLAGS, CPPFLAGS, and/or LDFLAGS environment variables either by exporting them beforehand, or by passing them on the command line similarly to make options (e.g. ./build.sh CFLAGS='-g')

If everything goes well, Symbiotic components are built and should be usable right from the build directories (see the next section for more details). Also, the components are installed to the install/ directory that can be packed or copied wherever you need (you can use ./build.sh archive to create a .zip file or full-archive to create .zip file including system libraries like libc with the build script). The install/ directory is under git control, so you can see the differences between versions or manually create an archive using git archive command.

When building on mac, you may need to build LLVM with shared libraries (modify the build script) or use with-llvm-* switch with your LLVM build.

Running Symbiotic

You can run Symbiotic directly from the root directory:

scripts/symbiotic <OPTIONS> file.c

If you run symbiotic from the scripts/ directory, it uses the components directly from the build directories, any changes to the components should take effect in this mode.

Alternatively, you can run Symbiotic also from the install/ directory:

$ install/bin/symbiotic <OPTIONS> file.c

In this mode, Symbiotic uses the components from the install/ directory.

Troubleshooting

In the case that something went wrong, try running Symbiotic with --debug=all switch. When the source code does not contain everything to compile (i.e. it includes some headers), you can use CFLAGS and CPPFLAGS environment variables to pass additional options to the compiler (clang). Either export them before running Symbiotic, or on one line:

CPPFLAGS='-I /lib/gcc/include' scripts/symbiotic file.c

You can also use --cppflags switch that works exactly the same as environment variables. If the program is split into more files, you can give Symbiotic all the files. At least one of them must contain the main function.

scripts/symbiotic main.c additional_definitions.c lib.c

Use --help switch to see all available options.

Example

Let's see how you can use Symbiotic to find an error in the following program test1.c:

#include <assert.h>
#define N 10

extern int __VERIFIER_nondet_int(void);

int main( ) {
  int a[N];
  for (int i = 0; i < N; ++i) {
	  a[i] = __VERIFIER_nondet_int();
  }

  int swapped = 1;
  while (swapped) {
    swapped = 0;
    for (int i = 1; i < N; ++i) {
      if ( a[i - 1] < a[i] ) {
        int t = a[i];
        a[i] = a[i - 1];
        a[i-1] = t;
        swapped = 1;
      }
    }
  }

  for (int x = 0 ; x < N ; x++ ) {
    for (int y = x+1 ; y < N ; y++ ) {
      assert(a[x] <= a[y]);
    }
  }
  return 0;
}

Running scripts/symbiotic --exit-on-error test1.c should produce an output similar to the following. The --exit-on-error option ensures that we stop after the first error is found, otherwise the computation would run for much longer.

7.0.0-dev-llvm-9.0.1-symbiotic:5a52b0ca-dg:e89761ff-sbt-slicer:fff6245c-sbt-instrumentation:2f9be629-klee:e643b135
INFO: Optimizations time: 0.028319835662841797
INFO: Starting slicing
INFO: Total slicing time: 0.0068209171295166016
INFO: Optimizations time: 0.027271509170532227
INFO: After-slicing optimizations and transformations time: 2.288818359375e-05
INFO: Starting verification
b'KLEE: WARNING: undefined reference to function: klee_make_nondet'
b'KLEE: ERROR: /home/marek/src/symbiotic/test1.c:27: ASSERTION FAIL: a[x] <= a[y]'
b'KLEE: NOTE: now ignoring this error at this location'
INFO: Verification time: 12.27576208114624

 --- Error trace ---

Error: ASSERTION FAIL: a[x] <= a[y]
File: /home/marek/src/symbiotic/test1.c
Line: 27
assembly.ll line: 172
Stack:
	#000000172 in main () at /home/marek/src/symbiotic/test1.c:27

 --- Sequence of non-deterministic values [function:file:line:col] ---

__VERIFIER_nondet_int:test1.c:9:11 := len 4 bytes, [4 times 0x0] (i32: 0)
__VERIFIER_nondet_int:test1.c:9:11 := len 4 bytes, [3 times 0x0|0x80] (i32: -2147483648)
__VERIFIER_nondet_int:test1.c:9:11 := len 4 bytes, [3 times 0x0|0x80] (i32: -2147483648)
__VERIFIER_nondet_int:test1.c:9:11 := len 4 bytes, [3 times 0x0|0x80] (i32: -2147483648)
__VERIFIER_nondet_int:test1.c:9:11 := len 4 bytes, [3 times 0x0|0x80] (i32: -2147483648)
__VERIFIER_nondet_int:test1.c:9:11 := len 4 bytes, [3 times 0x0|0x80] (i32: -2147483648)
__VERIFIER_nondet_int:test1.c:9:11 := len 4 bytes, [3 times 0x0|0x80] (i32: -2147483648)
__VERIFIER_nondet_int:test1.c:9:11 := len 4 bytes, [3 times 0x0|0x80] (i32: -2147483648)
__VERIFIER_nondet_int:test1.c:9:11 := len 4 bytes, [3 times 0x0|0x80] (i32: -2147483648)
__VERIFIER_nondet_int:test1.c:9:11 := len 4 bytes, [3 times 0x0|0x80] (i32: -2147483648)

 --- ----------- ---
Error found.
INFO: Total time elapsed: 12.659614086151123

In some cases, Symbiotic is able to generate also an executable witness. You must use --executable-witness switch. Then, you should see a message like this in the output:

Generating executable witness to : /home/marek/src/symbiotic/witness.exe

If you run the binary, it follows the found error path:

$ ./witness.exe
witness.exe: /home/marek/src/symbiotic/tests/test1-false-unreach-call.c:27: int main(): Assertion `a[x] <= a[y]' failed.
[1]    18810 abort (core dumped)  ./witness.exe

The binary is compiled with the -g option, so you can load it into a debugger.

In the default mode, Symbiotic looks for assertion violations. If you want to look for e.g., errors in memory manipulations, use --prp switch. For example, say you have a file test2.c with this contents:

extern void __VERIFIER_error() __attribute__ ((__noreturn__));

struct list {
 int n;
 struct list *next;
};

int i = 1;

struct list* append(struct list *l, int n)
{
 struct list *new_el;

 new_el = malloc(8);
 new_el->n = n;
 new_el->next = l;

 return new_el;
}

int main(void)
{
 struct list *l,m;
 l = &m;
 l->next = 0;
 l->n = 0;

 l = append(l, 1);
 l = append(l, 2);

 if (l->next->next->n == 0)
   __VERIFIER_error();
 return 0;
}

If you run scripts/symbiotic --prp=memsafety test2.c, you should get an output similar to the following:

7.0.0-dev-llvm-9.0.1-symbiotic:5a52b0ca-dg:e89761ff-sbt-slicer:fff6245c-sbt-instrumentation:2f9be629-klee:e643b135
INFO: Starting instrumentation
wrapper: `which slllvm` failed with error code 1

INFO: Instrumentation time: 0.04639697074890137
INFO: Optimizations time: 0.02850055694580078
INFO: Starting slicing
INFO: Total slicing time: 0.00681614875793457
INFO: Optimizations time: 0.02629995346069336
INFO: After-slicing optimizations and transformations time: 2.7894973754882812e-05
INFO: Starting verification
b'KLEE: WARNING ONCE: Alignment of memory from call "malloc" is not modelled. Using alignment of 8.'
b'KLEE: ERROR: /home/marek/src/symbiotic/test2_false-valid-deref.c:16: memory error: out of bound pointer'
b'KLEE: NOTE: now ignoring this error at this location'
INFO: Verification time: 0.029797792434692383

 --- Error trace ---

Error: memory error: out of bound pointer
File: /home/marek/src/symbiotic/test2_false-valid-deref.c
Line: 16
assembly.ll line: 31
Stack:
	#000000031 in append (=94514011128176, =1) at /home/marek/src/symbiotic/test2_false-valid-deref.c:16
	#100000064 in main () at /home/marek/src/symbiotic/test2_false-valid-deref.c:28
Info:
	address: 26:94514011726424
	pointing to: object at 94514011726416 of size 8
		MO15[8] allocated at append():  %7 = call i8* @malloc(i64 8), !dbg !23

 --- Sequence of non-deterministic values [function:file:line:col] ---


 --- ----------- ---
Error found.
INFO: Total time elapsed: 0.6174993515014648

If you would omit the --prp=memsafety switch, you would see that Symbiotic reports no error. However, the output mentions some memory errors. This means that Symbiotic hit an error but different one that it should look for. Note that the difference is not only in parsing the output. Since Symbiotic slices the program w.r.t error-sites, it may remove some errors that are not related to the particular error that we looked for. So the fact that Symbiotic found an invalid dereference even though it did not look for that is just a lucky coincidence and may not be true for other programs.

Verification backends

By default, Symbiotic runs KLEE to analyze the program. However, it can use many other tools for the analysis. Here is the list of supported tools (some of them are integrated rather experimentally and may not work seamlessly):

tool switch
KLEE --target=klee
CPAchecker --target=cpachecker
DIVINE --target=divine
CBMC --target=cbmc
SMACK --target=smack
SeaHorn --target=seahorn
Nidhugg --target=nidhugg
IKOS --target=ikos
UAutomizer --target=ultimate

CC mode

Symbiotic can also just output the transformed bitcode or generate C code from the transformed bitcode. ...TBD...

Symbiotic Components

Components of Symbiotic can be found at https://github.com/staticafi with the only exception of dg library that is currently at https://github.com/mchalupa/dg. All software used in Symbiotic are open-source projects and are licensed under various open-source licenses (mostly MIT license, and University of Illinois Open Source license)

Contact

For more information send an e-mail to [email protected].

symbiotic's People

Contributors

acalabek avatar kdudka avatar lembergerth avatar lzaoral avatar mchalupa avatar michalhe avatar moroxus avatar msimacek avatar strejcek avatar tomsik68 avatar trtikm avatar xvitovs1 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

symbiotic's Issues

metabug: incorrect answers

This bug is for gathering information about Symbiotic's incorrect answers

  • heap-manipulation/dll_of_dll_true-unreach-call.i #27
  • loop-invgen/heapsort_true-unreach-call.i #28

  • bug in floats #16

Fix initializing globals

Undefined globals should be made symbolic, why isn't it working?

KLEE: ERROR: unable to load symbol(xen_xenbus_fops) while initializing globals.
KLEE: ERROR: unable to load symbol(BATERY_GAIN) while initializing globals.

Reuse 32-bit lib.o

We have lib/ and lib32/ directories now, so we can create lib/lib.o lib32/lib.o and reuse it instead of re-compiling it for each benchmark again

bug with optimizations

This code should result in TRUE, but is FALSE with optimizations 'before' (without opts or without slicing it is fine)

#include <assert.h>

int a = 0;
int *p = ((void *) 0); 

void set(void)
{
        if (!a)
                p = &a; 
        else
                p = ((void *) 0); 
}

int main(void)
{
        int b = 2;
        if (a > b) {
                set();
                *p = 3;
        } else {
                set();
                *p = 4;
        }

        assert(a == 4); 
        return 0;
}

remove invalid aborts

if somebody checks for returned value from malloc we say unknown just for that (because we hit abort failure)

if ((mem = malloc(...)) == NULL)
   abort();

we can replace abort with klee_assume()

merge svc15 to symbiotic

There are just few files and the scripts are going to be rewritten into python later, so svc15 will be almost empty

strdup can never fail

strdup can never fail - change libc such that there will be a macro 'MALLOC_NEVER_FAILS' and this macro will cause conditional compilation of lib.c
This way we'll have just one version of __VERIFIER_malloc() function

floats bugs [cz]

  • floats-cbmc-regression/float14_true-unreach-call.i prepare odstrani __isinff, bez prepare da klee spravny vysledek
  • floats-cbmc-regression/float4_true-unreach-call.i klee vola __isnan a __isinf s argumentem 0 (konkretizoval?)
  • floats-cbmc-regression/float4_true-unreach-call.i prepare odstrani volani __isinf - klee bez prepare spadne na nepodporovane instrukci
  • floats-cbmc-regression/float-rounding1_true-unreach-call.i prepare odstrani fesetround, ale klee da spatny vysledek jak s prepare tak bez prepare

catch broken modules

if slicer breaks the module, say error or unknown (when slicer required) or use the original (when slicer is not required)

RESULT: DBG: = ptrtoint to label
RESULT: DBG: br i1 %26, label , label %30
RESULT: DBG: Broken module found, verification continues.
RESULT: DBG: Instruction does not dominate all uses!

prepare failed

These two benchmarks has 'Prepare phase failed'

ntdrivers/cdaudio_true-unreach-call.i.cil.c
ntdrivers/cdaudio_false-unreach-call.i.cil.c

O2 optimizations break this code

  1 int *getelem(int array[10], int idx)
  2 {
  3         __VERIFIER_assert(idx >= 0 && idx < 10);
  4         return &array[idx];
  5 }
  6 
  7 int main(void)
  8 {
  9         int array[10] = { 0 };
 10 
 11         for (int i = 0; i < 1000; ++i) {
 12                 int *p = getelem(array, rand() % 11);
 13                 *p = 1;
 14         }
 15 
 16         doit(array);
 17         return 0;
 18 }

with --optimizations=before-O2,after we get TRUE, without it we get FALSE (correct)

klee's bug (investigate and report to klee)

klee reports TRUE for this code (once we remove the loop, it reports FALSE). It reports TRUE without any optimizations, so there should be no problem with n being unspecified (with opts it gets correct)

#include <assert.h>

int main()
{
        int a;
        int n;

        if( n < 0 ) 
                return 0;

        for(; n < 100; n++) {
        }

        ++n;
        a = 2;
        assert(a == 3); 

        return 0;
}

TODO

  • add verifier missing types (mainly __VERIFIER_nondet_bool)
  • slicer sigsegv removing undef - fix the undef!
  • when slicer do not find slicing criterion, say TRUE
  • add klee_assume() to all malloc + calloc calls (that the pointer is not null)
  • make EGENERAL bound to KLEE: ERROR: not to 'now ignoring error on this loca'
  • fix truncateToNBits bug in klee

klee does not distinguish between out of memory and overlap

file as a bug for klee

  1 #include <assert.h>
  2 #define N 1000000000
  3 
  4 int main(void)
  5 {
  6   int a[N];
  7   int max = 0;
  8   int i = 0;
  9   while (i < N) {
 10     if (a[i] > max)
 11       max = a[i];
 12       ++i;
 13   }
 14 
 15   int x;
 16   for ( x = 0 ; x < N ; x++ )
 17     assert(a[x] <= max);
 18 
 19   return 0;
 20 }

This program makes klee to write out out of bound pointer, while it is perfectly ok. It is due to states overlap (Executor.cpp:3236). Klee does not distinguish between out of bound and overlap -> file it as a bug for klee

signals handling?

how is it with handling POSIX signals? ... it is more or less like threaded application, so nothing for symbiotic now...

create new symbiotic build script

rename the old to blah-blah-external or something like that and make the new use submodules as it will be easier to fetch and compile them

symbiotic: check klee's return code

recently I discovered, that something like this is evaluated to TRUE:

RESULT: DBG: terminate called after throwing an instance of 'std::bad_alloc'
RESULT: DBG: what(): std::bad_alloc
RESULT: DBG: 0 klee 0x0000000000e5b945 llvm::sys::PrintStackTrace(_IO_FILE*) + 37
RESULT: DBG: 1 klee 0x0000000000e5bd93
RESULT: DBG: 2 libpthread.so.0 0x00007f3e2c7d0340
RESULT: DBG: 3 libc.so.6 0x00007f3e2b76bcc9 gsignal + 57
RESULT: DBG: 4 libc.so.6 0x00007f3e2b76f0d8 abort + 328
RESULT: DBG: 5 libstdc++.so.6 0x00007f3e2c0a678d __gnu_cxx::__verbose_terminate_handler() + 349
RESULT: DBG: 6 libstdc++.so.6 0x00007f3e2c0a47f6
RESULT: DBG: 7 libstdc++.so.6 0x00007f3e2c0a4841
RESULT: DBG: 8 libstdc++.so.6 0x00007f3e2c0a4a58
RESULT: DBG: 9 libstdc++.so.6 0x00007f3e2c0a4f5c
RESULT: DBG: 10 libstdc++.so.6 0x00007f3e2c0a4fb9 operator new[](unsigned long) + 9
RESULT: DBG: 11 klee 0x00000000005f05b7 klee::PathLocation::PathLocation(std::basic_ifstream >&) + 71
RESULT: DBG: 12 klee 0x00000000005f1181 klee::TreeStreamWriter::readStream(unsigned int, std::vector >&) + 1409
RESULT: DBG: 13 klee 0x000000000054e181
RESULT: DBG: 14 klee 0x0000000000555c56 klee::Executor::terminateStateOnExit(klee::ExecutionState&) + 38
RESULT: DBG: 15 klee 0x0000000000561fc6 klee::Executor::executeInstruction(klee::ExecutionState&, klee::KInstruction*) + 13654
RESULT: DBG: 16 klee 0x0000000000563966 klee::Executor::run(klee::ExecutionState&) + 1654
RESULT: DBG: 17 klee 0x0000000000564211 klee::Executor::runFunctionAsMain(llvm::Function*, int, char**, char**) + 1681
RESULT: DBG: 18 klee 0x0000000000537c51 main + 7921
RESULT: DBG: 19 libc.so.6 0x00007f3e2b756ec5 __libc_start_main + 245
RESULT: DBG: 20 klee 0x000000000054b9e1

instead of only matching patterns in klee's output, check even for the return code and say error when somthing like this happens

lib.c correctness?

there are some hard-coded data types, like:
typedef unsigned int size_t

this could break something, fix it! (conditional compilation)

symbiotic: try slicing twice

slicing the code that has been already sliced does not remove anything (that's good), but if we optimize the code after slicing with opt and stuff like constant propagation and such, then the code can be sliced again with a positive number of nodes removed

try if that's worth it at all

add regression tests

add tests to symbiotic project that will test regressions, like:

__VERIFIER_assert(isdigit('1'))

and similar (this code was not working before)

lib.c: missing functions

strncmp
strcmp (??)
strchr (??)
strstr

mutexes && kfree (will be done by new instrumentation)

runme: remove wrong while

when parsing klee we do while read LINE, but then we dont use the line. I'm surprised it works... Just remove it and let the input go to grep

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.