{'fraction_non_alphanumeric': 0.03858693638620281, 'fraction_numerical': 0.006076099440554259, 'mean_word_length': 4.41726041144004, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 2, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 10, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
PAC Learning-Based Verification and Model Synthesis

We introduce a novel technique for verification and model synthesis of sequential programs. Our technique is based on learning a regular model of the set of feasible paths in a program, and testing whether this model contains an incorrect behavior. Exact learning algorithms require checking equivalence between the model and the program, which is a difficult problem, in general undecidable. Our learning procedure is therefore based on the framework of probably approximately correct (PAC) learning, which uses sampling instead and provides correctness guarantees expressed using the terms error probability and confidence. Besides the verification result, our procedure also outputs the model with the said correctness guarantees. Obtained preliminary experiments show encouraging results, in some cases even outperforming mature software verifiers.


INTRODUCTION
Formal verification of software aims to prove software properties through rigorous mathematical reasoning. Consider, for example, the C statement assert(x > 0) specifying that the value of the variable x must be positive. If the assertion is formally verified, it cannot be violated in any possible execution during runtime. Formal verification techniques are, however, often computationally expensive. Although sophisticated heuristics have been developed to improve scalability of the techniques, formally verifying real-world software is still considered to be impractical.
A common technique to ensure quality in industry is software testing. Errors in software can be detected by exploring different software behaviors via injecting various testing vectors. Testing cannot, however, guarantee software is free from errors. Consider again the assertion assert(x > 0). Unless all system behaviors are explored by testing vectors, it is unsound to conclude that the value of x is always positive. Various techniques have been proposed to improve its coverage, but it is an inherent feature of software testing that it cannot establish program properties conclusively.
In this paper, we propose a novel learning-based approach that aims to balance scalability and coverage of existing software engineering techniques. In order to be scalable, as for software testing, our new technique explores only a subset of all program behaviors. Moreover, we apply machine learning to generalize observed program behaviors for better semantic coverage. Our technique allows software engineers to combine scalable testing with high-coverage formal analyses and improve the quality assurance process. We hope that this work reduces the dichotomy between formal and practical software engineering techniques.
In our technical setting, we assume programs are annotated with program assertions. A program assertion is a Boolean expression intended to be true every time it is encountered during program execution. Given a program with assertions, our task is to check whether all assertions evaluate to true on all possible executions. In principle, the problem can be solved by examining all program executions. It is, however, prohibitive to inspect all executions exhaustively since there may be infinitely many of them. One way to simplify the analysis is to group the set of program executions to paths of a control flow graph.
A control flow graph (CFG) is derived from the syntactic structure of a program source code. Each execution of a program corresponds to a path in its control flow graph. One can therefore measure the completeness of software testing on CFGs. Line coverage, for instance, gives the ratio of explored edges in the CFG of the tested program, while branch coverage is the ratio of explored branches of this CFG. Note that such syntactic measures of code coverage approximate program executions only very roughly. Executions that differ in the number of iterations in a simple program loop have the same line and branch coverages, although their computation may be drastically different. A full syntactic code coverage does not necessarily mean all executions have been explored by software testing.
Observe that program executions traversing the same path in a CFG perform the same sequence of operations (although maybe with different values). Consider a path corresponding to a program execution in a CFG. Such a path can be characterized by the sequence of decisions that the execution took when traversing conditional statements in the CFG. We call a sequence of such decisions a decision vector. A decision vector is feasible if it represents one or more (possibly infinitely many) program executions, and infeasible if it represents a sequence of branching choices than can never occur in an execution of the program. To check whether all assertions evaluate to true on all executions, it suffices to examine all feasible decision vectors and check they do not represent any assertion-violating program execution. Although feasibility of a decision vector can be determined by using an offthe-shelf Satisfiability Modulo Theories (SMT) solver, the set of feasible decision vectors is in general difficult to compute exactly. Therefore, we apply algorithmic learning, in particular the framework of probably approximately correct learning, to construct a regular approximation of this set.
Within the framework of probably approximately correct (PAC) learning with queries, learning algorithms query about target concepts to construct hypotheses. The constructed hypotheses are then validated by sampling. If a hypothesis is invalidated by witnessing a counterexample, learning algorithms refine the invalidated hypothesis by the witness and more queries. If, on the other hand, a hypothesis conforms to all samples, PAC learning algorithms return the inferred hypothesis with statistical guarantees. In our approach, we adopt a PAC learning algorithm with queries to infer a regular language approximation to the set of feasible decision vectors of a program.
To grasp the statistical guarantees provided by PAC learning, consider the task of checking defects in a large shipment using uniform sampling. Because of the size of the shipment, it is impractical to check every item. We instead want to know, with a given confidence δ, if the defect probability is at most ǫ. This can be done by selecting r (to be determined later) randomly chosen items. If all chosen items are good, the method reports that the defect probability is at most ǫ. We argue the simple method can err with probability at most 1 − δ. Suppose r randomly chosen items are tested without any defect, but the defect probability is, in fact, more than ǫ. Under this thesis, the probability that r random items are all good is lower than (1 − ǫ) r . That is, the method is incorrect with probability lower than (1 − ǫ) r . Take r such that (1−ǫ) r < 1−δ. The simple method reports incorrect results with probability at most 1 − δ; we equivalently say the result of the method is PAC (ǫ, δ)-correct.
Using a similar argument, it can be shown that our PAC learning algorithm returns a regular set approximating the set of feasible decision vectors of the program with the error probability ǫ and confidence δ of our choice. If the inferred set contains no decision vector representing an assertionviolating program execution, our technique concludes the verification with statistical guarantees about correctness.
Our learning-based approach finds a balance between formal analysis and testing. Rather than exploring program behaviors exhaustively, our technique infers an approximation of the set of feasible decision vectors by queries and sampling. Although the set of feasible decision vectors is in general not computable, PAC learning with queries may still return a regular set approximation of it with a quantified guarantee. Such an approximate model with statistical guarantees can be useful for program verification. With an approximate model that is PAC (ǫ, δ)-correct and proved to be free from assertion violation, one can conclude that the program is also PAC (ǫ, δ)-correct. The statistical guarantees are different from syntactic code coverages in software testing. Recall that our application of PAC learning works over decision vectors. Decision vectors in turn represent program executions. When our technique does not find any assertion violation, the statistical guarantees give software engineers a semantic coverage about program executions. Along with conventional syntactic coverages, such information may help software engineers estimate the quality of software.
We implement a prototype, named Pac-Man (PAC learning-based Model synthesizer and ANalyzer), of our procedure based on program verifiers CPAchecker, CBMC, and the concolic tester Crest. We evaluate the prototype on the benchmarks from the recursive category of SV-COMP 2015 [1]. The results are encouraging-we can find all errors that can be found by Crest. We also provide quantified guarantee accompanied by a faithful approximate model for several examples that are challenging for program verifiers and concolic testers. This approximate model can later be reused, e.g., for verifying the same program with a different set of program assertions.
Our contributions are summarized in the following: • We show the PAC learning algorithm can be applied to synthesize a faithful approximate model of the set of feasible decision vectors of a program. Such a model can be useful in many different aspect of program verification (cf. Section 12 for details). We believe it is not hard to adopt our approach to handle different type of systems (e.g., black box systems) and to obtain approximate models on a different level of abstraction (e.g., on a function call graph). • We develop a verification procedure based on the approximate model obtained from PAC learning. The procedure integrates the advantages of both testing and verification. It uses testing techniques to collect samples and catch bugs. The PAC learning algorithm generalizes the samples to obtain an approximate model that can then be analyzed by verification techniques for statistical guarantees.

PRELIMINARIES
Let X be the set of program variables and F the set of function and predicate symbols. We use X ′ for the set {x ′ | x ∈ X }. The set T [X , F] of transition formulae consists of well-formed first-order logic formulae over X , X ′ , and F. For a transition formula f ∈ T [X , F] and n ∈ N, we use f n to denote the formula obtained from f by replacing all free variables x ∈ X and x ′ ∈ X ′ with x n and x n+1 respectively.
We represent a program with a single procedure using a control flow graph. (Section 9 extends the notion to programs with multiple procedures and procedure calls.) A control flow graph (CFG) is a graph G = (V, E, vi, vr, Ve, XFP ) where V = V b ∪Vs is a finite set of nodes consisting of disjoint sets of branching nodes V b and sequential nodes Vs, vi ∈ V is the initial node, vr ∈ Vs is the return node, Ve ⊆ V is the set of error nodes, XFP ⊆ X is the set of formal parameters, and E is a finite set of edges such that E ⊆ V × T [X , F] × V and the following conditions hold: • for any branching node • for any non-return sequential node vs ∈ Vs \{vr}, there is exactly one node v ′ ∈ V with (vs, f, v ′ ) ∈ E; and • for the return node vr ∈ Vs, there is no Assume, moreover, that the two successors v ′ 0 and v ′ 1 of the branching node v are ordered. Intuitively, the '1' corresponds to the if branch and the '0' corresponds to the else branch. We call v ′ 0 and v ′ 1 the 0-successor and 1-successor of v respectively. Similarly, f0 and f1 are called the 0-transition and 1-transition formulae of v. Note that the definition of a CFG allows us to describe nondeterministic choice, which is commonly used to model the environment. To be more specific, a nondeterministic choice from a branching node v can be represented by defining both the 0-transition and 1-transition formulae of v as x∈X x = x ′ .
A path in the CFG G is a sequence π = v0, f1, v1, f2, v2, . . . , fm, vm such that v0 = vi and (vj , fj+1, vj+1) ∈ E for every 0 ≤ j < m. The path π is feasible if the path formula m k=1 f k k is satisfiable. It is an error path if vj ∈ Ve for some 0 ≤ j ≤ m. The task of our analysis is to check whether G contains a feasible error path.
A sequence w = a1a2 · · · an with aj ∈ {0, 1} for 1 ≤ j ≤ n is called a word over {0, 1}. The length of w is |w| = n. The word of length 0 is the empty word λ. We also use w[j] to denote the j-th symbol aj. If u, w are words over {0, 1}, u · w denotes the concatenation of u and w. A language L over {0, 1} is a set of words over {0, 1}.
We introduce the function decision that maps a path π of G to a sequence of decisions made in the branching nodes traversed by π. Formally, decision is a function from paths to words over {0, 1} defined recursively as follows: decision( v0, f1, v1, f2, v2, . . . , fm, vm ) = decision( v0, f1 ) · decision( v1, f2, v2, . . . , fm, vm ) such that For a path π, decision(π) is the decision vector of π. We lift decision to a set of paths Π and define decision vectors of Π as decision(Π) = {decision(π) | π ∈ Π}. A finite automaton (with λ-moves) A is a tuple A = (Σ, Q, qi, ∆, F ) consisting of a finite alphabet Σ, a finite set of states Q, an initial state qi ∈ Q, a transition relation ∆ ⊆ Q × (Σ ∪ {λ}) × Q, and a set of accepting states F ⊆ Q. A transition (q, λ, q ′ ) ∈ ∆ is called a λ-transition. A word w over Σ is accepted by A if there are states q0, . . . , qm ∈ Q and symbols (or λ's) a1, . . . , am ∈ (Σ ∪ {λ}), such that w = a1 · · · am, for every 0 ≤ j < m there is a transition (qj , aj+1, qj+1) ∈ ∆, and further q0 = qi and qm ∈ F . The language of A is defined as L(A) = {w | w is accepted by A}. A language R is regular if R = L(A) for some finite automaton A. The finite automaton A is deterministic if its transition relation is a function from Q × Σ to Q. For any finite automaton A, there exists a deterministic finite automaton (DFA) B such that L(A) = L(B).

OVERVIEW
In this section, we give an overview of our verification procedure. Let G be a CFG of a program. Our goal is to check PAC Automata Learning Algorithm (Section 4)

Mechanical Teacher
Resolving Membership Queries (Section 6) Resolving Equivalence Queries by Sampling (Section 5)

Found a feasible error decision vector
The system is PAC (ǫ, δ)-correct Representation of the language decision(Π) of all feasible decision vectors in G is not so easy. In general, this language may not be regular or even computable. In our procedure, we construct a candidate finite automaton C that approximates decision(Π), the set of feasible decision vectors of G. We infer C using a probably approximately correct (PAC) online automata learning algorithm [2]. The use of PAC learning provides us with statistical guarantees about the correctness of C-we can claim that C is PAC (ǫ, δ)correct, i.e., with confidence δ, the deviation of L(C) from decision(Π) is less than ǫ (we give a proper explanation of the terms in Section 4).
On the other hand, it is straightforward to convert G to a finite automaton B accepting the set of all error decision vectors decision(B). Intuitively, states of B correspond to nodes of G, the initial state of B corresponds to the initial node of G, and accepting states of B correspond to G's error nodes. An edge from a sequential node is translated to a λ-transition. For a branching node, the edges to its 0-and 1-successors are translated to transitions over symbols 0 and 1 respectively (cf. Section 7).
A high-level overview or our learning procedure is given in Figure 1 (the procedure is similar in structure to the one of [2]). It consists of two main components: The learning algorithm asks the teacher two kinds of questions: membership ("Is a given decision vector feasible?") and equivalence ("Is a given candidate finite automaton PAC (ǫ, δ)correct?") queries. The teacher resolves the queries, at the same time observing whether some of the tested decision vectors corresponds to a feasible error path. By posing these queries, either the learning algorithm iteratively constructs a PAC (ǫ, δ)-correct approximation of decision(Π) or our procedure finds a feasible error decision vector.
As with other online learning-based techniques, we need to devise a mechanical teacher that answers queries from the learning algorithm. Checking membership queries (i.e., membership in the set decision(Π) of feasible decision vectors) is relatively easy-for example, given a decision vector d, we obtain its corresponding path π by unfolding the CFG G according to d, and use an off-the-shelf solver to decide whether π is feasible or not (cf. Section 6).
When the automata learning algorithm infers a candidate finite automaton C, we need to check whether L(C) approximates decision(Π), i.e., whether C is PAC (ǫ, δ)-correct. Since we cannot compare decision(Π) with L(C) directly, we employ the sampling-based approximate equivalence technique of PAC learning. While generally unsound, the technique still provides statistical guarantee about the correctness of the inferred model (details are given in Section 5).

PAC AUTOMATA LEARNING
Here we explain the PAC automata learning algorithm that we use to find an approximation to decision(Π). Classical PAC automata learning algorithm cannot be used directly for the purpose of program verification. It has to be modified to handle the case when the program contains an error. The classical PAC automata learning algorithm was obtained from modifying the requirement of the exact automata learning algorithm [3]. Our modification follows the same route. In this section, we first describe the classical "exact" automata learning algorithm of regular languages and then describe how to modify it for verification. Then we explain how to relax the requirement of an exact automata learning algorithm to infer an approximation to decision(Π).

Exact Learning of Regular Languages
Suppose R is a target regular language such that its description is not directly accessible. Automaton learning algorithms [2,18,14,5] infer automatically a finite automaton AR recognizing R. The setting of an online learning algorithm assumes a teacher who has access to R and can answer the following two types of queries: • Membership query Mem(w): is the word w a member of R, i.e., w ∈ R?
• Equivalence query Equ(C): is the language of the finite automaton C equal to R, i.e., L(C) = R? If not, what is a counterexample to this equality (a word in the symmetric difference of L(C) and R)?
The learning algorithm will then construct a finite automaton AR such that L(AR) = R by interacting with the teacher. Such an algorithm works iteratively: In each iteration, it performs membership queries to get information about R from the teacher. Using the results of the queries, it proceeds by constructing a candidate automaton C and, finally, makes an equivalence query Equ(C). If L(C) = R, the algorithm terminates with C as the resulting finite automaton AR. Otherwise, the teacher returns a word w distinguishing L(C) from the target language R. The learning algorithm uses w to modify the conjecture for the next iteration. The mentioned learning algorithms are guaranteed to find a finite automaton AR recognizing R using a number of queries polynomial to the number of states of the minimal DFA recognizing R. In the rest of the paper, we denote "online automata learning" simply as "automata learning".

Learning for Program Verification
Under the context of program verification, it may be the case that decision(Π) ∩ L(B) = ∅; in such a case, our procedure should return a feasible error path in the program. This is very similar to the setting of learning-based verification [11,9], where the learning algorithm is modified to return a counterexample in case the system contains an error.
We modified the used learning algorithm in a similar way. To be more specific, when the classical learning algorithm poses an equivalence query Equ(C), we first check whether there exists a decision vector c such that c ∈ L(C) ∩ L(B) and then test if c ∈ decision(Π).

In case that the two tests identified a decision vector
c such that c ∈ L(C) ∩ L(B) and c ∈ decision(Π), then c is in the difference of L(C) and decision(Π) and hence a valid counterexample for the classical learning algorithm to refine the next conjecture automaton C.
2. In case that the two tests identified a decision vector c such that c ∈ L(C) ∩ L(B) and c ∈ decision(Π), then c is a feasible error decision vector and we report c to the user.
3. In case that L(C) ∩ L(B) = ∅, the modified learning algorithm poses an equivalence query Equ(C) to the teacher.
Given a teacher answers membership and equivalence queries about decision(Π), the modified automata learning algorithm has the following properties. Observe that when the program does not contain any error, the behavior of the modified learning algorithm is identical to the classical one and hence is still an exact automata learning algorithm. Next we explain how to relax the requirements of the exact automata learning algorithm to obtain a PAC automata learning algorithm that is suitable for program verification.

Probably Approximately Correct Learning
The techniques for learning automata we just discussed in the previous section assume a teacher who has the ability to answer equivalence queries. Such an assumption is, however, invalid in our procedure. Checking decision(Π) = L(C) can be undecidable. Angluin showed in [3] that if we substitute equivalence queries with sampling, we can still make statistical claims about the difference of the inferred set and the target set.
Assume that we are given a probability distribution D over the elements of a universe U, and a hypothesis in the form In the hypothesis, the term Prob w∈U | D [¬ϕ(w)] denotes the probability that the formula ϕ(w) is invalid for w chosen randomly from U according to the distribution D. We call ǫ the error parameter and use the term confidence to denote the least probability that the hypothesis is correct. We say In the setting of automata learning, the considered universe is Σ * and the target regular language is R ⊆ Σ * . The task of an equivalence query Equ(C) is changed from checking exact equivalence, which we can express as checking that ∀w ∈ Σ * : w / ∈ R ⊖ L(C) (we use ⊖ to denote the symmetric difference operator), to checking approximate equivalence, i.e., checking whether the formula In other words, we check whether Prob w∈Σ * | D [w ∈ R ⊖ L(C)] ≤ ǫ with confidence δ. For a fixed R and a candidate C, we say that The teacher checks the PAC (ǫ, δ)-correctness of C by picking r samples according to D and testing if all of them are not in R ⊖ L(C). For the i-th equivalence query of the learning algorithm, the number of samples qi needed to establish that C is PAC (ǫ, δ)-correct is given by Angluin in [2] as (1) Since the inferred set C is guaranteed to be PAC (ǫ, δ)correct, this approach is termed probably approximately correct (PAC) learning [21].

RESOLVING EQUIVALENCE QUERIES BY SAMPLING
The current section discusses how to design a mechanism that the teacher can use for equivalence queries to provide the PAC (ǫ, δ)-correctness guarantee, as defined in Section 4. Given a probability distribution D over the set of feasible decision vectors decision(Π), we can use D to give a formal definition of the quality of a candidate automaton C. In particular, we use as a measure the probability with which a decision vector chosen randomly from decision(Π) (according to the distribution D) is contained in C.
A sampling mechanism offering such a distribution must satisfy the following conditions: 1. Only decision vectors in decision(Π) are sampled.
2. The samples are independent and identically distributed (IID), i.e., the distribution is fixed and the probability of sampling a particular element does not depend on the previously picked samples.
In this paragraph, we introduce the random input sampling mechanism. We treat all nondeterministic choices and formal parameters of the program as input variables and assume that all input variables are over finite domains. Each set of initial values of input variables yields a path in the CFG of the program. Based on this observation, random input sampling works by (1) picking uniformly at random a set of initial values for input variables of the program and then (2) obtaining the corresponding decision vector by traversing the CFG of the program using the picked values. The sampling mechanism forms a distribution such that the probability of a decision vector d being chosen is proportional to the number of program paths corresponding to d.
The issue of random input sampling is that it suffers from the well-known fact that coverage of input values is not a good approximation of program path coverage. Depending on the sizes of input domains of program variables, some paths might have only a negligible probability of being selected-for instance, given two 64-bit integers x and y, the probability of taking the true branch in the test x == 0 && y == 0 is equal to 2 −128 . The situation gets even worse for input variables over unbounded domains. Even with an extremely high coverage rate of input variables' values, many paths may still not be explored, while other are explored repeatedly. In order to get a sampling mechanism with a better distribution over program paths, we developed a technique that randomly explores program's paths using a concolic tester [12,19,7], which is an efficient means for exploring decision vectors corresponding to rare paths.
We describe the technique and prove its properties in the rest of this section.

Concolic Testing
Concolic testing is a testing approach that explores paths in the CFG of a program while searching for bugs. The algorithm begins with a decision vector generated by randomly picked input values. Then, it finds the next decision vector by flipping some decision made in the chosen path and obtains new input values that lead the program execution according to the new path. This mechanism gives rare paths a much greater chance to be explored. The selection of which decision should be flipped depends on the used search strategy of the tester.
In our procedure, we use the concept of a batched sample. A batched sample is defined as a set of decision vectors of the size k (where k is a given parameter) obtained from a concolic tester by exploring k paths using its search strategy. We denote D k the distribution over elements of (Σ * ) k obtained in this way. Our procedure restarts the concolic tester after taking every batched sample. The previous point gives us the guarantee that the probability of taking each batched sample remains the same during the execution our procedure (we assume that the concolic tester does not keep state information between its restarts), and that the distribution is IID and, therefore, meets condition 2 defined above. The principal functioning of concolic testers guarantees that condition 1 is also met.

Generalized Stochastic Equivalence
In this section, we show that our sampling mechanism using batched samples has the property required for the PAC (ǫ, δ)-correctness guarantee of the learning algorithm given in Section 4.3.
Recall that for the set of feasible decision vectors of a program decision(Π) and a candidate automaton C inferred by the learning algorithm using some distribution D over Σ * , if the teacher gives the answer yes for the equivalence query Equ(C), it guarantees with confidence δ that Since our sampling technique uses batched samples from the universe U k = (Σ * ) k w.r.t. the distribution D k instead of elements of Σ * and distribution D, we need to change the provided guarantee in our modification of the learning algorithm. If our algorithm answers yes, it guarantees that with confidence δ (we hereafter use the term PAC (ǫ, δ)correct to denote this form of guarantee). When a teacher receives an equivalence query Equ(C), it uses a concolic tester to obtain qi (given in (1)) batch samples. For each batch sample S, the teacher checks if there exists a decision vector w ∈ S such that w / ∈ L(C) (by definition w ∈ decision(Π)). The teacher answers yes if there is no such w. Otherwise, the teacher checks if w is an error decision vector and either reports w as a feasible error decision vector or returns w to the learning algorithm to refine the next conjecture.
The following lemma shows that if we use the number qi batched samples for testing the equivalence, we obtain the modified PAC (ǫ, δ)-correctness guarantee from (3).

Lemma 2. Let ǫ and δ be the error and confidence parameters, and R be the target language. If no decision vector w /
∈ L(C) is found in the qi batched samples, then it holds that C is PAC (ǫ, δ)-correct.
Based on the fact that L(C) ∩ L(B) = ∅ (the property of the modified learning algorithm in Section 4.2) and the lemma above, we obtain the following corollary.
Corollary 1. Let ǫ and δ be the error and confidence parameters, and R be the target language. If no decision vector w / ∈ L(C) is found in qi batched samples, then it holds that the program is PAC (ǫ, δ)-correct.

RESOLVING MEMBERSHIP QUERIES
In this section, we describe how a membership query Mem(d) in the algorithm in Figure 1 is discharged by the teacher. Let Π be the set of feasible paths of a CFG G. When the learning algorithm asks a membership query Mem(d), the teacher needs to check whether the decision vector d is in the set of feasible decision vectors decision(Π).
Recall that π is a feasible path if and only if ϕ = m j=1 fj j is satisfiable. Therefore, the teacher can simply construct the formula ϕ from the path π and check its satisfiability using an off-the-shelf constraint solver.
Alternatively, the teacher can check feasibility by translating the path into a sequence of program statements (with conditions removed and substituted by assertions on the values of the conditions) and asking a symbolic executor or software model checker whether the final line of the constructed program is reachable. The alternative option is easier to implement but usually suffers from some performance penalty.

ERROR DECISION VECTORS
Let B be the set of error paths in a CFG. In this section, we show how we construct a finite automaton accepting the set of all error decision vectors decision(B) of the given CFG. This automaton will later be intersected with the automaton representing the set of feasible paths to determine whether the CFG contains a feasible error path.
Definition 1. Let G = (V b ∪ Vs, E, vi, vr, Ve, XFP ) be a CFG. We define the error trace automaton for G as the finite automaton B = ({0, 1}, V b ∪ Vs, vi, ∆E, Ve) where ∆E is defined as follows: Informally, B contains a state for every node and a transition for every edge of G. It reads a symbol in each state corresponding to a branching node and performs λ-transitions for states corresponding to sequential nodes. For every error node, B reads all remaining symbols and accepts the input word. It is straightforward to see that B accepts exactly the set of decision vectors corresponding to error paths in G. In Section 9, we describe an extension of our procedure to programs with procedure calls. Because representing the set of error decision vectors using a finite automaton is in this setting imprecise, the section also discusses an extension that represents the set of error paths in a program with procedure calls using pushdown automata.

THE MAIN PROCEDURE
We summarize our procedure in this section. Let G be the CFG of the verified program, k be the size of a batched sample, ǫ be the error parameter, and δ be the confidence parameter. The goal of our procedure is to either find a feasible error decision vector of G or show that G is PAC (ǫ, δ)correct. In the latter case, we also accompany our answer with a PAC (ǫ, δ)-correct regular representation of the set of feasible decision vectors of G. Let Π be the set of feasible paths of G, D k be the distribution defined by our sampling mechanism (cf. Section 5), and L(B) be the set of error decision vectors of G (cf. Section 7).
A detailed flow chart of our procedure can be found in Figure 2. First, the bottom part of the figure describes our learning algorithm. We extend the online automata learning algorithm with two additional tests for verification, as described in Section 4.2. In particular, when the automata learning algorithm outputs a candidate C, before sending teacher the equivalence query Equ(C), we first test whether L(C) contains a feasible error decision vector c. In case it does, we report c as an error. Otherwise, in the case c is both in L(C) and L(B) but is not feasible, we return c to the learning algorithm to further refine the conjecture.
The top part of the figure describes our design of a mechanical teacher. The task of the teacher is to answer queries from the learning algorithm. Membership queries of the form Mem(w) can be answered by constructing the path corresponding to the decision vector w and the associated path formula, which is then solved using a constraint solver (cf. Section 6). Equivalence queries, on the other hand, are discharged using a concolic tester by checking whether there is a decision vector s in the set of batched samples S such that it does not belong to the language of C (cf. Section 5). If no such a decision vector exists, we conclude that the program is PAC (ǫ, δ)-correct. Otherwise, we test whether s ∈ L(B); if this holds, we report that we have found a feasible error decision vector. In the case s / ∈ L(B), it holds that s is a feasible decision vector in decision(Π) but not in the language of the current conjecture L(C). If this happens, we return s to the automata learning algorithm to refine the conjecture and continue with the next iteration of the learning loop.
In general, our procedure is not guaranteed to terminate. When the procedure terminates and reports an error (either by the teacher or the learning algorithm), a feasible error  Figure 2: A detailed flow chart of our verification procedure decision vector is found and the program is reported to be incorrect. If the teacher approves an approximate finite automaton C, our procedure reports that C is an approximate model of decision(Π) w.r.t. the PAC (ǫ, δ)-correctness guarantee, which, in turn, implies that the program is PAC (ǫ, δ)correct. From Lemma 2, we have the following theorem Theorem 1. Let ǫ and δ be the error and confidence parameters respectively and Π be the set of feasible paths of a given CFG G. If our procedure terminates with an approximate finite automaton C, the program is PAC (ǫ, δ)-correct.
Moreover, we obtain the following corollary.
Corollary 2. Suppose our procedure reports a program P is PAC (ǫ, δ)-correct. If we run the concolic tester with the same search strategy and batch size used in our procedure on P , with confidence δ, the concolic tester will find an error with a probability less than ǫ.
Thanks to the properties of the modified automata learning algorithm, when decision(Π) is a regular set, our algorithm is guaranteed to terminate and either (1) return a counterexample c ∈ L(B) ∩ decision(Π) or (2) find an approximate model of decision(Π) that is disjoint with L(B).

HANDLING PROCEDURE CALLS
In this section, we extend our formalism of CFGs to handle programs with multiple procedures. We use a PDA to represent error decision vectors in this setting. The issue of using finite automata to represent error decision vectors in the said setting is that when returning from a procedure call, a finite automaton cannot remember an unbounded number of return points (in the case of recursive procedures). Therefore, an overapproximation, such as a nondeterministic jump to any possible return point, needs to be used. The said overapproximation is, however, too imprecise and yields numerous spurious errors. In contrast, PDAs can represent the set of error decision vectors precisely.
On the other hand, we still use a finite automaton to represent the approximation of the set of feasible decision vectors decision(Π). As a consequence, except that we need to use PDA operations instead of FA operations and handle procedure calls in the membership queries, all other components remain unchanged for the setting of multiple procedures.

Extending CFGs with Procedure Calls
Assume the set of procedure names P. A CFG with calls (CFGC) is defined as a graph G = (V, E, vi, vr, Ve, XFP ) where V, vi, vr, Ve, and XFP are defined in the same way as for a CFG, and is an extended set of edges that apart from local CFG edges (v, f, v ′ ) for f ∈ T [X , F] also contains procedure call edges e = (v, (p, gin , gout ), v ′ ) for (p, gin , gout ) ∈ P × T [X , F] × T [X , F] and sequential nodes v. The gin and gout components of e correspond to formulae for passing actual values to formal parameters of p (formula gin ) and passing the return value of p back to the caller procedure (formula gout ).
In this extension, we define a program as a set of CFGCs prog = {G1, . . . , Gn} together with a (bijective) mapping cfgc prog : P → prog that assigns procedure names to CFGCs. We abuse notation and use prog to denote cfgc prog , i.e., prog (p) denotes the CFGC of a procedure p in a program prog . We assume that all CFGCs in prog have pairwise disjoint sets of nodes, and further assume an entry point main ∈ P.
In this paragraph, we give an informal description of how we extend the definition of a path from a program consisting of single CFG to a program consisting of a set of CFGCs and a dedicated entry point. Given a procedure call edge e in a CFGC G, we call the inlining of e in G the CFGC G ′ obtained from G by substituting e with the CFGC of the called procedure. We use prog to denote the set of CFGs obtained from prog (main) by performing all possible (even recursively called) sequences of inlinings, and removing any left procedure call edges from the output CFGCs. A path in prog is then a sequence π = v0, f1, v1, f2, v2, . . . , fm, vm such that there exists a CFG G ′ ∈ prog for which it holds that π ∈ G ′ .

Encoding Error Decision Vectors with Pushdown Automata
In this section, we describe how we construct the PDA encoding the set of error traces in the considered extension. The general idea is the same as the one for the use of finite automata (described in Section 7). The main difference is that we add jumps between CFGCs (corresponding to procedure call edges), which use the stack to remember which state the PDA should return to after the procedure call terminates.
In the following, given a CFGC G = (V, E, vi, vr, Ve, XFP ), we use V (G), E(G), . . . , XFP (G) to denote the corresponding components of G, and, moreover, we use Vs(G) and V b (G) to denote the set of sequential and branching nodes of G respectively. Consider a program prog = {G1, . . . , Gn}.

IMPLEMENTATION
We created a prototype tool Pac-Man that implements the verification procedure described in this paper. The tool uses several third-party libraries and tools. First, it uses CIL (C Intermediate Language) [17] to convert the verified C program to a set of CFGCs, from which we construct the error trace pushdown automaton BP . Further, we use the libAMoRE++ library [16,6] to perform operations of automata, such as testing their membership and emptiness, or computing their intersection.
For learning automata, we use the implementation of various learning algorithms within the libalf library [6]. Membership queries are discharged using a concolic tester, mentioned as an alternative option in Section 6. Given a decision vector, our tool uses the CFG of the program to generate a path corresponding to the decision vector. The path is passed in the form of a sequence of program statements to the software model checker CPAchecker [4], which checks its feasibility. It is possible to switch the model checker with other checkers, such as CBMC [10].
To deal with equivalence queries, we modified the concolic tester Crest [7] to generate a batch of k decision vectors, as described in Section 5. As Crest may fail to generate the decision vector of a program execution when the execution terminates abnormally, we modified Crest to take a finite prefix of the execution in this case. One issue of Crest that we encountered is that when it processes a condition composed using Boolean connectives, it expands the condition into a cascade of if statements corresponding to the Boolean expression, making the program longer and harder to learn. We addressed this by modifying Crest so that it can process conditions with Boolean connectives inside without expanding them, and in this way we increased the performance and precision of the analysis.
We also implemented the following three optimizations to improve the performance of the prototype.

Intersection with Bad Automaton.
Recall that our modified learning algorithm (described in Section 4.2) first checks whether the intersection of the language of the conjecture L(C) and the bad language L(BP ) is empty. Checking emptiness of a PDA is, however, more difficult than that of a finite automaton. To speed up the procedure, we build a finite automaton BO that overapproximates the error language and always first checks whether L(C) ∩ L(BO) = ∅, which is an emptiness test for finite automata. We check L(C) ∩ L(BP ) = ∅ only for the cases that the previous test fails.

Counterexample from the Learning Algorithm.
When an equivalence query returns a counterexample c, automata learning algorithms usually do not guarantee that c is not a valid counterexample in the next conjecture automaton. In our preliminary experiments, we found out that it happens very often that the mechanical teacher returns the same counterexample in several consecutive iterations. Therefore, we decided to check whether c is still a valid counterexample (by a membership query) for the learning algorithm before proceeding to the emptiness test. In the case c is valid, it will be immediately returned to the learning algorithm to refine the conjecture.

Handling Membership Queries.
The main bottleneck of our approach is the time spent for membership queries. In our implementation, the software model checker CPAchecker is used to check whether a path is feasible. For each membership query, if we invoke CPAchecker with a system call, a Java virtual machine will be created and the components of CPAchecker need to be loaded, which is very time consuming. To make membership queries more efficient, we modified CPAchecker to run in a server mode so that it can check more than a single path without being re-invoked.

EXPERIMENTS
This section presents our experimental results to justify the claims made in this paper. We evaluated the performance of our prototype using the recursive category of SV-

Comparison of Learning Algorithms
We evaluated our approach with different automata learning algorithms implemented within the libalf library. There are five active online automata learning algorithms implemented in libalf: Angluin's L * [2], L * -columns, Kearns/Vazirani (KV) [14], Rivest/Schapire (RS) [18], and NL * [5]. Among the search strategies provided by Crest, we chose the random branch strategy. The experimental results are in Table 1.  The results show that KV is the algorithm with the best performance-it solved 21 out of the 24 examples. Our technique solves more than any participant in the recursive category of SV-COMP 2015 but the winner. The main reason for the performance difference is that KV uses a tree-based data structure to store query results. Compared to other learning algorithms that use table-based structures, KV requires much less number of membership queries to maintain the consistency of the tree-based structure. For all learning algorithms except RS, the number of error paths found by the emptiness test of the intersection of the conjecture and the bad automaton is more than that found by Crest. In our experiments, the time spent for membership queries is usually the performance bottleneck. Table 1 shows that membership queries took 30 % of the total execution time for KV and at least 58 % for other algorithms.

Comparison of Search Strategies
We also evaluated the performance of our algorithm against different Crest search strategies. According to [7], the most efficient ones are random branch strategy (RBS for short) and control-flow directed strategy (CDS for short). Therefore, we tested the performance of our prototype using these two strategies. We selected KV as the learning algorithm in this experiment. The results are shown in Table 2. Table 2 shows that although the average time for taking one sample with CDS is more than with RBS, the total time is less. The main reason is that CDS explores untouched branching points more aggressively than RBS but requires more overhead. Our experiments conform the results in [7].

Evaluation of CREST with Restarts
To justify our modification to the PAC (ǫ, δ)-correctness guarantee given in Section 5.2, we show in the experiment below that running Crest in batches does not decrease its bug-hunting capabilities. We compared the performance of Table 3: Evaluation of Crest with and without restart. For each example, the number of batches and the number of iterations used to find bugs are obtained respectively from the worst run in scenario (1) and from the best run in scenario (2).

Settings Examples
Batch Size 10 Never Restart  Ackermann02  batch 3  iteration 14  Addition02  batch 1  iteration 2  Addition03  Timeout  Timeout  BallRajamani-SPIN2000 batch 1  iteration 1  EvenOdd03  batch 1  iteration 2  Fibonacci04  batch 4  iteration 2  Fibonacci05  Timeout  Timeout  McCarthy91 batch 1 iteration 2  Table 3, we chose RBS as the search strategy. We also tried the experiments with the CFG strategy and got a similar result. We list the worst result for scenario (1) and the best result for scenario (2) that we received in our three runs. We found out that the worst runs in scenario (1) can still find with a little overhead all bugs found by the best runs in scenario (2).

Evaluating Quality of Learned Automata
Besides the performance in terms of the running time, we also compared the quality of the learned automata produced by our prototype using the two strategies for the 15 successfully verified bug-free examples. To evaluate the quality of the learned automata, for each example, we ran Crest with the given search strategy to get 100 batched samples and tested how many of the them are all accepted by the learned automaton. The average values of the runs are shown in Table 4 where evaluation strategies are strategies used to generate the testing batched samples. The table shows that the quality of the automata learned with the two strategies is almost the same. Also, observe that the guarantee of our procedure is that the sample coverage is higher than 90 %. Our experimental results show that the quality of the automata produced by our procedure matches the theoretical expectations.
Finally, we tested how many words generated by Crest are not covered in the automata learned with the KV algorithm and RBS. Again, we ran Crest with RBS in two scenarios: (1) restart after each 10 decision vectors and (2) never restart. For each learned automaton (there were 15) and each scenario, we generated 1000 decision vectors and checked how many of them are accepted by the automaton. In total, for scenario (1), we observed 1487 accepted batches of size 10 (for the total of 15 000 tested vectors), yielding the correctness 99.13 %. For scenario (2), we observed 14 977 accepted vectors, for the correctness 99.86 %. We notice that no matter which strategy we use, the learned automaton accepts over 99 % of the decision vectors produced by Crest.

DISCUSSION
There are several advantages of having a program model with statistical guarantees. For instance, the model can be reused for verifying a different set of properties of the program. Assume that the new property to be verified is described as an error path automaton B ′ and C is the learned automaton. If L(B ′ ) ∩ L(C) = ∅, we verified the program with the new property and the same PAC (ǫ, δ)-correctness guarantee. For the case that there exists a decision vector w ∈ L(B ′ ) ∩ L(C), we test whether w is feasible and either report that w is a feasible error decision vector w.r.t. B ′ or continue the learning algorithm with w as a counterexample for refining the next conjecture.
In this paper we focus on checking validity of program assertions. The verification step is handled by making an intersection of the conjecture automaton C and the error path automaton B and testing its emptiness. This procedure can be generalized to more sophisticated safety properties by replacing the tests L(C) ∩ L(B) = ∅ and s ∈ L(B) with other tests. For example, we can check the property "the program contains at most 10 consecutive 1-decisions on any path" with a statistical guarantee of the correctness of the received answer. By extending the alphabet {0, 1} with program labels, one can also check temporal properties related to those labels, e.g., "label A should be reached within 10 decisions after label B is reached." One possible extension of our work is to learn sequences of feasible function calls instead of decision vectors. This might lead to a more compact model in contrast to the current approach. However, in this case the alphabet of the model to be learned will be all function names in the program, which is usually much larger than 2, the size of the alphabet in our work. Moreover, in this setting, it is much harder to answer membership queries; a program path composed of function calls might perform a complex traversal through loops and branches in between the calls, making the problem of checking feasibility of a program path already undecidable.
One benefit of our approach is that, in principle, it can be extended to black box system verification and model synthesis. By observing the behavior of the environment, we may find some pattern (e.g., some statistical distribution) of the inputs and then, based on that, design a sampling mechanism. Under the assumption that the behavior of the environment remains unchanged, we can verify or synthesize the model of the system w.r.t. the given sample distribution.

RELATED WORKS
Exact automata learning algorithm was first proposed by Angluin [2] and later improved by many people [2,18,14,5]. The concept of probably approximately correct (PAC) learning was first proposed by Valiant in his seminal work [21]. The idea of turning an exact learning algorithm to a PAC learning algorithm can be found in Section 1.2 of [3].
Applying PAC learning to testing has been considered before [22,13]. The work in [13] considers a program that manipulates graphs and check if the output graph of the program has properties such as being bipartite, k-colorable, etc. Our work considers assertion checking, which is more general than the specialized properties. The work [22] considers more theoretical aspects of the problem. The author estimates the maximal number of queries required to infer a model of a black box machine. The context is quite different, e.g., the work does not discuss how to sample according to some distribution efficiently to produce the desired guarantee (bounded path coverage) as we do in this paper.
The L * algorithm has been used to infer the model of error traces of a program. In [8], instead of decision vectors, the authors try to learn the sequences of function calls leading to an error. Their teacher is implemented using a bounded model checker and hence can only guarantee correctness up to a given bound. The authors do not make use of the PAC learning technique as we did in this work.
Both our approach and statistical model checking [20,15,23] provide statistical guarantees. As mentioned in the introduction, statistical model checking assumes a given model while our technique generates models of programs with statistical guarantee. Those models can be analyzed using various techniques and reused for verifying different properties.

APPENDIX A. AN INLINING IN A CFGC
Consider a procedure call edge e = (v, (p, gin , gout), v ′ ) of Gj = (Vj, Ej, vij , vrj , Vej , XFP j ) for 1 ≤ j ≤ n. Further assume that prog (p) = G k = (V k , E k , v ik , v rk , V ek , XFP k ) for 1 ≤ k ≤ n. The inlining of e in prog is the program prog # = {G1, . . . , Gj−1, G # j , Gj+1, . . . , Gn} such that G # j = (Vj ∪ V # k , E # , vij , vrj, Vej ∪ V # ek , XFP j ) where V # k is a set of fresh nodes (i.e., V # k is disjoint from the set of nodes of any CFGC in prog ) and V # ek ⊆ V # k . Moreover, there exist bijections σ : V # k → V k and σe : V # ek → V ek such that σe ⊆ σ. The set of edges E # is defined as ) ∈ E k }. Let inln(prog) be the smallest (potentially infinite) set that contains prog and is closed w.r.t. inlinings in main, i.e., if inln(prog) contains a program prog # with a procedure call edge e in the CFGC prog # (main), it also contains the inlining of e in prog # . We abuse notation and use σ uniformly to denote for all programs prog # ∈ inln(prog) the mapping of the nodes of the CFGCs in prog # to their original nodes in prog (for nodes V of prog , we assume that σ|V = id, i.e., that the restriction of σ to V is the identity relation). We denote as prog the set of CFGs (without procedure call edges) obtained by starting from the set inln(prog), collecting the CFGCs of main functions of all inlinings of prog into the set M = {prog # (main) | prog # ∈ inln(prog)}, and, finally, transforming the CFGCs of M into CFGs of prog by substituting each procedure call edge (v # , (p # , g # in , g # out ), v #′ ) with the edge (v # , ff, v #′ ).