5 research outputs found

    Computing change of invariants to support software evolution

    Get PDF
    Software is always evolving. In the recent years, the development community has shifted towards Agile development paradigm resulting in faster release cycle. This emphasis on speed is, generally, accompanied by an increase in the number of bugs and reduced focus on updating non-functional software artifacts like specification document. Recent studies have found that developers find it difficult to determine whether a change might break code elsewhere in the program, resulting in 25% of bugs fixes to be incorrect or buggy. A method to capture the semantic changes between different versions of a program is vital in understanding the impact of the change and in preventing bugs. An invariant is a condition that is always true at a given program point. Invariants are used to specify the requirements and desired behavior of a program at any program point. The difference in invariants between different program versions can be used to capture the changes made to the program. In this thesis, we use the change of invariants as a way to capture the semantic changes over different program versions. We designed a static demand-driven algorithm for automatically computing the change of invariants between different versions of a program. To evaluate the algorithm and its ability to capture semantic changes over different program versions, we built a prototype framework called Hydrogen. Our experimental results show that Hydrogen is able to compute the change of invariants between different versions of the programs, and the computed change of invariants can be used for understanding changes and generating assertions to prevent similar bugs in future

    Reproducing Failures in Fault Signatures

    Full text link
    Software often fails in the field, however reproducing and debugging field failures is very challenging: the failure-inducing input may be missing, and the program setup can be complicated and hard to reproduce by the developers. In this paper, we propose to generate fault signatures from the failure locations and the original source code to reproduce the faults in small executable programs. We say that a fault signature reproduces the fault in the original program if the two failed in the same location, triggered the same error conditions after executing the same selective sequences of failure-inducing statements. A fault signature aims to contain only sufficient statements that can reproduce the faults. That way, it provides some context to inform how a fault is developed and also avoids unnecessary complexity and setups that may block fault diagnosis. To compute fault signatures from the failures, we applied a path-sensitive static analysis tool to generate a path that leads to the fault, and then applied an existing syntactic patching tool to convert the path into an executable program. Our evaluation on real-world bugs from Corebench, BugBench, and Manybugs shows that fault signatures can reproduce the fault for the original programs. Because fault signatures are less complex, automatic test input generation tools generated failure-inducing inputs that could not be generated by using the entire programs. Some failure-inducing inputs can be directly transferred to the original programs. Our experimental data are publicly available at https://doi.org/10.5281/zenodo.5430155

    Analyzing code fragments for faults

    Get PDF
    It appears to be a fact of life that no matter how much effort is spent on testing a program, software defects are continually introduced and removed during the development process. Numerous static and dynamic code analysis based techniques exist to help the developers quickly locate and fix these faults. However, in spite of existence of advanced techniques like path-sensitive static analysis tools, fuzzers, automated fault localization, and program repairs, a significant amount of developer's time is still spent in locating, understanding and fixing faults. In this thesis, we developed code fragment analysis techniques to address these challenges. The code fragments consists of noncontinuous statements extracted from the original programs, with respect to some desired property. These code fragments can then be made executable to help gain further insight on the property. First, we identified a set of challenges for extracting and building such statements and devised solutions for them. Then, we used our findings to automatically validate path-sensitive static analysis warnings by converting the paths reported by the tools into code fragments. These code fragments are then dynamically executed to check for the existence of the static warnings reported by the tools. We found that code fragments are able to validate static warnings by exposing their dynamic symptoms. Hence, we created as-small-as-possible executable code fragments that can reproduce the faults called fault signatures. We found that the smaller size and complexity of the fault signatures helped fuzzers to generate crashing inputs for faults that are harder to reproduce using the original programs. As the next step, we generated fault signatures for crashes reported by fuzzers. We then used them to identify "unique" faults and deduplicate the crashing inputs reported by the fuzzers. We found that using fault signatures correctly grouped the crashing inputs for unique faults and outperformed the state-of-the-art fuzzer based deduplication methods by as much as 75 times. Finally, we analyzed features of code fragments and used diffs generated from vulnerability fixing patches to actively train a machine learning model that identifies statements that contribute towards the bug fix. This model was then used to produce a large dataset of line-level vulnerability labels that can be used by other deep-learning based approaches for tasks like identifying vulnerable lines, bug detection, and fault localization. We found that using our dataset improved the performance of LineVul, a state-of-the-art vulnerability detection model, in terms of both the number of detected vulnerable functions/statements and their accuracy

    Computing change of invariants to support software evolution

    No full text
    Software is always evolving. In the recent years, the development community has shifted towards Agile development paradigm resulting in faster release cycle. This emphasis on speed is, generally, accompanied by an increase in the number of bugs and reduced focus on updating non-functional software artifacts like specification document. Recent studies have found that developers find it difficult to determine whether a change might break code elsewhere in the program, resulting in 25% of bugs fixes to be incorrect or buggy. A method to capture the semantic changes between different versions of a program is vital in understanding the impact of the change and in preventing bugs. An invariant is a condition that is always true at a given program point. Invariants are used to specify the requirements and desired behavior of a program at any program point. The difference in invariants between different program versions can be used to capture the changes made to the program. In this thesis, we use the change of invariants as a way to capture the semantic changes over different program versions. We designed a static demand-driven algorithm for automatically computing the change of invariants between different versions of a program. To evaluate the algorithm and its ability to capture semantic changes over different program versions, we built a prototype framework called Hydrogen. Our experimental results show that Hydrogen is able to compute the change of invariants between different versions of the programs, and the computed change of invariants can be used for understanding changes and generating assertions to prevent similar bugs in future.</p
    corecore