GithubHelp home page GithubHelp logo

boolector / boolector Goto Github PK

View Code? Open in Web Editor NEW
319.0 14.0 63.0 20.61 MB

A Satisfiability Modulo Theories (SMT) solver for the theories of fixed-size bit-vectors, arrays and uninterpreted functions.

Home Page: http://boolector.github.io

License: Other

Shell 0.32% Python 0.68% Makefile 0.01% C++ 5.17% C 22.22% SMT 69.69% CMake 0.90% Dockerfile 0.03% Cython 0.99%

boolector's Introduction

License: MIT Build Status

Boolector

Boolector is a Satisfiability Modulo Theories (SMT) solver for the theories of fixed-size bit-vectors, arrays and uninterpreted functions. It supports the SMT-LIB logics BV, QF_ABV, QF_AUFBV, QF_BV and QF_UFBV. Boolector provides a rich C and Python API and supports incremental solving, both with the SMT-LIB commands push and pop, and as solving under assumptions. The documentation of its API can be found here.

Website

More information about Boolector is available at: https://boolector.github.io

Download

The latest version of Boolector is available on GitHub: https://github.com/boolector/boolector

Installation

On macOS (or Linux) via Homebrew

brew install boolector

Note: this installation doesn't come with Python bindings and it uses Lingeling as backend.

Prerequisites

To build Boolector from source you need:

  • cmake >= 3.3
  • gcc/clang
  • g++/clang++

To build the python module pyboolector you further need:

  • Cython >= 0.22

Build

Boolector can be built with support for the SAT solvers CaDiCaL, CryptoMiniSat, Lingeling, MiniSAT, and PicoSAT. To build and setup these solvers you can use the scripts setup-{cadical,cms,lingeling,minisat,picosat}.sh in the contrib directory. Optionally, you can place any of these solvers in a directory on the same level as the Boolector source directory or provide a path to configure.sh. You can build Boolector with support for multiple SAT solvers. Note that using MiniSAT will force libboolector.a to depend not only on libz.so but also on libstdc++.so. Thus, if you want to link libboolector.a with MiniSAT backend against your own programs, you need to use -lz -lstdc++ as linking options.

Boolector has one other external dependency, the BTOR2 format tools package. As with the SAT solvers, you can either use the provided script setup-btor2tools.sh in contrib or clone the BTOR2Tools repository into directory btor2tools on the same level as the Boolector repository or provide a path to configure.sh.

Linux and Unix-like OS

Assume that we build Boolector with support for Lingeling:

# Download and build Boolector
git clone https://github.com/boolector/boolector
cd boolector

# Download and build Lingeling
./contrib/setup-lingeling.sh

# Download and build BTOR2Tools
./contrib/setup-btor2tools.sh

# Build Boolector
./configure.sh && cd build && make

All binaries (boolector, btormc, btormbt, btoruntrace) are generated into directory boolector/build/bin, and all libraries (libboolector.a, libboolector.so) are generated into directory boolector/build/lib.

For more build configuration options of Boolector, see configure.sh -h.

To build Boolector with Python bindings you need to install Cython, and btor2tools and SAT solvers must be compiled with flag -fPIC (see build instructions of these tools for more details on how to build as shared library). The provided setup-*.sh scripts automatically compile all dependencies with -fPIC. Then, from Boolector's root directory configure and build Boolector as follows:

./configure.sh --python
cd build
make

To build the API documentation of Boolector, it is required to install Sphinx (>= version 1.2). Then build Boolector and issue:

cd doc
make html

The documentation is then generated into doc/_build/html. Make sure to build Boolector with Python bindings, else the documentation of its Python API will not be included.

Linking against Boolector in CMake projects

Boolector's build system provides a CMake package configuration, which can be used by the find_package() command to provide information about Boolector's include directories, libraries and it's dependencies.

After installing Boolector you can issue the following commands in your CMake project to link against Boolector.

find_package(Boolector)
target_link_libraries(<your_target> Boolector::boolector)

Windows

For building and usage of Boolector on Windows, please see COMPILING_WINDOWS.md.

Usage

For a list of command line options, refer to boolector -h.

For examples and instructions on how to use Boolector's C API, refer to examples/api/c and the API documentation. To build all examples in examples/api/c issue:

cd build
make examples

For examples and instructions on how to use Boolector's Python API, refer to examples/api/python/api_usage_examples.py and the API documentation.
To run api_usage_examples.py, from Boolector's root directory issue:

PYTHONPATH="build/lib" python examples/api/python/api_usage_examples.py

Contributing

Boolector is distributed under the MIT license (see COPYING file). By submitting a contribution you automatically accept the conditions described in COPYING. Additionally, we ask you to certify that you have the right to submit such contributions. To manage this process we use a mechanism known as Developer Certificate of Origin, which can be acknowledged by signing-off your commits with git commit -s. We require all pull requests to be squashed into a single commit and signed-off.

Developer Certificate of Origin
Version 1.1

Copyright (C) 2004, 2006 The Linux Foundation and its contributors.
1 Letterman Drive
Suite D4700
San Francisco, CA, 94129

Everyone is permitted to copy and distribute verbatim copies of this
license document, but changing it is not allowed.


Developer's Certificate of Origin 1.1

By making a contribution to this project, I certify that:

(a) The contribution was created in whole or in part by me and I
    have the right to submit it under the open source license
    indicated in the file; or

(b) The contribution is based upon previous work that, to the best
    of my knowledge, is covered under an appropriate open source
    license and I have the right under that license to submit that
    work with modifications, whether created in whole or in part
    by me, under the same open source license (unless I am
    permitted to submit under a different license), as indicated
    in the file; or

(c) The contribution was provided directly to me by some other
    person who certified (a), (b) or (c) and I have not modified
    it.

(d) I understand and agree that this project and the contribution
    are public and that a record of the contribution (including all
    personal information I submit with it, including my sign-off) is
    maintained indefinitely and may be redistributed consistent with
    this project or the open source license(s) involved.

boolector's People

Contributors

aniemetz avatar arminbiere avatar aytey avatar barracuda156 avatar cr1901 avatar cyanokobalamyne avatar femigr avatar imphil avatar mballance avatar mpreiner avatar nakengelhardt avatar q3k avatar rexyuan avatar ryanglscott avatar xiretza 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  avatar  avatar

boolector's Issues

generate model for all expressions BTOR_OPT_MODEL_GEN not working

In betortypes.h we can read:

* **BTOR_OPT_MODEL_GEN**
      | Enable (``value``: 1 or 2) or disable (``value``: 0) generation of a
        model for satisfiable instances.
      | There are two modes for model generation:
      * generate model for asserted expressions only (``value``: 1)
      * generate model for all expressions (``value``: 2)

But even with the value 2 the boolector_print_model function only gives model for declare-fun variables but not for define-fun variables.

Is it a bug?

Thank you.

PS: My define-fun variables come from an SMTLIB file parsed with boolector_parse_smt2.

To reproduce, parse this file:

(set-logic QF_ABV)
(declare-fun memory0 () (Array (_ BitVec 32) (_ BitVec 8)))
(declare-fun eax0 () (_ BitVec 32))
(declare-fun ebx0 () (_ BitVec 32))
(declare-fun ecx0 () (_ BitVec 32))
(declare-fun edx0 () (_ BitVec 32))
(declare-fun esi0 () (_ BitVec 32))
(declare-fun edi0 () (_ BitVec 32))
(declare-fun ebp0 () (_ BitVec 32))
(declare-fun esp0 () (_ BitVec 32))
(assert (= esp0 (_ bv65536 32)))
(assert (= ebp0 (_ bv65536 32)))
(define-fun res321 () (_ BitVec 32) (_ bv0 32))
(define-fun OF1 () (_ BitVec 1) (_ bv0 1))
(define-fun SF1 () (_ BitVec 1) (ite (bvslt res321 (_ bv0 32)) (_ bv1 1) (_ bv0 1)))
(define-fun ZF1 () (_ BitVec 1) (bvcomp res321 (_ bv0 32)))
(define-fun AF1 () (_ BitVec 1) (_ bv0 1))
(define-fun PF1 () (_ BitVec 1) (bvnot (bvxor (bvxor (bvxor (bvxor (bvxor (bvxor (bvxor ((_ extract 0 0) res321) ((_ extract 1 1) res321)) ((_ extract 2 2) res321)) ((_ extract 3 3) res321)) ((_ extract 4 4) res321)) ((_ extract 5 5) res321)) ((_ extract 6 6) res321)) ((_ extract 7 7) res321))))
(define-fun CF1 () (_ BitVec 1) (_ bv0 1))
(define-fun eax1 () (_ BitVec 32) res321)
(define-fun res322 () (_ BitVec 32) eax1)
(define-fun OF2 () (_ BitVec 1) (_ bv0 1))
(define-fun SF2 () (_ BitVec 1) (ite (bvslt res322 (_ bv0 32)) (_ bv1 1) (_ bv0 1)))
(define-fun PF2 () (_ BitVec 1) (bvnot (bvxor (bvxor (bvxor (bvxor (bvxor (bvxor (bvxor ((_ extract 0 0) res322) ((_ extract 1 1) res322)) ((_ extract 2 2) res322)) ((_ extract 3 3) res322)) ((_ extract 4 4) res322)) ((_ extract 5 5) res322)) ((_ extract 6 6) res322)) ((_ extract 7 7) res322))))
(define-fun ZF2 () (_ BitVec 1) (bvcomp res322 (_ bv0 32)))
(define-fun CF2 () (_ BitVec 1) (_ bv0 1))
(define-fun cond_expr1 () (_ BitVec 1) ZF2)

and call boolector_print_model .

I only obtain:

(model
  (define-fun eax0 () (_ BitVec 32) (_ bv0 32))
  (define-fun ebx0 () (_ BitVec 32) (_ bv0 32))
  (define-fun ecx0 () (_ BitVec 32) (_ bv0 32))
  (define-fun edx0 () (_ BitVec 32) (_ bv0 32))
  (define-fun esi0 () (_ BitVec 32) (_ bv0 32))
  (define-fun edi0 () (_ BitVec 32) (_ bv0 32))
  (define-fun ebp0 () (_ BitVec 32) (_ bv65536 32))
  (define-fun esp0 () (_ BitVec 32) (_ bv65536 32))
)

But I would like also see cons_expr1, CF2, etc ...

