To begin with, each time we need to make a transition between the symbolic and the concrete domains (in either way), we ``flip a coin'' and we either make the transition to the opposite domain or not, according to the outcome. By doing so, we end up symbolically analyzing in part all three components of the system (kernel, libraries and application), and not just the unit (as was happening in the S2E paper). This approach results in the tree being expanded in depth and height by all three components, but not always (the ``when" is governed by the coin). By doing so, we give the user the possibility to acquire some (thus not total) knowledge about what could go wrong in the whole system. There are several optimizations that can be made to this approach. First, the ``flipping of the coin'' does not necessarily have to be completely random. We can adjust a threshold during execution, depending on how much time symbolic analysis take. By doing so, if we see that in general the symbolic analysis takes too long, we can ``flip a coin'' that favors, e.g., two out of three times the concrete execution and one time the symbolic analysis. Secondly, if we see that the symbolic analysis ``gets stuck'' somewhere (e.g., in the case where unbounded symbolic variables are encountered in loops) we can fall back to the last switching point, and concretely execute the corresponding loop. Moreover, we can keep statistics about the symbolic execution of the system functions. By doing so, we can keep track of which functions take long to symbolically analyze, and decide that we will concretely execute those functions from now on, while ``keeping the coin'' for other functions and code segments that can be quickly symbolically analysed. As a final idea, we could also use information from the API specifications of specific functions (when such information is available) to govern the switching between concrete and symbolic modes. |
One-Pagers > OP11: A New Consistency Model >