Or even better, I would like to get model of only one variable (see #50)

Thank

Unable to build the code, undefined reference to symbol '__tls_get_addr@@GLIBC_2.3' error

While running "make" command, I'm getting the following error. Please help me to build boolector in my system. I'm using Ubuntu 19.10. It has gcc and g++ both of version 9.

[ 53%] Linking CXX executable ../bin/btormc
/usr/bin/ld: /usr/lib/gcc/x86_64-linux-gnu/9/libstdc++.a(eh_globals.o): undefined reference to symbol '__tls_get_addr@@GLIBC_2.3'
/usr/bin/ld: /lib/x86_64-linux-gnu/ld-linux-x86-64.so.2: error adding symbols: DSO missing from command line
collect2: error: ld returned 1 exit status

Error with Array sort as input to function

Hi,

When trying to use an array as an input to a function I get the following

(set-logic QF_AUFBV)

(define-fun Store-2 
  ((m (Array (_ BitVec 32) (_ BitVec 8))) (a (_ BitVec 32)))
  (Array (_ BitVec 32) (_ BitVec 8))
  (store m a #x08))

(check-sat)
(get-model)
$ boolector no_overlap.smt2
boolector: no_overlap.smt2:4:8: expected '_' at 'Array'

I can't see anything in the SMT-LIB2 standard that would forbid this and CVC4 seems not to mind.

$ cvc4 no_overlap.smt2 
sat
(error "Cannot get model when produce-models options is off.")

Is this a design decision in boolector or am I doing something wrong?

Thanks,
Sean

(or) fails with single argument

I'm generating smt2 formulas from machine code and in some cases a single-argument (or) comes up:

% echo '(assert (or true))' | boolector
boolector: <stdin>:1:10: argument to 'or' missing

It's just a minor issue that I can work around easily, but it would be nice if one didn't have to special-case this.

Regression with SMT2 `distinct`

This query:

(declare-fun c0 () (_ BitVec 4))
(declare-fun c1 () (_ BitVec 4))
(declare-fun c2 () (_ BitVec 4))
(define-fun e3 () Bool (distinct c0 c1 c2))
(define-fun e11 () Bool (and (not (= c0 c1)) (not (= c0 c2)) (not (= c1 c2))))
(assert e3)
(assert (not e11))
(check-sat)

returns SAT in the 3.0.0 release, but should be UNSAT (e3 and e11 are equivalent, and e11 is asserted negatively). With model generation on, the resulting model obviously violates distinct:

(model
  (define-fun c0 () (_ BitVec 4) #b1000)
  (define-fun c1 () (_ BitVec 4) #b0000)
  (define-fun c2 () (_ BitVec 4) #b0000)
)

The same query returns UNSAT in 2.4.1 and with Z3. The version with only two variables returns UNSAT as expected.

Docker ?

Hi,
Could you please propose a Docker for Boolector? or at least a dockerfile ?

[Bug] `(push 0)`/`(pop 0)` raises an error message

Hi there,

SMT-LIB v2 explicitly defines (push 0) and (pop 0) as operations without effect (cf. p. 59 in version 2.6 of the language standard), but the current version of Boolector prints an error message instead:

(set-logic QF_UFBV)
(push 0)
(check-sat)
[boolector] boolector_push: context level must be greater than 0

The following patch seems to fix the problem: boolector-3.0.0_push_pop_0.patch.txt

Release boolector as a PyPi package

Hello,
I've been using Boolector via the C API, and have recently started using the Python interface. I'd like to have Boolector available via the PyPi package repository (pypi.org), and it doesn't appear to be directly available at the moment. I'm happy to volunteer to put together such a package, but wanted to check if there are concerns about doing so.

Thanks,
Matthew

Possibly incorrect result for a quantified formula

I have a quantified formula (in the attachment formula.zip) for which Boolector 3.0.1-pre returns sat. I think that this result might be incorrect, as Z3 (4.8.5), CVC4 (1.6), and Q3B (1.0) all return unsat.

I am using the following versions of Boolector and Lingeling:

[btor>main] Boolector Version 3.0.1-pre master-319e4e969523238bce24061b706629cc9fa58cb4
[btor>main]  -std=gnu99 -W -Wall -Wextra -Wredundant-decls -O3
[btor>main] released 2019-03-13T14:16:35
[btor>main] compiled 2019-03-13T14:16:35
[btor>main] GNU 8.2.1

[lingeling] Lingeling
[lingeling] 
[lingeling] Version bcj 78ebb8672540bde0a335aea946bbf32515157d5a

If it helps with the debugging, the formula is a result of applying some rewriting rules to the formula 2017-Preiner-psyco/090.smt2 from BV category of SMT-LIB.

Thank you for looking into it.

support for >2 arity bxnor

I think this should parse because bvxnor is left-associative:

(assert (= (bvxnor #b0 #b0 #b0) (bvnot (bvxor #b0 #b0 #b0))))

That said, bvxnor is hardly used.

[Bug] Wrong result for `(= false false true)`

Hi there,

the current version of Boolector reports sat for the following SMT-LIB v2 script, but the correct result is unsat (cf. p. 36 in version 2.6 of the language standard):

(set-logic QF_UFBV)
(assert (= false false true))
(check-sat)

It seems that Boolector handles = as left-assoc, even though it is defined to be chainable. Both z3 and CVC4 report the correct result.

SMT2: Calling `assert` between `check-sat` and `get-value` causes crash instead of error

The following SMT2 file causes a crash:

(set-option :produce-models true )
(set-logic QF_BV )

(declare-fun dummy () (_ BitVec 8))
(assert (not (= dummy #x42)))
(check-sat)
(assert (= dummy #x00))
(get-value (dummy))

On release builds this derefs a null pointer, on debug builds this causes an assertion failure.

Backtrace on debug build:

#0  raise (sig=6) at ../sysdeps/unix/sysv/linux/raise.c:50
#1  0x0000000000401add in abort ()
#2  0x00000000004019b7 in __assert_fail_base.cold.0 ()
#3  0x00000000006e8132 in __assert_fail ()
#4  0x000000000048439c in btor_model_get_bv_aux (btor=0x895840, bv_model=0x0, fun_model=0x0, exp=0x8ac160) at /shared/dev/boolector/src/btormodel.c:508
#5  0x00000000004845aa in btor_model_get_bv (btor=0x895840, exp=0x8ac160) at /shared/dev/boolector/src/btormodel.c:569
#6  0x000000000049defd in print_bv_value_smt2 (btor=0x895840, node=0x8ac160, symbol_str=0x8bfc60 "in1a", base=1, file=0x8789e0 <_IO_2_1_stdout_>)
    at /shared/dev/boolector/src/btorprintmodel.c:417
#7  0x000000000049e4aa in btor_print_value_smt2 (btor=0x895840, exp=0x8ac160, symbol_str=0x8bfc60 "in1a", file=0x8789e0 <_IO_2_1_stdout_>)
    at /shared/dev/boolector/src/btorprintmodel.c:512
#8  0x000000000040c30c in boolector_print_value_smt2 (btor=0x895840, node=0x8ac160, symbol_str=0x8bfc60 "in1a", file=0x8789e0 <_IO_2_1_stdout_>)
    at /shared/dev/boolector/src/boolector.c:310
#9  0x0000000000573b8f in read_command_smt2 (parser=0x89bec0) at /shared/dev/boolector/src/parser/btorsmt2.c:4771
#10 0x00000000005741b4 in parse_smt2_parser (parser=0x89bec0, prefix=0x7fffffffe740, infile=0x89bc50, infile_name=0x7fffffffed83 "/tmp/manual.smt2", 
    outfile=0x8789e0 <_IO_2_1_stdout_>, res=0x7fffffffe6b0) at /shared/dev/boolector/src/parser/btorsmt2.c:4862
#11 0x000000000049abaa in parse_aux (btor=0x895840, infile=0x89bc50, prefix=0x7fffffffe740, infile_name=0x7fffffffed83 "/tmp/manual.smt2", 
    outfile=0x8789e0 <_IO_2_1_stdout_>, parser_api=0x877310 <parsesmt2_parser_api>, error_msg=0x7fffffffe918, status=0x7fffffffe924, 
    msg=0x89be80 "parsing '/tmp/manual.smt2'") at /shared/dev/boolector/src/btorparse.c:68
#12 0x000000000049bf3e in btor_parse (btor=0x895840, infile=0x89bc50, infile_name=0x7fffffffed83 "/tmp/manual.smt2", outfile=0x8789e0 <_IO_2_1_stdout_>, 
    error_msg=0x7fffffffe918, status=0x7fffffffe924) at /shared/dev/boolector/src/btorparse.c:230
#13 0x000000000043d495 in boolector_parse (btor=0x895840, infile=0x89bc50, infile_name=0x7fffffffed83 "/tmp/manual.smt2", outfile=0x8789e0 <_IO_2_1_stdout_>, 
    error_msg=0x7fffffffe918, status=0x7fffffffe924) at /shared/dev/boolector/src/boolector.c:4612
#14 0x000000000040a1d8 in boolector_main (argc=2, argv=0x7fffffffeb18) at /shared/dev/boolector/src/btormain.c:1462
#15 0x00000000004036bd in main (argc=2, argv=0x7fffffffeb18) at /shared/dev/boolector/src/boolectormain.c:17

Test-suite failure in random1btor2

Hello,

When running the test-suite test-case of random1btor2, I see the following failure:

$ ./bin/boolector src/tests/log/random1.btor2
boolector: line 21: id exceeds maximum

Is this a known/expected outcome?

All other tests, including random1.btor, pass. I single out random1.btor because the header of random1.btor2 states:

This is the BTOR2 version of src/tests/log/random1.btor.

which suggests there is something different between the BTOR1 and BTOR2 instances.

Any help would be greatly appreciated.

Thank you,

Andrew

SMT parser stuck in rewriting

Solving this large SMT2 file (generated by Rosette, which we recently added Boolector support to) seems to get stuck in parsing -- I've left it running for over 45 minutes. In particular, with verbosity turned up:

boolector -v -v -v -v -m --smt2-model mc-save-guess-oneshot-1.smt2

the last lines we see before it hangs are:

[btor>smt2] defined 'e32888' as bit-vector at line 32890 column 13
[btorsmt2] line 32890    column 28   token 00000002 (
[btorsmt2] line 32890    column 29   token 00000408 =
[btorsmt2] line 32890    column 31   token 00000004 e0
[btorsmt2] line 32890    column 34   token 00000004 e32887
[btorsmt2] line 32890    column 40   token 00000003 )

Line 32890 is:

(define-fun e32888 () Bool (= e0 e32887))

According to a profiler, it's getting stuck while rewriting this equality (in rewrite_eq_exp), but I don't know the code well enough to figure out whether it's getting into an infinite loop or just incredibly slow, since this is a pretty big SMT term. (though for comparison, Z3 solves this in about a second).

p.s. Thanks for the new release! We are getting some really nice results using Boolector with Rosette.

wrong get-value answer

Hi,

I have a project that needs to use SMT solvers.
My project can works with Z3, CVC4 and BOOLECTOR.

In order to know which one is the best I run my project with each solvers.

But in one case, the get-value reply of Boolector seems wrong.

Here you can find the formula file in order to reproduce the bug:

(set-logic QF_ABV)


; ------[ BOA: Entry variables declarations of BB 0_0x574 -- โˆ… (BB entry point of the formula) ]------

(declare-fun memory_entry_0_0x574-empty () (Array (_ BitVec 32) (_ BitVec 8)))
(declare-fun eax_entry_0_0x574-empty () (_ BitVec 32))
(declare-fun ebx_entry_0_0x574-empty () (_ BitVec 32))
(declare-fun ecx_entry_0_0x574-empty () (_ BitVec 32))
(declare-fun edx_entry_0_0x574-empty () (_ BitVec 32))
(declare-fun esi_entry_0_0x574-empty () (_ BitVec 32))
(declare-fun edi_entry_0_0x574-empty () (_ BitVec 32))
(declare-fun ebp_entry_0_0x574-empty () (_ BitVec 32))
(declare-fun esp_entry_0_0x574-empty () (_ BitVec 32))
(declare-fun OF_entry_0_0x574-empty () (_ BitVec 1))
(declare-fun SF_entry_0_0x574-empty () (_ BitVec 1))
(declare-fun ZF_entry_0_0x574-empty () (_ BitVec 1))
(declare-fun PF_entry_0_0x574-empty () (_ BitVec 1))
(declare-fun CF_entry_0_0x574-empty () (_ BitVec 1))
(declare-fun AF_entry_0_0x574-empty () (_ BitVec 1))
(declare-fun DF_entry_0_0x574-empty () (_ BitVec 1))

; ------[ BOA: Concrete regs at BB 0_0x574 -- โˆ… entry ]------

(assert (= ebx_entry_0_0x574-empty (_ bv1396 32)))
(assert (= ecx_entry_0_0x574-empty (_ bv1048580 32)))
(assert (= ebp_entry_0_0x574-empty (_ bv1048568 32)))
(assert (= esp_entry_0_0x574-empty (_ bv1048560 32)))
(assert (= CF_entry_0_0x574-empty (_ bv0 1)))
(assert (= ZF_entry_0_0x574-empty (_ bv0 1)))
(assert (= SF_entry_0_0x574-empty (_ bv0 1)))
(assert (= PF_entry_0_0x574-empty (_ bv1 1)))
(assert (= OF_entry_0_0x574-empty (_ bv0 1)))
(assert (= AF_entry_0_0x574-empty (_ bv0 1)))
(assert (= DF_entry_0_0x574-empty (_ bv0 1)))

; ------[ BOA: Concrete stack 32 at BB 0_0x574 -- โˆ… entry ]------

(assert (= (concat (select memory_entry_0_0x574-empty (bvadd (_ bv1048556 32) (_ bv3 32))
) (concat (select memory_entry_0_0x574-empty (bvadd (_ bv1048556 32) (_ bv2 32))
) (concat (select memory_entry_0_0x574-empty (bvadd (_ bv1048556 32) (_ bv1 32))
) (select memory_entry_0_0x574-empty (_ bv1048556 32))))) (_ bv1396 32)))
(assert (= (concat (select memory_entry_0_0x574-empty (bvadd (_ bv1048560 32) (_ bv3 32))
) (concat (select memory_entry_0_0x574-empty (bvadd (_ bv1048560 32) (_ bv2 32))
) (concat (select memory_entry_0_0x574-empty (bvadd (_ bv1048560 32) (_ bv1 32))
) (select memory_entry_0_0x574-empty (_ bv1048560 32))))) (_ bv1048580 32)))
(assert (= (concat (select memory_entry_0_0x574-empty (bvadd (_ bv1048568 32) (_ bv3 32))
) (concat (select memory_entry_0_0x574-empty (bvadd (_ bv1048568 32) (_ bv2 32))
) (concat (select memory_entry_0_0x574-empty (bvadd (_ bv1048568 32) (_ bv1 32))
) (select memory_entry_0_0x574-empty (_ bv1048568 32))))) (_ bv1048576 32)))

; ------[ Formula of BB 0_0x574-empty ]------

; ------[ ####  Instr #0: @0x574: add ebx, 0x1a8c   #### ]------

; ------[   ****    DBA instr #0: res32<32> := (0x00001a8c + ebx<32>)   **** ]------
(define-fun
  res320_0_0x574-empty () (_ BitVec 32) (bvadd ebx_entry_0_0x574-empty (_ bv6796 32)))

; ------[   ****    DBA instr #1: OF<1> := ((ebx<32>{31} = 0<1>) & (ebx<32>{31} != res32<32>{31}))  **** ]------
(define-fun
  OF_exit_0_0x574-empty () (_ BitVec 1)
  (bvand (bvcomp ((_ extract 31 31) ebx_entry_0_0x574-empty) (_ bv0 1))
  (bvnot
  (bvcomp ((_ extract 31 31) ebx_entry_0_0x574-empty)
  ((_ extract 31 31) res320_0_0x574-empty)))))

; ------[   ****    DBA instr #2: SF<1> := (res32<32> <s 0<32>) **** ]------
(define-fun
  SF_exit_0_0x574-empty () (_ BitVec 1)
  (ite (bvslt res320_0_0x574-empty (_ bv0 32)) (_ bv1 1) (_ bv0 1)))

; ------[   ****    DBA instr #3: ZF<1> := (res32<32> = 0<32>)  **** ]------
(define-fun
  ZF_exit_0_0x574-empty () (_ BitVec 1) (bvcomp res320_0_0x574-empty (_ bv0 32)))

; ------[   ****    DBA instr #4: AF<1> := (12<5> + (extu ebx<32>{0,3} 5)){4}   **** ]------
(define-fun
  AF_exit_0_0x574-empty () (_ BitVec 1)
  ((_ extract 4 4)
  (bvadd ((_ zero_extend 1) ((_ extract 3 0) ebx_entry_0_0x574-empty)) (_ bv12 5))))

; ------[   ****    DBA instr #5: PF<1> :=  !  ((((((((res32<32>{0} ^ res32<32>{1}) ^ res32<32>{2}) ^ res32<32>{3}) ^       res32<32>{4}) ^ res32<32>{5}) ^ res32<32>{6}) ^ res32<32>{7}))  **** ]------
(define-fun
  PF_exit_0_0x574-empty () (_ BitVec 1)
  (bvnot
  (bvxor
  (bvxor
  (bvxor
  (bvxor
  (bvxor
  (bvxor
  (bvxor ((_ extract 0 0) res320_0_0x574-empty) ((_ extract 1 1) res320_0_0x574-empty))
  ((_ extract 2 2) res320_0_0x574-empty)) ((_ extract 3 3) res320_0_0x574-empty))
  ((_ extract 4 4) res320_0_0x574-empty)) ((_ extract 5 5) res320_0_0x574-empty))
  ((_ extract 6 6) res320_0_0x574-empty)) ((_ extract 7 7) res320_0_0x574-empty))))

; ------[   ****    DBA instr #6: CF<1> := (0b000000000000000000001101010001100 + (extu ebx<32> 33)){32}    **** ]------
(define-fun
  CF_exit_0_0x574-empty () (_ BitVec 1)
  ((_ extract 32 32)
  (bvadd ((_ zero_extend 1) ebx_entry_0_0x574-empty) (_ bv6796 33))))

; ------[   ****    DBA instr #7: ebx<32> := res32<32>  **** ]------
(define-fun ebx_exit_0_0x574-empty () (_ BitVec 32) res320_0_0x574-empty)

; ------[   ****    DBA instr #8: goto (0x0000057a, 0)  **** ]------

; ------[ ####  Instr #1: @0x57a: call 0x657    #### ]------

; ------[   ****    DBA instr #0: esp<32> := (esp<32> - 4<32>)  **** ]------
(define-fun
  esp_exit_0_0x574-empty () (_ BitVec 32) (bvsub esp_entry_0_0x574-empty (_ bv4 32)))

; ------[   ****    DBA instr #1: @[esp<32>,4] := 0x0000057f    **** ]------
(define-fun mem_case_write_addr0_0_0x574-empty () (_ BitVec 32) esp_exit_0_0x574-empty)
(define-fun
  memory_exit_0_0x574-empty () (Array (_ BitVec 32) (_ BitVec 8))
  (store
  (store
  (store (store memory_entry_0_0x574-empty esp_exit_0_0x574-empty (_ bv127 8))
  (bvadd esp_exit_0_0x574-empty (_ bv1 32)) (_ bv5 8))
  (bvadd esp_exit_0_0x574-empty (_ bv2 32)) (_ bv0 8))
  (bvadd esp_exit_0_0x574-empty (_ bv3 32)) (_ bv0 8)))

; ------[   ****    DBA instr #2: goto (0x00000657, 0) #call with return address @ (0x0000057f, 0)  **** ]------


; ------[ BOA: Exit variables of the formula definitions ]------

(define-fun memory_exit () (Array (_ BitVec 32) (_ BitVec 8)) memory_exit_0_0x574-empty)
(define-fun eax_exit () (_ BitVec 32) eax_entry_0_0x574-empty)
(define-fun ebx_exit () (_ BitVec 32) ebx_exit_0_0x574-empty)
(define-fun ecx_exit () (_ BitVec 32) ecx_entry_0_0x574-empty)
(define-fun edx_exit () (_ BitVec 32) edx_entry_0_0x574-empty)
(define-fun esi_exit () (_ BitVec 32) esi_entry_0_0x574-empty)
(define-fun edi_exit () (_ BitVec 32) edi_entry_0_0x574-empty)
(define-fun ebp_exit () (_ BitVec 32) ebp_entry_0_0x574-empty)
(define-fun esp_exit () (_ BitVec 32) esp_exit_0_0x574-empty)
(define-fun OF_exit () (_ BitVec 1) OF_exit_0_0x574-empty)
(define-fun SF_exit () (_ BitVec 1) SF_exit_0_0x574-empty)
(define-fun ZF_exit () (_ BitVec 1) ZF_exit_0_0x574-empty)
(define-fun PF_exit () (_ BitVec 1) PF_exit_0_0x574-empty)
(define-fun CF_exit () (_ BitVec 1) CF_exit_0_0x574-empty)
(define-fun AF_exit () (_ BitVec 1) AF_exit_0_0x574-empty)
(define-fun DF_exit () (_ BitVec 1) DF_entry_0_0x574-empty)


(push 1)

(define-fun mem_case_symb () (_ BitVec 32) (concat (select memory_exit (bvadd (_ bv1048556 32) (_ bv3 32))
) (concat (select memory_exit (bvadd (_ bv1048556 32) (_ bv2 32))
) (concat (select memory_exit (bvadd (_ bv1048556 32) (_ bv1 32))
) (select memory_exit (_ bv1048556 32))))))

(check-sat)

(get-value (mem_case_symb))

(assert (not (= mem_case_symb (_ bv1407 32))))

(check-sat)

Answer of CVC4:

sat
((mem_case_symb (_ bv1407 32)))
unsat

Answer of Z3:

sat
((mem_case_symb #x0000057f))
unsat

Answer of Boolector:

sat
((mem_case_symb (_ bv0 32))) # The error here!
unsat

I use the last version of master branch.

Thank you for your help!

Different duration for a different push/pop queries order?

Hi,

I just notice that I obtain a different computation time of Boolector if I send it a list of queries in a different order, is it normal and how to optimize this?

To reproduce this issue download the files formula.smt2, mem_analysis.smt2 and reg_analysis.smt2.

  • formula.smt2 only contain variables definitions without any check-sat or get-value.
  • mem_analysis.smt2 and reg_analysis.smt2 contain a list of queries in the form of push - check-sat - get-value - assert - check-sat - pop.

If I swap mem_analysis.smt2 and reg_analysis.smt2 I obtain different durations:

$ cat formula.smt2 reg_analysis.smt2 mem_analysis.smt2 | time boolector --smt2 -i -d -m
boolector --smt2 -i -d -m  21,24s user 0,08s system 99% cpu 21,441 total

$ cat formula.smt2 mem_analysis.smt2 reg_analysis.smt2 | time boolector --smt2 -i -d -m
boolector --smt2 -i -d -m  39,16s user 0,17s system 98% cpu 39,880 total

Time is multiplied by 2!

Thank you for your help and/or explanation

Edit: It seems that I obtain a better time if I restart Boolector and re send the formula for each query instead of playing with the push - pop commands :-/

smtlib files.zip

Python module name change

With the release of version 3 the python module name has changed from boolector to pyboolector. If this was intentional, I would suggest adding this to the release notes.

The API works fine. Thanks for the new release!

[Bug Report] Use-after-free problem in car function in btorsmt.c

Hi, there.

A Use-after-free problem was discovered in car function in btorsmt.c in src/parser. A crafted input can cause segment faults and I have confirmed them with address sanitizer too.

Here are the POC files. Please use ./boolector $POC to reproduce the bug.
POC.zip

Note that similar issues were reported (#28 and #29) in the past, which is fixed. But this bug can still reproduce on the master branch.

$ git log

commit 0874a185cd98711b3e4a0b1a0c10e858ff4a23e6
Author: Aina Niemetz <[email protected]>
Date:   Fri Mar 22 19:39:12 2019 -0700

    btoruntrace: Fix mem leak.

The ASAN dumps the stack trace as follows:

=================================================================
==31295==ERROR: AddressSanitizer: heap-use-after-free on address 0x60300000e0b0 at pc 0x7f17e08cbb00 bp 0x7ffe777fdf20 sp 0x7ffe777fdf18
READ of size 8 at 0x60300000e0b0 thread T0
    #0 0x7f17e08cbaff in car /boolector/src/parser/btorsmt.c:236:16
    #1 0x7f17e08cbaff in recursively_delete_smt_node /boolector/src/parser/btorsmt.c:383
    #2 0x7f17e08ca6c3 in release_smt_nodes /boolector/src/parser/btorsmt.c:443:5
    #3 0x7f17e08ca6c3 in release_smt_internals /boolector/src/parser/btorsmt.c:449
    #4 0x7f17e08c1de1 in parse_smt_parser /boolector/src/parser/btorsmt.c:2956:3
    #5 0x7f17e0674ff1 in parse_aux /boolector/src/btorparse.c:68:15
    #6 0x7f17e0673e81 in btor_parse /boolector/src/btorparse.c:230:9
    #7 0x4f5138 in boolector_main /boolector/src/btormain.c:1462:19
    #8 0x7f17df44882f in __libc_start_main /build/glibc-Cl5G7W/glibc-2.23/csu/../csu/libc-start.c:291
    #9 0x419c58 in _start (/boolector/build/bin/boolector+0x419c58)

0x60300000e0b0 is located 0 bytes inside of 24-byte region [0x60300000e0b0,0x60300000e0c8)
freed by thread T0 here:
    #0 0x4b9c00 in __interceptor_cfree.localalias.0 (/boolector/build/bin/boolector+0x4b9c00)
    #1 0x7f17e08cc2e7 in recursively_delete_smt_node /boolector/src/parser/btorsmt.c:394:5
    #2 0x7f17e08ca6c3 in release_smt_nodes /boolector/src/parser/btorsmt.c:443:5
    #3 0x7f17e08ca6c3 in release_smt_internals /boolector/src/parser/btorsmt.c:449
    #4 0x7f17e08c1de1 in parse_smt_parser /boolector/src/parser/btorsmt.c:2956:3
    #5 0x7f17e0674ff1 in parse_aux /boolector/src/btorparse.c:68:15
    #6 0x7f17e0673e81 in btor_parse /boolector/src/btorparse.c:230:9
    #7 0x4f5138 in boolector_main /boolector/src/btormain.c:1462:19
    #8 0x7f17df44882f in __libc_start_main /build/glibc-Cl5G7W/glibc-2.23/csu/../csu/libc-start.c:291

previously allocated by thread T0 here:
    #0 0x4b9d88 in __interceptor_malloc (/boolector/build/bin/boolector+0x4b9d88)
    #1 0x7f17e09f1d6b in btor_mem_malloc /boolector/src/utils/btormem.c:75:12
    #2 0x7f17e08c151f in cons /boolector/src/parser/btorsmt.c:255:3
    #3 0x7f17e08c151f in parse /boolector/src/parser/btorsmt.c:2889
    #4 0x7f17e08c151f in parse_smt_parser /boolector/src/parser/btorsmt.c:2955
    #5 0x7f17e0674ff1 in parse_aux /boolector/src/btorparse.c:68:15
    #6 0x7f17e0673e81 in btor_parse /boolector/src/btorparse.c:230:9
    #7 0x4f5138 in boolector_main /boolector/src/btormain.c:1462:19
    #8 0x7f17df44882f in __libc_start_main /build/glibc-Cl5G7W/glibc-2.23/csu/../csu/libc-start.c:291

SUMMARY: AddressSanitizer: heap-use-after-free /boolector/src/parser/btorsmt.c:236:16 in car
Shadow bytes around the buggy address:
  0x0c067fff9bc0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c067fff9bd0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c067fff9be0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c067fff9bf0: fa fa fa fa fa fa fa fa 00 00 00 fa fa fa 00 00
  0x0c067fff9c00: 00 fa fa fa fd fd fd fd fa fa 00 00 00 fa fa fa
=>0x0c067fff9c10: fd fd fd fa fa fa[fd]fd fd fa fa fa fd fd fd fd
  0x0c067fff9c20: fa fa 00 00 00 05 fa fa 00 00 07 fa fa fa fd fd
  0x0c067fff9c30: fd fd fa fa 00 00 00 00 fa fa fd fd fd fd fa fa
  0x0c067fff9c40: 00 00 00 00 fa fa 00 00 00 00 fa fa 00 00 00 00
  0x0c067fff9c50: fa fa 00 00 00 00 fa fa 00 00 00 00 fa fa 00 00
  0x0c067fff9c60: 00 00 fa fa fd fd fd fd fa fa fd fd fd fd fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Heap right redzone:      fb
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack partial redzone:   f4
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
==31295==ABORTING

Example of quantifiers usage in python bindings

It is my understanding that Boolector 3 supports quantified bitvectors.
I cannot find the associated methods in the python wrappers. I was expecting to have a way to create a Forall and an Exists node. Are these missing or is there a special way to construct quantified expressions?

Thanks,
Marco

Edit: This is related to pysmt/pysmt#505

Error with Array sort as output from function with parameters

When running the latest version of boolector on the following example I get the error message printed afterwards. Is this a bug or intended behaviour? Is there a reason to forbid functions returning arrays?

(set-logic QF_AUFBV)

(declare-const x (Array (_ BitVec 32) (_ BitVec 8)))
(define-fun Store-2 
  ((a (_ BitVec 32)))
  (Array (_ BitVec 32) (_ BitVec 8))
  (store x a #x08))

(check-sat)
(get-model)
$ boolector no_overlap.smt2
boolector: no_overlap.smt2:6:36: sort Array is not supported for arity > 0

Thanks,
Sean

Should uext bounds check?

We ran into an issue when passing -1 (which when casted to uint32_t is a huge number) to boolector_uext; boolector crashes with a segfault. Here is some Haskell code demonstrating the bug:

PLSysSec/haskell-boolector#5

We can produce C code to trigger this, but I image ya'll already have an easier/faster way to test this.

Thanks!

print-success: get-value response is not standards compliant

For this input:

(set-option :print-success true)
(set-option :produce-models true)
(set-logic QF_BV)
(declare-fun x () (_ BitVec 8))
(check-sat)
(get-value (x))

Boolector 3.0.0 (freshly built out of github sources) prints:

success
success
success
success
sat
success
((x #b00000000))

This is not standards compliant, since the printing of success in response to get-value should not be there. (That is, after the sat response, we shouldn't see a success, but directly the printing of the valuation pair.) If you try it with other solvers (z3, yices, cvc4), you can see that success isn't printed after we see sat.

This might sound like nit-picking, but unfortunately, it breaks compatibility with tools that operate on top of SMT-solvers; and is a real issue for me. Would be great if it can be fixed!

C interface "get-value"

Hi,

It would be fantastic if you can implement the (get-value (my_var)) SMTLIB command with a C API function?

Thank you!

Reduce verbosity with model-gen

If you try with the attached file test.smt2.

With CVC4 you get:

 $ cvc4 --lang=smt2.6 --produce-models --incremental /tmp/test.smt2
sat
((esi2 (_ bv8328 32)))

With Z3 you get:

 $ z3 -smt2 pp.bv_literals=false /tmp/test.smt2
sat
((esi2 (_ bv8328 32)))

But with Boolector you get:

$ boolector --model-gen --incremental --smt2 --pretty-print=0 --dec --exit-codes=0 --output-format=smt2 /tmp/test.smt2
sat
((esi2 (_ bv8328 32)))
2[8172] 96 memory0
2[8173] 32 memory0
2[8174] 0 memory0
2[8175] 0 memory0
3 0 eax0
4 0 ebx0
5 0 ecx0
6 0 edx0
7 0 esi0
8 0 edi0
9 65536 ebp0
10 65536 esp0
11 0 OF0
12 0 SF0
13 0 ZF0
14 0 PF0
15 0 CF0
16 0 AF0
17 0 DF0
40[8172] 96 memory1
40[8173] 32 memory1
40[8174] 0 memory1
40[8175] 0 memory1
41 0 eax1
42 0 ebx1
43 0 ecx1
44 0 edx1
45 0 esi1
46 0 edi1
47 65536 ebp1
48 65536 esp1
49 0 OF1
50 0 SF1
51 0 ZF1
52 0 PF1
53 0 CF1
54 0 AF1
55 0 DF1

As expected, the 3 solvers give the same result, BUT Boolector prints some other information on my variables.

  1. Is it the expected behavior?
  2. Is there an option to disable this extra information?
  3. If no option, can you tell me which lines in the source code I have to comment to disable this extra information in order to get the same output as Z3 and CVC4.

Thank you very munch for your help!

test.smt2.zip

How do you specify lingeling switches from boolector executable

Hi,
We used to call "boolector --lingeling --lingeling-opts=elim=0" to set a particular option in the lingeling in older versions. Now the same option fails. Can you please let me know how we can do the same with the current boolector version? If it is not there would you be able to add the feature?

Some tests fail

 268/1800 Test  #268: modelgen ....................................   Passed    0.08 sec
          Start  269: modelgen1
 269/1800 Test  #269: modelgen1 ...................................Child aborted***Exception:   0.13 sec
          Start  270: modelgen10
 270/1800 Test  #270: modelgen10 ..................................Child aborted***Exception:   0.09 sec
          Start  271: modelgen11
 271/1800 Test  #271: modelgen11 ..................................Child aborted***Exception:   0.09 sec
          Start  272: modelgen12
 272/1800 Test  #272: modelgen12 ..................................Child aborted***Exception:   0.09 sec
          Start  273: modelgen13
 273/1800 Test  #273: modelgen13 ..................................Child aborted***Exception:   0.09 sec
          Start  274: modelgen14
 274/1800 Test  #274: modelgen14 ..................................Child aborted***Exception:   0.09 sec

Example of the individual failure log:

$ ctest --verbose -R modelgen20
UpdateCTestConfiguration  from :/usr/ports/math/boolector/work/.build/DartConfiguration.tcl
UpdateCTestConfiguration  from :/usr/ports/math/boolector/work/.build/DartConfiguration.tcl
Test project /usr/ports/math/boolector/work/.build
Constructing a list of tests
Done constructing a list of tests
Updating test list for fixtures
Added 0 tests to meet fixture requirements
Checking test dependency graph...
Checking test dependency graph end
test 281
    Start 281: modelgen20

281: Test command: /usr/ports/math/boolector/work/.build/bin/test "-q" "-e" "modelgen20"
281: Test timeout computed to be: 10000000
281:   File "/usr/ports/math/boolector/work/boolector-3.0.0-239-g0b4b8540/contrib/btorcheckmodel.py", line 11
281:     print "Usage: ./btorcheckmodel <btor-file> <btor-output-model-file> <boolector-binary>"
281:                                                                                           ^
281: SyntaxError: Missing parentheses in call to 'print'. Did you mean print("Usage: ./btorcheckmodel <btor-file> <btor-output-model-file> <boolector-binary>")?
281: Assertion failed: (ret_val == 0), function modelgen_test, file /usr/ports/math/boolector/work/boolector-3.0.0-239-g0b4b8540/test/testmodelgen.c, line 92.
1/1 Test #281: modelgen20 .......................Child aborted***Exception:   0.12 sec

0% tests passed, 1 tests failed out of 1

Total Test time (real) =   0.22 sec

The following tests FAILED:
	281 - modelgen20 (Child aborted)
Errors while running CTest

Dumping of const arrays is incorrect

I believe this condition is wrong: https://github.com/Boolector/boolector/blob/master/src/dumper/btordumpsmt.c#L806

Instead it should look like this:

          if (btor_node_is_update (real_exp->e[0])
              || btor_node_is_uf_array (real_exp->e[0])
              || btor_node_is_const_array (real_exp->e[0]))

Currently, when there is a select from const array, Boolector prints this as if it were a function call to the array, instead of a call to "select." Boolector actually parses this fine (so does yices), but Z3 chokes.

Incorrect result for a quantified formula

I have a quantified formula (in the attachment formula.zip) for which the latest version of Boolector returns sat. I think that this result is incorrect, as Z3 (4.8.5), CVC4 (1.6), and Q3B (1.0) all return unsat.

I am using the following versions of Boolector and Lingeling:

[btor>main] Boolector Version 3.0.1-pre master-aa5b2972e8ba9a8c2e0788d3f9c683e7fe87440a
[btor>main]  -std=gnu99 -W -Wall -Wextra -Wredundant-decls -O3
[btor>main] released 2019-06-24T10:29:35
[btor>main] compiled 2019-06-24T10:29:35
[btor>main] GNU 9.1.0
[lingeling] Version bcj 78ebb8672540bde0a335aea946bbf32515157d5a
[lingeling] released Thu May 17 11:57:41 CEST 2018
[lingeling] compiled Fri Jun 21 10:53:36 CEST 2019
[lingeling] gcc (GCC) 9.1.0

Curiously, if I run Boolector only on the second conjunct of this formula, the result is unsat.

Thank you for investigating.

Set timeout on the fly, using command line interface

I am currently in the process of migrating a project from z3 to boolector and was wondering if it offers a similar functionality to change timeout on the fly, e.g.:

(set-option :timeout 2000)

I searched the API docs and found this, however, I was wondering if there is exists a comparable feature when using boolector from the command line with the smt2 flag.

Out of Bounds write in pusht_bfr

While fuzzing boolector,

this input file
2147483649 sort 
was found, which leads to an out of bounds write, according to valgrind.

The attached file contains more lines leading to the same crash, the above file contains the minimal version.

ASAN trace (probably not useful, since it does not find the write)
==25988==ERROR: AddressSanitizer failed to allocate 0x800002000 (34359746560) bytes of LargeMmapAllocator (error code: 12)
==25988==Process memory map follows:
	0x000000400000-0x0000007e2000	/home/user/boolector-asan
	0x0000009e2000-0x0000009e3000	/home/user/boolector-asan
	0x0000009e3000-0x000000a07000	/home/user/boolector-asan
	0x000000a07000-0x0000016fa000	
	0x00007fff7000-0x00008fff7000	
	0x00008fff7000-0x02008fff7000	
	0x02008fff7000-0x10007fff8000	
	0x600000000000-0x602000000000	
	0x602000000000-0x602000010000	
	0x602000010000-0x603000000000	
	0x603000000000-0x603000010000	
	0x603000010000-0x604000000000	
	0x604000000000-0x604000010000	
	0x604000010000-0x606000000000	
	0x606000000000-0x606000010000	
	0x606000010000-0x607000000000	
	0x607000000000-0x607000010000	
	0x607000010000-0x608000000000	
	0x608000000000-0x608000010000	
	0x608000010000-0x60b000000000	
	0x60b000000000-0x60b000010000	
	0x60b000010000-0x60c000000000	
	0x60c000000000-0x60c000010000	
	0x60c000010000-0x60e000000000	
	0x60e000000000-0x60e000010000	
	0x60e000010000-0x611000000000	
	0x611000000000-0x611000010000	
	0x611000010000-0x615000000000	
	0x615000000000-0x615000020000	
	0x615000020000-0x616000000000	
	0x616000000000-0x616000020000	
	0x616000020000-0x619000000000	
	0x619000000000-0x619000020000	
	0x619000020000-0x61d000000000	
	0x61d000000000-0x61d000020000	
	0x61d000020000-0x621000000000	
	0x621000000000-0x621000020000	
	0x621000020000-0x622000000000	
	0x622000000000-0x622000020000	
	0x622000020000-0x624000000000	
	0x624000000000-0x624000030000	
	0x624000030000-0x625000000000	
	0x625000000000-0x625000020000	
	0x625000020000-0x629000000000	
	0x629000000000-0x629000010000	
	0x629000010000-0x62d000000000	
	0x62d000000000-0x62d000020000	
	0x62d000020000-0x631000000000	
	0x631000000000-0x631000040000	
	0x631000040000-0x640000000000	
	0x640000000000-0x640000003000	
	0x7f5e91ee2000-0x7f6291ee4000	
	0x7f6691e00000-0x7f6691f00000	
	0x7f6692000000-0x7f6692100000	
	0x7f6692200000-0x7f6692300000	
	0x7f6692400000-0x7f6692500000	
	0x7f6692533000-0x7f6694885000	
	0x7f6694885000-0x7f6694a6c000	/lib/x86_64-linux-gnu/libc-2.27.so
	0x7f6694a6c000-0x7f6694c6c000	/lib/x86_64-linux-gnu/libc-2.27.so
	0x7f6694c6c000-0x7f6694c70000	/lib/x86_64-linux-gnu/libc-2.27.so
	0x7f6694c70000-0x7f6694c72000	/lib/x86_64-linux-gnu/libc-2.27.so
	0x7f6694c72000-0x7f6694c76000	
	0x7f6694c76000-0x7f6694c8d000	/lib/x86_64-linux-gnu/libgcc_s.so.1
	0x7f6694c8d000-0x7f6694e8c000	/lib/x86_64-linux-gnu/libgcc_s.so.1
	0x7f6694e8c000-0x7f6694e8d000	/lib/x86_64-linux-gnu/libgcc_s.so.1
	0x7f6694e8d000-0x7f6694e8e000	/lib/x86_64-linux-gnu/libgcc_s.so.1
	0x7f6694e8e000-0x7f6694e91000	/lib/x86_64-linux-gnu/libdl-2.27.so
	0x7f6694e91000-0x7f6695090000	/lib/x86_64-linux-gnu/libdl-2.27.so
	0x7f6695090000-0x7f6695091000	/lib/x86_64-linux-gnu/libdl-2.27.so
	0x7f6695091000-0x7f6695092000	/lib/x86_64-linux-gnu/libdl-2.27.so
	0x7f6695092000-0x7f6695099000	/lib/x86_64-linux-gnu/librt-2.27.so
	0x7f6695099000-0x7f6695298000	/lib/x86_64-linux-gnu/librt-2.27.so
	0x7f6695298000-0x7f6695299000	/lib/x86_64-linux-gnu/librt-2.27.so
	0x7f6695299000-0x7f669529a000	/lib/x86_64-linux-gnu/librt-2.27.so
	0x7f669529a000-0x7f66952b4000	/lib/x86_64-linux-gnu/libpthread-2.27.so
	0x7f66952b4000-0x7f66954b3000	/lib/x86_64-linux-gnu/libpthread-2.27.so
	0x7f66954b3000-0x7f66954b4000	/lib/x86_64-linux-gnu/libpthread-2.27.so
	0x7f66954b4000-0x7f66954b5000	/lib/x86_64-linux-gnu/libpthread-2.27.so
	0x7f66954b5000-0x7f66954b9000	
	0x7f66954b9000-0x7f6695656000	/lib/x86_64-linux-gnu/libm-2.27.so
	0x7f6695656000-0x7f6695855000	/lib/x86_64-linux-gnu/libm-2.27.so
	0x7f6695855000-0x7f6695856000	/lib/x86_64-linux-gnu/libm-2.27.so
	0x7f6695856000-0x7f6695857000	/lib/x86_64-linux-gnu/libm-2.27.so
	0x7f6695857000-0x7f66959d0000	/usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25
	0x7f66959d0000-0x7f6695bd0000	/usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25
	0x7f6695bd0000-0x7f6695bda000	/usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25
	0x7f6695bda000-0x7f6695bdc000	/usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25
	0x7f6695bdc000-0x7f6695be0000	
	0x7f6695be0000-0x7f6695c07000	/lib/x86_64-linux-gnu/ld-2.27.so
	0x7f6695cdd000-0x7f6695df4000	
	0x7f6695df4000-0x7f6695e07000	
	0x7f6695e07000-0x7f6695e08000	/lib/x86_64-linux-gnu/ld-2.27.so
	0x7f6695e08000-0x7f6695e09000	/lib/x86_64-linux-gnu/ld-2.27.so
	0x7f6695e09000-0x7f6695e0a000	
	0x7ffde7145000-0x7ffde7166000	[stack]
	0x7ffde71ea000-0x7ffde71ed000	[vvar]
	0x7ffde71ed000-0x7ffde71ef000	[vdso]
	0xffffffffff600000-0xffffffffff601000	[vsyscall]
==25988==End of process memory map.
==25988==AddressSanitizer CHECK failed: /build/llvm-toolchain-3.9-GZwVE7/llvm-toolchain-3.9-3.9.1/projects/compiler-rt/lib/sanitizer_common/sanitizer_common.cc:120 "((0 && "unable to mmap")) != (0)" (0x0, 0x0)
==25988==WARNING: failed to fork (errno 12)
==25988==WARNING: failed to fork (errno 12)
==25988==WARNING: failed to fork (errno 12)
==25988==WARNING: failed to fork (errno 12)
==25988==WARNING: failed to fork (errno 12)
==25988==WARNING: Failed to use and restart external symbolizer!
    #0 0x4efc65  (/home/user/boolector-asan+0x4efc65)
    #1 0x50a375  (/home/user/boolector-asan+0x50a375)
    #2 0x4f9aa2  (/home/user/boolector-asan+0x4f9aa2)
    #3 0x503a15  (/home/user/boolector-asan+0x503a15)
    #4 0x4425b9  (/home/user/boolector-asan+0x4425b9)
    #5 0x43c7d6  (/home/user/boolector-asan+0x43c7d6)
    #6 0x4e6178  (/home/user/boolector-asan+0x4e6178)
    #7 0x42aa0a  (/home/user/boolector-asan+0x42aa0a)
    #8 0x42ab61  (/home/user/boolector-asan+0x42ab61)
    #9 0x6f4720  (/home/user/boolector-asan+0x6f4720)
    #10 0x65b591  (/home/user/boolector-asan+0x65b591)
    #11 0x5a033a  (/home/user/boolector-asan+0x5a033a)
    #12 0x59f55a  (/home/user/boolector-asan+0x59f55a)
    #13 0x52531e  (/home/user/boolector-asan+0x52531e)
    #14 0x7f66948a6b96  (/lib/x86_64-linux-gnu/libc.so.6+0x21b96)
    #15 0x4367a9  (/home/user/boolector-asan+0x4367a9)
Valgrind trace
==26039== Memcheck, a memory error detector
==26039== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==26039== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==26039== Command: ./boolector-plain pusht_bfr.btor2
==26039== 
==26039== Warning: set address range perms: large range [0x15bf0028, 0x25bf0058) (noaccess)
==26039== Warning: set address range perms: large range [0x79e43040, 0x99e43040) (undefined)
==26039== Warning: set address range perms: large range [0x25bf1028, 0x45bf1058) (noaccess)
==26039== Warning: set address range perms: large range [0xd9e44040, 0x119e44040) (undefined)
==26039== Warning: set address range perms: large range [0x59e43028, 0x99e43058) (noaccess)
==26039== Warning: set address range perms: large range [0x199e45040, 0x219e45040) (undefined)
==26039== Warning: set address range perms: large range [0x99e44028, 0x119e44058) (noaccess)
==26039== Warning: set address range perms: large range [0x319e46040, 0x419e46040) (undefined)
==26039== Warning: set address range perms: large range [0x119e45028, 0x219e45058) (noaccess)
==26039== Warning: set address range perms: large range [0x619e47040, 0x819e47040) (undefined)
==26039== Warning: set address range perms: large range [0x219e46028, 0x419e46058) (noaccess)
==26039== Invalid write of size 8
==26039==    at 0x1197DA: pusht_bfr (in /home/user/boolector-plain)
==26039==    by 0x11991C: new_line_bfr (in /home/user/boolector-plain)
==26039==    by 0x1E9730: btor2parser_read_lines (in /home/user/boolector-plain)
==26039==    by 0x1BB013: parse_btor2_parser (in /home/user/boolector-plain)
==26039==    by 0x16C6FD: btor_parse (in /home/user/boolector-plain)
==26039==    by 0x128F87: boolector_main (in /home/user/boolector-plain)
==26039==    by 0x541AB96: (below main) (libc-start.c:310)
==26039==  Address 0x400000000 is 8,155,537,344 bytes inside a block of size 8,589,934,592 free'd
==26039==    at 0x4C31D2F: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==26039==    by 0x1197C5: pusht_bfr (in /home/user/boolector-plain)
==26039==    by 0x11991C: new_line_bfr (in /home/user/boolector-plain)
==26039==    by 0x1E9730: btor2parser_read_lines (in /home/user/boolector-plain)
==26039==    by 0x1BB013: parse_btor2_parser (in /home/user/boolector-plain)
==26039==    by 0x16C6FD: btor_parse (in /home/user/boolector-plain)
==26039==    by 0x128F87: boolector_main (in /home/user/boolector-plain)
==26039==    by 0x541AB96: (below main) (libc-start.c:310)
==26039==  Block was alloc'd at
==26039==    at 0x4C31D2F: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==26039==    by 0x1197C5: pusht_bfr (in /home/user/boolector-plain)
==26039==    by 0x11991C: new_line_bfr (in /home/user/boolector-plain)
==26039==    by 0x1E9730: btor2parser_read_lines (in /home/user/boolector-plain)
==26039==    by 0x1BB013: parse_btor2_parser (in /home/user/boolector-plain)
==26039==    by 0x16C6FD: btor_parse (in /home/user/boolector-plain)
==26039==    by 0x128F87: boolector_main (in /home/user/boolector-plain)
==26039==    by 0x541AB96: (below main) (libc-start.c:310)
==26039== 
boolector: line 5: expected tag
==26039== 
==26039== HEAP SUMMARY:
==26039==     in use at exit: 17,179,869,328 bytes in 3 blocks
==26039==   total heap usage: 870 allocs, 867 frees, 68,719,507,815 bytes allocated
==26039== 
==26039== LEAK SUMMARY:
==26039==    definitely lost: 120 bytes in 1 blocks
==26039==    indirectly lost: 24 bytes in 1 blocks
==26039==      possibly lost: 17,179,869,184 bytes in 1 blocks
==26039==    still reachable: 0 bytes in 0 blocks
==26039==         suppressed: 0 bytes in 0 blocks
==26039== Rerun with --leak-check=full to see details of leaked memory
==26039== 
==26039== For counts of detected and suppressed errors, rerun with: -v
==26039== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

Used version

$ boolector --version
3.0.1-pre

Steps to reproduce

boolector  pusht_bfr.btor2.txt

Add support for the (reset) SMTLIB command

Hi,
Do you plan to add the support for the (reset) SMTLIB command?

According to http://smtlib.cs.uiowa.edu/papers/smt-lib-reference-v2.6-r2017-07-18.pdf:

The new command reset brings the state of a solver to the state it had immediately after start up (resetting everything).

In my case, I have a lot of formula to check but they are not related at all. This is why I use the (reset) command with Z3 and CVC4. But with Boolector I have to kill the Boolector process and start a new one each time I want to "start a fresh session".

Thank you!

Bug in scope handling (SMT-LIB 2 parser)

Hi there,

we observed a bug with the following (already reduced) SMT-LIB 2 script:

(set-logic QF_UFBV)
(push 2)
(declare-fun t_n () (_ BitVec 27))
(check-sat)
(pop 1)
(declare-fun t_n (Bool Bool) (_ BitVec 3))
(check-sat)
(exit)

Using both the most recent version and the version tagged 3.0.0, Boolector prints the following error:

[boolector] boolector_uf: symbol 'BTOR@2t_n' is already in use

The bug seems to be related to the scope handling in the SMT-LIB 2 parser. If we apply the following patch, the bug disappears: boolector-3.0.0.patch.txt Sorry, but the patch does not work properly. If we add (push 1) after the pop command, Boolector prints an error message again. It seems that the symbol table is not properly cleared when leaving the scope, but this is just an assumption...

Question on overflow operations

Hi,

I see that the C API includes a bunch of operations relating to the overflow in arithmetic operations, like uaddo, saddo, usubo, ssubo, umulo, smulo, sdivo.
Since these appear to me outside the SMT-LIB v2 format, are there any formal definition of each such function (especially the signed ones) into an equivalent SMT2 expression?

Thanks
Regards
Aman
https://aman-goel.github.io

CMake PythonLibs: Incorrect detection from within python virtual environment

There seems to be some issues with CMake FindPythonLibs on systems with multiple versions of Python (see e.g. pybind/pybind11#99 ). This has been reported multiple times for OS X, where it is common to have a system python and a version installed via homebrew (or similar), but this also happens on linux, when using virtual environments and this happens in Travis CI (ubuntu xenial):

  • When testing python 3.7, python is able to detect the mismatch and only raises a warning (although I fear this will turn into a segfault at some point):
/home/travis/virtualenv/python3.7.1/lib/python3.7/importlib/_bootstrap.py:219: RuntimeWarning: compiletime version 3.5 of module 'pyboolector' does not match runtime version 3.7
  • When testing python 2.7, it is impossible to load the library (there is a mismatch of minor version: 2.7.11 vs 2.7.15):
Traceback (most recent call last):
  File "<string>", line 1, in <module>
ImportError: /home/travis/virtualenv/python2.7.15/lib/python2.7/site-packages/pyboolector.so: undefined symbol: PyFPE_jbuf

In both cases we can see that the CMake log shows that the detected python library is incorrect:

-- Found PythonInterp: /home/travis/virtualenv/python3.7.1/bin/python (found version "3.7.1") 
-- Found PythonLibs: /usr/lib/x86_64-linux-gnu/libpython3.5m.so (found version "3.5.2") 

Potential Fixes:

  1. In https://cmake.org/cmake/help/v3.7/module/FindPythonLibs.html there is the following recommendation: "If calling both find_package(PythonInterp) and find_package(PythonLibs), call find_package(PythonInterp) first to get the currently active Python version by default with a consistent version of PYTHON_LIBRARIES."
    I checked and to me, it seems that this is already the case, but a second opinion would be good, since this would be the easiest fix.

  2. CMake 3.12 introduces a FindPython command that deprecates the FindPythonLibs one, and might address this, but it is very recent and would make it hard to build boolector on older systems.

  3. Use the flags -DPYTHON_INCLUDE_DIR and -DPYTHON_LIBRARY in CMake to manually specify the path of the library. This seems a simple workaround, and would be my preferred way. This could be a dedicated option in the configure.sh, or we could allow to specify pass-through flags to CMake (this is a bit more general and might come handy in other situations). A way of doing this would be to change L178 of configure.sh from cmake_opts="" tocmake_opts="${CMAKE_OPTIONS}".

More info on how to reproduce are available in pysmt/pysmt#514

Use after Free in get_failed_assumptions

While fuzzing boolector,

this input file
(assert#b0)
(check-sat)
(get-unsat-assumptions)
(get-unsat-assumptions)

was found, which leads to a use after free in get_failed_assumptions.

The input file looks like this is related to #28, but the backtrace produced by ASAN is different, which is why this is filed as a separate issue.

The attached file contains more lines leading to the same crash, the above file contains the minimal version.

ASAN trace
=================================================================
==9780==ERROR: AddressSanitizer: heap-use-after-free on address 0x602000009710 at pc 0x00000052bd1c bp 0x7ffd2e8c9eb0 sp 0x7ffd2e8c9ea8
READ of size 8 at 0x602000009710 thread T0
    #0 0x52bd1b in boolector_get_failed_assumptions /home/user/boolector-master/src/boolector.c:624:12
    #1 0x6851db in read_command_smt2 /home/user/boolector-master/src/parser/btorsmt2.c:4700:28
    #2 0x682a27 in parse_smt2_parser /home/user/boolector-master/src/parser/btorsmt2.c:4828:10
    #3 0x5a033a in parse_aux /home/user/boolector-master/src/btorparse.c:68:15
    #4 0x59f55a in btor_parse /home/user/boolector-master/src/btorparse.c:230:9
    #5 0x52531e in boolector_main /home/user/boolector-master/src/btormain.c:1454:19
    #6 0x7f53f5a65b96 in __libc_start_main /build/glibc-OTsEL5/glibc-2.27/csu/../csu/libc-start.c:310
    #7 0x4367a9 in _start (/home/user/boolector-asan+0x4367a9)

0x602000009710 is located 0 bytes inside of 8-byte region [0x602000009710,0x602000009718)
freed by thread T0 here:
    #0 0x4e5bc8 in __interceptor_free.localalias.0 (/home/user/boolector-asan+0x4e5bc8)
    #1 0x68525b in read_command_smt2 /home/user/boolector-master/src/parser/btorsmt2.c:4706:7
    #2 0x682a27 in parse_smt2_parser /home/user/boolector-master/src/parser/btorsmt2.c:4828:10
    #3 0x5a033a in parse_aux /home/user/boolector-master/src/btorparse.c:68:15
    #4 0x59f55a in btor_parse /home/user/boolector-master/src/btorparse.c:230:9
    #5 0x52531e in boolector_main /home/user/boolector-master/src/btormain.c:1454:19
    #6 0x7f53f5a65b96 in __libc_start_main /build/glibc-OTsEL5/glibc-2.27/csu/../csu/libc-start.c:310

previously allocated by thread T0 here:
    #0 0x4e61a5 in realloc (/home/user/boolector-asan+0x4e61a5)
    #1 0x6cd24e in btor_mem_realloc /home/user/boolector-master/src/utils/btormem.c:104:12
    #2 0x52bc11 in boolector_get_failed_assumptions /home/user/boolector-master/src/boolector.c:633:3
    #3 0x6851db in read_command_smt2 /home/user/boolector-master/src/parser/btorsmt2.c:4700:28
    #4 0x682a27 in parse_smt2_parser /home/user/boolector-master/src/parser/btorsmt2.c:4828:10
    #5 0x5a033a in parse_aux /home/user/boolector-master/src/btorparse.c:68:15
    #6 0x59f55a in btor_parse /home/user/boolector-master/src/btorparse.c:230:9
    #7 0x52531e in boolector_main /home/user/boolector-master/src/btormain.c:1454:19
    #8 0x7f53f5a65b96 in __libc_start_main /build/glibc-OTsEL5/glibc-2.27/csu/../csu/libc-start.c:310

SUMMARY: AddressSanitizer: heap-use-after-free /home/user/boolector-master/src/boolector.c:624:12 in boolector_get_failed_assumptions
Shadow bytes around the buggy address:
  0x0c047fff9290: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff92a0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff92b0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff92c0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff92d0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
=>0x0c047fff92e0: fa fa[fd]fa fa fa 00 fa fa fa fd fd fa fa fd fa
  0x0c047fff92f0: fa fa fd fd fa fa fd fd fa fa fd fa fa fa fd fa
  0x0c047fff9300: fa fa fd fa fa fa fd fa fa fa 04 fa fa fa 04 fa
  0x0c047fff9310: fa fa 05 fa fa fa 03 fa fa fa 06 fa fa fa 06 fa
  0x0c047fff9320: fa fa 00 01 fa fa 00 01 fa fa 00 01 fa fa 00 01
  0x0c047fff9330: fa fa 00 fa fa fa 06 fa fa fa 07 fa fa fa 07 fa
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Heap right redzone:      fb
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack partial redzone:   f4
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
==9780==ABORTING
Valgrind trace
==9802== Memcheck, a memory error detector
==9802== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==9802== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==9802== Command: ./boolector-plain boolector_get_failed_assumptions.txt
==9802== 
==9802== Invalid read of size 8
==9802==    at 0x12B0AD: boolector_get_failed_assumptions (in /home/user/boolector-plain)
==9802==    by 0x1CA6D2: read_command_smt2 (in /home/user/boolector-plain)
==9802==    by 0x1CC289: parse_smt2_parser (in /home/user/boolector-plain)
==9802==    by 0x16C6FD: btor_parse (in /home/user/boolector-plain)
==9802==    by 0x128F87: boolector_main (in /home/user/boolector-plain)
==9802==    by 0x541AB96: (below main) (libc-start.c:310)
==9802==  Address 0x5809830 is 0 bytes inside a block of size 8 free'd
==9802==    at 0x4C30D3B: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==9802==    by 0x1CA705: read_command_smt2 (in /home/user/boolector-plain)
==9802==    by 0x1CC289: parse_smt2_parser (in /home/user/boolector-plain)
==9802==    by 0x16C6FD: btor_parse (in /home/user/boolector-plain)
==9802==    by 0x128F87: boolector_main (in /home/user/boolector-plain)
==9802==    by 0x541AB96: (below main) (libc-start.c:310)
==9802==  Block was alloc'd at
==9802==    at 0x4C2FA3F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==9802==    by 0x4C31D84: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==9802==    by 0x1D906D: btor_mem_realloc (in /home/user/boolector-plain)
==9802==    by 0x12B1B2: boolector_get_failed_assumptions (in /home/user/boolector-plain)
==9802==    by 0x1CA6D2: read_command_smt2 (in /home/user/boolector-plain)
==9802==    by 0x1CC289: parse_smt2_parser (in /home/user/boolector-plain)
==9802==    by 0x16C6FD: btor_parse (in /home/user/boolector-plain)
==9802==    by 0x128F87: boolector_main (in /home/user/boolector-plain)
==9802==    by 0x541AB96: (below main) (libc-start.c:310)
==9802== 
==9802== Invalid free() / delete / delete[] / realloc()
==9802==    at 0x4C30D3B: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==9802==    by 0x12B10A: boolector_get_failed_assumptions (in /home/user/boolector-plain)
==9802==    by 0x1CA6D2: read_command_smt2 (in /home/user/boolector-plain)
==9802==    by 0x1CC289: parse_smt2_parser (in /home/user/boolector-plain)
==9802==    by 0x16C6FD: btor_parse (in /home/user/boolector-plain)
==9802==    by 0x128F87: boolector_main (in /home/user/boolector-plain)
==9802==    by 0x541AB96: (below main) (libc-start.c:310)
==9802==  Address 0x5809830 is 0 bytes inside a block of size 8 free'd
==9802==    at 0x4C30D3B: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==9802==    by 0x1CA705: read_command_smt2 (in /home/user/boolector-plain)
==9802==    by 0x1CC289: parse_smt2_parser (in /home/user/boolector-plain)
==9802==    by 0x16C6FD: btor_parse (in /home/user/boolector-plain)
==9802==    by 0x128F87: boolector_main (in /home/user/boolector-plain)
==9802==    by 0x541AB96: (below main) (libc-start.c:310)
==9802==  Block was alloc'd at
==9802==    at 0x4C2FA3F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==9802==    by 0x4C31D84: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==9802==    by 0x1D906D: btor_mem_realloc (in /home/user/boolector-plain)
==9802==    by 0x12B1B2: boolector_get_failed_assumptions (in /home/user/boolector-plain)
==9802==    by 0x1CA6D2: read_command_smt2 (in /home/user/boolector-plain)
==9802==    by 0x1CC289: parse_smt2_parser (in /home/user/boolector-plain)
==9802==    by 0x16C6FD: btor_parse (in /home/user/boolector-plain)
==9802==    by 0x128F87: boolector_main (in /home/user/boolector-plain)
==9802==    by 0x541AB96: (below main) (libc-start.c:310)
==9802== 
==9802== Invalid read of size 8
==9802==    at 0x14BC53: btor_delete (in /home/user/boolector-plain)
==9802==    by 0x127EC9: boolector_main (in /home/user/boolector-plain)
==9802==    by 0x541AB96: (below main) (libc-start.c:310)
==9802==  Address 0x5809880 is 0 bytes inside a block of size 8 free'd
==9802==    at 0x4C30D3B: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==9802==    by 0x1CA705: read_command_smt2 (in /home/user/boolector-plain)
==9802==    by 0x1CC289: parse_smt2_parser (in /home/user/boolector-plain)
==9802==    by 0x16C6FD: btor_parse (in /home/user/boolector-plain)
==9802==    by 0x128F87: boolector_main (in /home/user/boolector-plain)
==9802==    by 0x541AB96: (below main) (libc-start.c:310)
==9802==  Block was alloc'd at
==9802==    at 0x4C2FA3F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==9802==    by 0x4C31D84: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==9802==    by 0x1D906D: btor_mem_realloc (in /home/user/boolector-plain)
==9802==    by 0x12B1B2: boolector_get_failed_assumptions (in /home/user/boolector-plain)
==9802==    by 0x1CA6D2: read_command_smt2 (in /home/user/boolector-plain)
==9802==    by 0x1CC289: parse_smt2_parser (in /home/user/boolector-plain)
==9802==    by 0x16C6FD: btor_parse (in /home/user/boolector-plain)
==9802==    by 0x128F87: boolector_main (in /home/user/boolector-plain)
==9802==    by 0x541AB96: (below main) (libc-start.c:310)
==9802== 
==9802== Invalid free() / delete / delete[] / realloc()
==9802==    at 0x4C30D3B: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==9802==    by 0x14BC8E: btor_delete (in /home/user/boolector-plain)
==9802==    by 0x127EC9: boolector_main (in /home/user/boolector-plain)
==9802==    by 0x541AB96: (below main) (libc-start.c:310)
==9802==  Address 0x5809880 is 0 bytes inside a block of size 8 free'd
==9802==    at 0x4C30D3B: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==9802==    by 0x1CA705: read_command_smt2 (in /home/user/boolector-plain)
==9802==    by 0x1CC289: parse_smt2_parser (in /home/user/boolector-plain)
==9802==    by 0x16C6FD: btor_parse (in /home/user/boolector-plain)
==9802==    by 0x128F87: boolector_main (in /home/user/boolector-plain)
==9802==    by 0x541AB96: (below main) (libc-start.c:310)
==9802==  Block was alloc'd at
==9802==    at 0x4C2FA3F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==9802==    by 0x4C31D84: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==9802==    by 0x1D906D: btor_mem_realloc (in /home/user/boolector-plain)
==9802==    by 0x12B1B2: boolector_get_failed_assumptions (in /home/user/boolector-plain)
==9802==    by 0x1CA6D2: read_command_smt2 (in /home/user/boolector-plain)
==9802==    by 0x1CC289: parse_smt2_parser (in /home/user/boolector-plain)
==9802==    by 0x16C6FD: btor_parse (in /home/user/boolector-plain)
==9802==    by 0x128F87: boolector_main (in /home/user/boolector-plain)
==9802==    by 0x541AB96: (below main) (libc-start.c:310)
==9802== 
==9802== 
==9802== HEAP SUMMARY:
==9802==     in use at exit: 0 bytes in 0 blocks
==9802==   total heap usage: 1,164 allocs, 1,166 frees, 46,991 bytes allocated
==9802== 
==9802== All heap blocks were freed -- no leaks are possible
==9802== 
==9802== For counts of detected and suppressed errors, rerun with: -v
==9802== ERROR SUMMARY: 4 errors from 4 contexts (suppressed: 0 from 0)

Used version

$ boolector --version
3.0.1-pre

Steps to reproduce

boolector  boolector_get_failed_assumptions.txt

Constant (e.g., zero-initialized) arrays

Hi,

Thanks so much for all your work maintaining this library! I was looking at the current C API documentation, and I don't see a way to create a constant array - that is, an array where all elements have a given concrete value, such as 0. I'm looking for a feature analogous to Z3's Z3_mk_const_array. Does an equivalent feature exist in Boolector?

boolector_bv_assignment output doesn't match docs

Changing the setting BTOR_OPT_OUTPUT_NUMBER_FORMAT to be BTOR_OUTPUT_BASE_HEX appears to enable hexadecimal output not only in dumps, but also in the return value of boolector_bv_assignment(), contradicting the boolector_bv_assignment docs which say that "Each character of the string can be 0, 1 or x". I'm not sure whether this is a documentation bug, and BTOR_OPT_OUTPUT_NUMBER_FORMAT is indeed meant to apply here - in which case, will the character be x if any of the 4 bits it represents are x? - or if this is an actual functionality bug, and BTOR_OPT_OUTPUT_NUMBER_FORMAT is not meant to affect the output of boolector_bv_assignment().

I get this behavior both with Boolector commit fa434d30 and with commit fafab47e. (Respectively, those are latest-master-at-time-of-writing, and the git tag 3.1.0.)

Pointer arithmetic

In btornode.h, I see code like this:

static inline BtorNode *
btor_node_real_addr (const BtorNode *node)
{
return (BtorNode *) (~3ul & (uintptr_t) node);
}

This is worrisome for 64-bit Windows, as 3UL is only four bytes wide (sizeof(long) = 4 on 64-bit Windows, but sizeof(uinitptr_t) = 8). Thus I am not sure if the arithmetic being done on the input pointer and the subsequent cast back to a return pointer results in a valid pointer. I don't exactly understand what this code is supposed to do, but I do know I get crashes when importing pyboolector.pyd in python, and (after some sleuthing) came down to this inlined function being called. The stack trace doesn't show this function, though, because it is inlined.

Thoughts?

[Bug Report] Heap buffer-overflow in prase function in btoruntrace.c

Hi, there.

A Heap-buffer-overflow in prase function in btoruntrace.c. A crafted input can cause segment faults and I have confirmed them with address sanitizer too.

Here are the POC files. Please use ./btoruntrace $POC to reproduce the bug.
POC.zip

$ git log

commit 0874a185cd98711b3e4a0b1a0c10e858ff4a23e6
Author: Aina Niemetz <[email protected]>
Date:   Fri Mar 22 19:39:12 2019 -0700

    btoruntrace: Fix mem leak.

The ASAN dumps the stack trace as follows:

=================================================================
==9237==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x60400000a6f8 at pc 0x0000004f08a2 bp 0x7ffe219c03b0 sp 0x7ffe219c03a8
WRITE of size 1 at 0x60400000a6f8 thread T0
    #0 0x4f08a1 in parse /home/wencheng/Documents/FuzzingObject/boolector/src/btoruntrace.c:539:45
    #1 0x50ed8f in main /home/wencheng/Documents/FuzzingObject/boolector/src/btoruntrace.c:1867:3
    #2 0x7fef504ab82f in __libc_start_main /build/glibc-Cl5G7W/glibc-2.23/csu/../csu/libc-start.c:291
    #3 0x41c628 in _start (/home/wencheng/Documents/FuzzingObject/boolector/build/bin/btoruntrace+0x41c628)

0x60400000a6f8 is located 0 bytes to the right of 40-byte region [0x60400000a6d0,0x60400000a6f8)
allocated by thread T0 here:
    #0 0x4bc8e0 in calloc (/home/wencheng/Documents/FuzzingObject/boolector/build/bin/btoruntrace+0x4bc8e0)
    #1 0x7fef51a5566f in btor_mem_calloc /home/wencheng/Documents/FuzzingObject/boolector/src/utils/btormem.c:134:12
    #2 0x4ee4b8 in parse /home/wencheng/Documents/FuzzingObject/boolector/src/btoruntrace.c:442:3
    #3 0x50ed8f in main /home/wencheng/Documents/FuzzingObject/boolector/src/btoruntrace.c:1867:3
    #4 0x7fef504ab82f in __libc_start_main /build/glibc-Cl5G7W/glibc-2.23/csu/../csu/libc-start.c:291

SUMMARY: AddressSanitizer: heap-buffer-overflow /home/wencheng/Documents/FuzzingObject/boolector/src/btoruntrace.c:539:45 in parse
Shadow bytes around the buggy address:
  0x0c087fff9480: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c087fff9490: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c087fff94a0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c087fff94b0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c087fff94c0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
=>0x0c087fff94d0: fa fa fa fa fa fa fa fa fa fa 00 00 00 00 00[fa]
  0x0c087fff94e0: fa fa 00 00 00 00 00 00 fa fa 00 00 00 00 00 00
  0x0c087fff94f0: fa fa 00 00 00 00 00 00 fa fa 00 00 00 00 00 00
  0x0c087fff9500: fa fa 00 00 00 00 00 00 fa fa 00 00 00 00 00 00
  0x0c087fff9510: fa fa 00 00 00 00 00 00 fa fa 00 00 00 00 00 00
  0x0c087fff9520: fa fa 00 00 00 00 00 00 fa fa 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07
  Heap left redzone:       fa
  Heap right redzone:      fb
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack partial redzone:   f4
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
==9237==ABORTING
Aborted

UAF causing intermittent crashes

I'm experiencing intermittent crashes which I've been trying to track down more precisely for a while. I believe I've pinpointed it as a UAF in Boolector, but I could still be wrong - among other things, I'm not very familiar with the Boolector codebase.

Specifically I believe the culprit to be btor_node_create_bv_const in btornode.c. I'm looking at the case where the lookup fails such that we end up calling new_const_exp_node. Somehow (I'm not sure) the node returned from new_const_exp_node may have a .next field which refers to some other node, but without recording that it has a ref to that other node. Let the const node be Node A, and the .next node on Node A be Node B. What I believe I'm observing in my crash traces is a case where the external caller uses boolector_release on Node B with the result that it's freed, but later operations (e.g. boolector_sat) still have a pointer to the now-freed Node B through Node A ->next.

I'm guessing this UAF doesn't usually manifest as a problem because the memory isn't reused for anything, so the Node B data stays valid enough for things to work. In my case, I have a multithreaded program where different threads are working on different Boolector instances; but these threads still naturally share the same allocator. So other threads have a timing window to come in and reallocate something else at Node B's address, and this is what I believe is causing my intermittent crashes.

I'm happy to keep digging, and I realize I very much could be wrong about the root cause here, especially as I'm not positive what internal invariants Boolector maintains around when refcounts are supposed to be inc'd and dec'd.

`udiv_bitvec` does not check for a second operand of `0`

When targeting 32-bit Windows (I have not tried 64-bit Windows, sorry), I get an assertion error when running ./bin/test.exe udiv_bitvec.

To diagnose this failure, I modified test/testbv.c as follows (the print of bv1 and bv2 is superfluous, given the print of a1 and a2, but that shouldn't change anything):

-    assert (ares == bres);
+    if (ares != bres)
+    {
+        printf("***\n");
+        printf("bv1 = %" PRIu64 "\n", btor_bv_to_uint64(bv1));
+        printf("bv2 = %" PRIu64 "\n", btor_bv_to_uint64(bv2));
+        printf("a1 = %" PRIu64 "\n", a1);
+        printf("a2 = %" PRIu64 "\n", a2);
+        printf("ares = %" PRIu64 "\n", ares);
+        printf("bres = %" PRIu64 "\n", bres);
+        printf("***\n");
+    }
+    // assert (ares == bres);

and I get the following output:

***
bv1 = 4294978274
bv2 = 0
a1 = 4294978274
a2 = 0
ares = 4294967295
bres = 8589934591
***
***
bv1 = 12315
bv2 = 0
a1 = 12315
a2 = 0
ares = 4294967295
bres = 8589934591
***
***
bv1 = 19733
bv2 = 0
a1 = 19733
a2 = 0
ares = 4294967295
bres = 8589934591
***

So, of the 100000 tests that get run, we only see assertion failures when a2 is 0.

This particular test does this:

  binary_bitvec (udiv, btor_bv_udiv, BTOR_TEST_BITVEC_TESTS, 33);

where the last argument is the bit-width (33 in this case). Furthermore the function udiv looks like this:

udiv (uint64_t x, uint64_t y, uint32_t bw)
{
  if (y == 0) return UINT32_MAX % (uint64_t) pow (2, bw);
  return (x / y) % (uint64_t) pow (2, bw);
}

So, for udiv, if the second argument (== bv2) is 0, then it returns something based off of UINT32_MAX, while I imagine (and I haven't checked) that btor_bv_udiv is "width agnostic". Furthermore, all of the variables inside of the function binary_bitvec (the callee of udiv) are uint64_ts.

Interestingly, when I run this test (with these prints) on 32-bit Linux, then the lowest value I get for bv1/a1 is 48121 and the lowest for bv2/a2 is 96199 (i.e., I never seem to get 0 for bv2).

If I create a hand-written test on any Linux architecture (both 32-bit and 64-bit) that does something like this:

void udiv_zero_test(void)
{
  BtorBitVector *bv1, *bv2, *res;
  uint64_t a1, a2, ares, bres;
  uint32_t bit_width = 33;

  // 12315 and 0 come from the failing Windows tests
  bv1  = btor_bv_uint64_to_bv (g_mm, 12315, bit_width);
  bv2  = btor_bv_uint64_to_bv (g_mm, 0, bit_width);
  res  = btor_bv_udiv(g_mm, bv1, bv2);
  a1   = btor_bv_to_uint64 (bv1);
  a2   = btor_bv_to_uint64 (bv2);
  ares = udiv(a1, a2, bit_width);
  bres = btor_bv_to_uint64 (res);
  if (ares != bres)
  {
      printf("***\n");
      printf("bv1 = %" PRIu64 "\n", btor_bv_to_uint64(bv1));
      printf("bv2 = %" PRIu64 "\n", btor_bv_to_uint64(bv2));
      printf("a1 = %" PRIu64 "\n", a1);
      printf("a2 = %" PRIu64 "\n", a2);
      printf("ares = %" PRIu64 "\n", ares);
      printf("bres = %" PRIu64 "\n", bres);
      printf("***\n");
  }
  // assert (ares == bres);
  btor_bv_free (g_mm, res);
  btor_bv_free (g_mm, bv1);
  btor_bv_free (g_mm, bv2);
}

(rather than the call to random_bv) then I do see this failure (again, on any Linux architecture).

Importantly: if I change the function udiv to do its modulo calculation based up on UINT64_MAX then the tests no longer fail!

Some questions:

  1. Is it correct that random_bv can return 0?
  2. What does it mean that random_bv never returns 0 on Linux, but does on Windows (maybe rand() is just "less random" on Windows)?
  3. Is there an issue that Boolector has no tests that explicitly check bv2 being 0?
  4. Is it correct that udiv does its modulo calculations based off UINT32_MAX when working on 64-bit operands?

If you are happy, I would suggest that we:

  1. Create a new bit-vector test-suite that does the same as udiv_bitvec, but where bv2 is always hard-coded to be 0 (maybe something like: udiv_bitvec_zero)
  2. Modify the udiv function to base its calculations off of UINT64_MAX

I am more than happy to do this work.

Use After Free in btor_delete

While fuzzing boolector,

this input file
(assert(bvcomp#xe#x5))
(check-sat)
(get-unsat-assumptions)
was found, which leads to a use after free in btor_delete.

The attached file contains more lines leading to the same crash, the above file contains the minimal version.

ASAN trace
=================================================================
==25480==ERROR: AddressSanitizer: heap-use-after-free on address 0x602000009490 at pc 0x000000569948 bp 0x7ffe250893f0 sp 0x7ffe250893e8
READ of size 8 at 0x602000009490 thread T0
    #0 0x569947 in btor_delete /home/user/boolector-master/src/btorcore.c:933:9
    #1 0x5263d6 in btormain_delete_btormain /home/user/boolector-master/src/btormain.c:457:3
    #2 0x5263d6 in boolector_main /home/user/boolector-master/src/btormain.c:1625
    #3 0x7fc17c831b96 in __libc_start_main /build/glibc-OTsEL5/glibc-2.27/csu/../csu/libc-start.c:310
    #4 0x4367a9 in _start (/home/user/boolector-asan+0x4367a9)

0x602000009490 is located 0 bytes inside of 8-byte region [0x602000009490,0x602000009498)
freed by thread T0 here:
    #0 0x4e5bc8 in __interceptor_free.localalias.0 (/home/user/boolector-asan+0x4e5bc8)
    #1 0x68525b in read_command_smt2 /home/user/boolector-master/src/parser/btorsmt2.c:4706:7
    #2 0x682a27 in parse_smt2_parser /home/user/boolector-master/src/parser/btorsmt2.c:4828:10
    #3 0x5a033a in parse_aux /home/user/boolector-master/src/btorparse.c:68:15
    #4 0x59f55a in btor_parse /home/user/boolector-master/src/btorparse.c:230:9
    #5 0x52531e in boolector_main /home/user/boolector-master/src/btormain.c:1454:19
    #6 0x7fc17c831b96 in __libc_start_main /build/glibc-OTsEL5/glibc-2.27/csu/../csu/libc-start.c:310

previously allocated by thread T0 here:
    #0 0x4e61a5 in realloc (/home/user/boolector-asan+0x4e61a5)
    #1 0x6cd24e in btor_mem_realloc /home/user/boolector-master/src/utils/btormem.c:104:12
    #2 0x52bc11 in boolector_get_failed_assumptions /home/user/boolector-master/src/boolector.c:633:3
    #3 0x6851db in read_command_smt2 /home/user/boolector-master/src/parser/btorsmt2.c:4700:28
    #4 0x682a27 in parse_smt2_parser /home/user/boolector-master/src/parser/btorsmt2.c:4828:10
    #5 0x5a033a in parse_aux /home/user/boolector-master/src/btorparse.c:68:15
    #6 0x59f55a in btor_parse /home/user/boolector-master/src/btorparse.c:230:9
    #7 0x52531e in boolector_main /home/user/boolector-master/src/btormain.c:1454:19
    #8 0x7fc17c831b96 in __libc_start_main /build/glibc-OTsEL5/glibc-2.27/csu/../csu/libc-start.c:310

SUMMARY: AddressSanitizer: heap-use-after-free /home/user/boolector-master/src/btorcore.c:933:9 in btor_delete
Shadow bytes around the buggy address:
  0x0c047fff9240: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff9250: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff9260: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff9270: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff9280: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
=>0x0c047fff9290: fa fa[fd]fa fa fa fd fa fa fa fd fd fa fa fd fa
  0x0c047fff92a0: fa fa fd fd fa fa fd fd fa fa fd fd fa fa fd fd
  0x0c047fff92b0: fa fa fd fd fa fa fd fd fa fa fd fd fa fa fd fa
  0x0c047fff92c0: fa fa fd fd fa fa fd fd fa fa fd fa fa fa fd fa
  0x0c047fff92d0: fa fa fd fd fa fa fd fd fa fa 00 00 fa fa fd fd
  0x0c047fff92e0: fa fa fd fd fa fa fd fd fa fa fd fa fa fa fd fa
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Heap right redzone:      fb
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack partial redzone:   f4
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
==25480==ABORTING
Valgrind trace
==25740== Memcheck, a memory error detector
==25740== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==25740== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==25740== Command: ./boolector-plain btor_delete.txt
==25740== 
==25740== Invalid read of size 8
==25740==    at 0x14BC53: btor_delete (in /home/user/boolector-plain)
==25740==    by 0x127EC9: boolector_main (in /home/user/boolector-plain)
==25740==    by 0x541AB96: (below main) (libc-start.c:310)
==25740==  Address 0x580a420 is 0 bytes inside a block of size 8 free'd
==25740==    at 0x4C30D3B: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==25740==    by 0x1CA705: read_command_smt2 (in /home/user/boolector-plain)
==25740==    by 0x1CC289: parse_smt2_parser (in /home/user/boolector-plain)
==25740==    by 0x16C6FD: btor_parse (in /home/user/boolector-plain)
==25740==    by 0x128F87: boolector_main (in /home/user/boolector-plain)
==25740==    by 0x541AB96: (below main) (libc-start.c:310)
==25740==  Block was alloc'd at
==25740==    at 0x4C2FA3F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==25740==    by 0x4C31D84: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==25740==    by 0x1D906D: btor_mem_realloc (in /home/user/boolector-plain)
==25740==    by 0x12B1B2: boolector_get_failed_assumptions (in /home/user/boolector-plain)
==25740==    by 0x1CA6D2: read_command_smt2 (in /home/user/boolector-plain)
==25740==    by 0x1CC289: parse_smt2_parser (in /home/user/boolector-plain)
==25740==    by 0x16C6FD: btor_parse (in /home/user/boolector-plain)
==25740==    by 0x128F87: boolector_main (in /home/user/boolector-plain)
==25740==    by 0x541AB96: (below main) (libc-start.c:310)
==25740== 
==25740== Invalid free() / delete / delete[] / realloc()
==25740==    at 0x4C30D3B: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==25740==    by 0x14BC8E: btor_delete (in /home/user/boolector-plain)
==25740==    by 0x127EC9: boolector_main (in /home/user/boolector-plain)
==25740==    by 0x541AB96: (below main) (libc-start.c:310)
==25740==  Address 0x580a420 is 0 bytes inside a block of size 8 free'd
==25740==    at 0x4C30D3B: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==25740==    by 0x1CA705: read_command_smt2 (in /home/user/boolector-plain)
==25740==    by 0x1CC289: parse_smt2_parser (in /home/user/boolector-plain)
==25740==    by 0x16C6FD: btor_parse (in /home/user/boolector-plain)
==25740==    by 0x128F87: boolector_main (in /home/user/boolector-plain)
==25740==    by 0x541AB96: (below main) (libc-start.c:310)
==25740==  Block was alloc'd at
==25740==    at 0x4C2FA3F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==25740==    by 0x4C31D84: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==25740==    by 0x1D906D: btor_mem_realloc (in /home/user/boolector-plain)
==25740==    by 0x12B1B2: boolector_get_failed_assumptions (in /home/user/boolector-plain)
==25740==    by 0x1CA6D2: read_command_smt2 (in /home/user/boolector-plain)
==25740==    by 0x1CC289: parse_smt2_parser (in /home/user/boolector-plain)
==25740==    by 0x16C6FD: btor_parse (in /home/user/boolector-plain)
==25740==    by 0x128F87: boolector_main (in /home/user/boolector-plain)
==25740==    by 0x541AB96: (below main) (libc-start.c:310)
==25740== 
==25740== 
==25740== HEAP SUMMARY:
==25740==     in use at exit: 0 bytes in 0 blocks
==25740==   total heap usage: 1,193 allocs, 1,194 frees, 47,978 bytes allocated
==25740== 
==25740== All heap blocks were freed -- no leaks are possible
==25740== 
==25740== For counts of detected and suppressed errors, rerun with: -v
==25740== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)

Used version

$ boolector --version
3.0.1-pre

Steps to reproduce

boolector  btor_delete.txt

Termination callback and boolector_pop()

It seems that the result from the termination callback is "sticky"/"permanent" even across push/pop. Meaning that if the termination callback ever returns nonzero (indicating to terminate), then all future calls to boolector_sat() will terminate without even bothering to call the termination callback - even if boolector_pop() is used to revert to a previous state. I'm not sure if this is an intended feature or not. For my use case, I would prefer if boolector_pop() would reset the termination state, so that the termination callback would be checked again for future operations after the pop.

Here's a code example of the behavior I'm observing:

#include <boolector.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>

int32_t myterm(void* arg) {
  static bool first_time = true;
  if (first_time) {
    first_time = false;
    printf("returning 1\n");
    return 1;  // terminate the first time
  } else {
    printf("returning 0\n");
    return 0;  // then let it run indefinitely
  }
}

const char* describe_satresult(int32_t satresult) {
  switch (satresult) {
    case BOOLECTOR_SAT: return "SAT";
    case BOOLECTOR_UNSAT: return "UNSAT";
    case BOOLECTOR_UNKNOWN: return "UNKNOWN";
    default: return "unrecognized return code";
  }
}

int main(int argc, char* argv[]) {
  Btor* btor = boolector_new();
  boolector_set_opt(btor, BTOR_OPT_INCREMENTAL, 1);
  boolector_set_term(btor, &myterm, NULL);

  printf("Boolector version: %s\n", boolector_version(btor));

  // just a bunch of nonsense so that the sat() query is nontrivial
  BoolectorSort sort = boolector_bitvec_sort(btor, 1024);
  BoolectorNode* bv0 = boolector_var(btor, sort, "bv0");
  BoolectorNode* bv1 = boolector_var(btor, sort, "bv1");
  BoolectorNode* sum = boolector_var(btor, sort, "sum");
  BoolectorNode* zero = boolector_zero(btor, sort);
  boolector_assert(btor, boolector_not(btor, boolector_eq(btor, sum, zero)));
  boolector_assert(btor, boolector_eq(btor, sum, boolector_add(btor, bv0, bv1)));
  BoolectorNode* bv2 = boolector_slice(btor, bv0, 1023, 512);
  BoolectorNode* bv3 = boolector_slice(btor, bv0, 511, 0);
  boolector_assert(btor, boolector_ugt(btor, bv2, bv3));
  BoolectorNode* bv4 = boolector_concat(btor, bv2, boolector_add(btor, bv2, bv3));

  boolector_push(btor, 1);
  boolector_assert(btor, boolector_ugt(btor, bv4, bv1));
  printf("first result: %s\n", describe_satresult(boolector_sat(btor)));
  boolector_pop(btor, 1);

  printf("second result: %s\n", describe_satresult(boolector_sat(btor)));
}

In this example, we have a termination callback which terminates the first query, but (theoretically) lets all future queries continue indefinitely. In main(), we make two calls to boolector_sat(), expecting the first to be terminated. After the first call is terminated, we use boolector_pop() to return to an earlier state and check for satisfiability there.

The output I get from running this code is

Boolector version: 3.2.0
returning 1
first result: UNKNOWN
second result: UNKNOWN

which indicates that both queries were terminated. Furthermore, the termination callback only prints once, indicating that the second call to boolector_sat() never even checked the termination callback. This is the behavior I'm wondering whether it's intended or a bug.

My intended use case is to implement per-sat()-call query timeouts. So, even if one query times out and is terminated by the callback, I'd like the ability to boolector_pop() and continue working with a different set of constraints. It's possible that the termination callback mechanism is not the correct tool for this purpose - if there's a different tool that would work better, I'd love to hear about it.

Boolector crashes when printing constant array

I'm not sure it's the same issue, but Boolector keeps crashing when I try to verify a formula with const_array.

This is a reduced trace; it crashes when trying to dump the const_array node right after creating it:
btor.trace.txt

It happens with the latest release and with cad16b1. When I try it with a debug version, it fails the following assertion:

$ ~/tools/boolector/build/bin/btoruntrace -s btor.trace 
btoruntrace: /home/mgadelha/tools/boolector/src/dumper/btordumpsmt.c:602: expand_lambda: Assertion `static_rho' failed.
Aborted (core dumped)

I'm using lingeling only.

Originally posted by @mikhailramalho in #75 (comment)

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.