{ "cells": [ { "cell_type": "markdown", "id": "f5ef9c15", "metadata": {}, "source": [ "# The Debugging Book" ] }, { "cell_type": "markdown", "id": "84988848", "metadata": {}, "source": [ "## Sitemap\n", "While the chapters of this book can be read one after the other, there are many possible paths through the book. In this graph, an arrow _A_ → _B_ means that chapter _A_ is a prerequisite for chapter _B_. You can pick arbitrary paths in this graph to get to the topics that interest you most:\n" ] }, { "cell_type": "code", "execution_count": 1, "id": "0af20351", "metadata": { "execution": { "iopub.execute_input": "2025-01-22T08:34:45.293344Z", "iopub.status.busy": "2025-01-22T08:34:45.293246Z", "iopub.status.idle": "2025-01-22T08:34:45.358045Z", "shell.execute_reply": "2025-01-22T08:34:45.357638Z" } }, "outputs": [], "source": [ "# ignore\n", "from bookutils import InteractiveSVG" ] }, { "cell_type": "code", "execution_count": 2, "id": "c3056e06", "metadata": { "execution": { "iopub.execute_input": "2025-01-22T08:34:45.359619Z", "iopub.status.busy": "2025-01-22T08:34:45.359531Z", "iopub.status.idle": "2025-01-22T08:34:45.363068Z", "shell.execute_reply": "2025-01-22T08:34:45.362854Z" } }, "outputs": [ { "data": { "text/html": [ "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "Tracer\n", "\n", "\n", "\n", "\n", "Tracing Executions\n", "\n", "\n", "\n", "\n", "\n", "Debugger\n", "\n", "\n", "\n", "\n", "How Debuggers Work\n", "\n", "\n", "\n", "\n", "\n", "Tracer->Debugger\n", "\n", "\n", "\n", "\n", "\n", "Assertions\n", "\n", "\n", "\n", "\n", "Asserting\n", "Expectations\n", "\n", "\n", "\n", "\n", "\n", "Tracer->Assertions\n", "\n", "\n", "\n", "\n", "\n", "DeltaDebugger\n", "\n", "\n", "\n", "\n", "Reducing Failure-\n", "Inducing Inputs\n", "\n", "\n", "\n", "\n", "\n", "Tracer->DeltaDebugger\n", "\n", "\n", "\n", "\n", "\n", "StatisticalDebugger\n", "\n", "\n", "\n", "\n", "Statistical\n", "Debugging\n", "\n", "\n", "\n", "\n", "\n", "Tracer->StatisticalDebugger\n", "\n", "\n", "\n", "\n", "\n", "DynamicInvariants\n", "\n", "\n", "\n", "\n", "Mining Function\n", "Specifications\n", "\n", "\n", "\n", "\n", "\n", "Tracer->DynamicInvariants\n", "\n", "\n", "\n", "\n", "\n", "ChangeDebugger\n", "\n", "\n", "\n", "\n", "Isolating Failure-\n", "Inducing Changes\n", "\n", "\n", "\n", "\n", "\n", "DeltaDebugger->ChangeDebugger\n", "\n", "\n", "\n", "\n", "\n", "DDSetDebugger\n", "\n", "\n", "\n", "\n", "Generalizing Failure\n", "Circumstances\n", "\n", "\n", "\n", "\n", "\n", "DeltaDebugger->DDSetDebugger\n", "\n", "\n", "\n", "\n", "\n", "PerformanceDebugger\n", "\n", "\n", "\n", "\n", "Debugging\n", "Performance Issues\n", "\n", "\n", "\n", "\n", "\n", "DeltaDebugger->PerformanceDebugger\n", "\n", "\n", "\n", "\n", "\n", "Repairer\n", "\n", "\n", "\n", "\n", "Repairing Code\n", "Automatically\n", "\n", "\n", "\n", "\n", "\n", "DeltaDebugger->Repairer\n", "\n", "\n", "\n", "\n", "\n", "StatisticalDebugger->PerformanceDebugger\n", "\n", "\n", "\n", "\n", "\n", "StatisticalDebugger->Repairer\n", "\n", "\n", "\n", "\n", "\n", "Intro_Debugging\n", "\n", "\n", "\n", "\n", "Introduction to\n", "Debugging\n", "\n", "\n", "\n", "\n", "\n", "Intro_Debugging->Tracer\n", "\n", "\n", "\n", "\n", "\n", "Slicer\n", "\n", "\n", "\n", "\n", "Tracking \n", "Failure Origins\n", "\n", "\n", "\n", "\n", "\n", "Intro_Debugging->Slicer\n", "\n", "\n", "\n", "\n", "\n", "Tracking\n", "\n", "\n", "\n", "\n", "Tracking Bugs\n", "\n", "\n", "\n", "\n", "\n", "Intro_Debugging->Tracking\n", "\n", "\n", "\n", "\n", "\n", "ChangeCounter\n", "\n", "\n", "\n", "\n", "Where the Bugs are\n", "\n", "\n", "\n", "\n", "\n", "Tracking->ChangeCounter\n", "\n", "\n", "\n", "\n", "\n" ], "text/plain": [ "" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# ignore\n", "InteractiveSVG(filename='PICS/Sitemap.svg')" ] }, { "cell_type": "markdown", "id": "71610d6b", "metadata": {}, "source": [ "## [Table of Contents](index.ipynb)\n", "\n", "\n", "### [Part I: Whetting Your Appetite](01_Intro.ipynb)\n", "\n", "In this part, we introduce the topics of the book.\n", "\n", "#### [Tours through the Book](Tours.ipynb)\n", "\n", "#### [Introduction to Debugging](Intro_Debugging.ipynb)\n", "\n", "In this book, we want to explore _debugging_ - the art and science of fixing bugs in computer software. In particular, we want to explore techniques that _automatically_ answer questions like: Where is the bug? When does it occur? And how can we repair it? But before we start automating the debugging process, we first need to understand what this process is.\n", "\n", "### [Part II: Observing Executions](02_Observing.ipynb)\n", "\n", "In this part, we show how to observe executions – by tracing, by interactively debugging, and more.\n", "\n", "#### [Tracing Executions](Tracer.ipynb)\n", "\n", "In this chapter, we show how to _observe program state during an execution_ – a prerequisite for logging and interactive debugging. Thanks to the power of Python, we can do this in a few lines of code.\n", "#### [How Debuggers Work](Debugger.ipynb)\n", "\n", "Interactive _debuggers_ are tools that allow you to selectively observe the program state during an execution. In this chapter, you will learn how such debuggers work – by building your own debugger.\n", "#### [Asserting Expectations](Assertions.ipynb)\n", "\n", "In the previous chapters on [tracing](Tracer.ipynb) and [interactive debugging](Debugger.ipynb), we have seen how to observe executions. By checking our observations against our expectations, we can find out when and how the program state is faulty. So far, we have assumed that this check would be done by _humans_ – that is, us. However, having this check done by a _computer_, for instance as part of the execution, is infinitely more rigorous and efficient. In this chapter, we introduce techniques to _specify_ our expectations and to check them at runtime, enabling us to detect faults _right as they occur_.\n", "\n", "### [Part III: Flows and Dependencies](03_Dependencies.ipynb)\n", "\n", "In this part, we show how to follow where specific (faulty) values come from, and why they came to be.\n", "\n", "#### [Tracking Failure Origins](Slicer.ipynb)\n", "\n", "The question of \"Where does this value come from?\" is fundamental for debugging. Which earlier variables could possibly have influenced the current erroneous state? And how did their values come to be?\n", "\n", "### [Part IV: Reducing Failure Causes](04_Reducing.ipynb)\n", "\n", "In this part, we show how to narrow down failures by systematic experimentation.\n", "\n", "#### [Reducing Failure-Inducing Inputs](DeltaDebugger.ipynb)\n", "\n", "A standard problem in debugging is this: Your program fails after processing some large input. Only a _part_ of this input, however, is responsible for the failure. _Reducing_ the input to a failure-inducing minimum not only eases debugging – it also helps in understanding why and when the program fails. In this chapter, we present techniques that _automatically reduce and simplify failure-inducing inputs to a minimum_, notably the popular _Delta Debugging_ technique.\n", "#### [Isolating Failure-Inducing Changes](ChangeDebugger.ipynb)\n", "\n", "\"Yesterday, my program worked. Today, it does not. Why?\" In debugging, as elsewhere in software development, code keeps on changing. Thus, it can happen that a piece of code that yesterday was working perfectly, today no longer runs – because we (or others) have made some changes to it that cause it to fail. The good news is that for debugging, we can actually _exploit_ this version history to narrow down _the changes that caused the failure_ – be it by us or by others.\n", "\n", "### [Part V: Abstracting Failures](05_Abstracting.ipynb)\n", "\n", "In this part, we show how to determine abstract failure conditions.\n", "\n", "#### [Statistical Debugging](StatisticalDebugger.ipynb)\n", "\n", "In this chapter, we introduce _statistical debugging_ – the idea that specific events during execution could be _statistically correlated_ with failures. We start with coverage of individual lines and then proceed towards further execution features.\n", "#### [Mining Function Specifications](DynamicInvariants.ipynb)\n", "\n", "In the [chapter on assertions](Assertions.ipynb), we have seen how important it is to _check_ whether the result is as expected. In this chapter, we introduce a technique that allows us to _mine_ function specifications from a set of given executions, resulting in abstract and formal _descriptions_ of what the function expects and what it delivers.\n", "#### [Generalizing Failure Circumstances](DDSetDebugger.ipynb)\n", "\n", "One central question in debugging is: _Does this bug occur in other situations, too?_ In this chapter, we present a technique that is set to _generalize_ the circumstances under which a failure occurs. The DDSET algorithm takes a failure-inducing input, breaks it into individual elements. For each element, it tries to find whether it can be replaced by others in the same category, and if so, it _generalizes_ the concrete element to the very category. The result is a _pattern_ that characterizes the failure condition: \"The failure occurs for all inputs of the form `( * )`\".\n", "#### [Learning from Failures](Alhazen.ipynb)\n", "\n", "Given the many executions we can generate, it is only natural that these executions would also be subject to _machine learning_ in order to learn which features of the input (or the execution) would be associated with failures.\n", "#### [Debugging Performance Issues](PerformanceDebugger.ipynb)\n", "\n", "Most chapters of this book deal with _functional_ issues – that is, issues related to the _functionality_ (or its absence) of the code in question. However, debugging can also involve _nonfunctional_ issues, however – performance, usability, reliability, and more. In this chapter, we give a short introduction on how to debug such nonfunctional issues, notably _performance_ issues.\n", "\n", "### [Part VI: Automatic Repair](06_Repairing.ipynb)\n", "\n", "In this part, we show how to automatically repair code.\n", "\n", "#### [Repairing Code Automatically](Repairer.ipynb)\n", "\n", "So far, we have discussed how to track failures and how to locate defects in code. Let us now discuss how to _repair_ defects – that is, to correct the code such that the failure no longer occurs. We will discuss how to _repair code automatically_ – by systematically searching through possible fixes and evolving the most promising candidates.\n", "\n", "### [Part VII: Debugging in the Large](07_In_the_Large.ipynb)\n", "\n", "In this part, we show how to track failures, changes, and fixes.\n", "\n", "#### [Tracking Bugs](Tracking.ipynb)\n", "\n", "So far, we have assumed that failures would be discovered and fixed by a single programmer during development. But what if the user who discovers a bug is different from the developer who eventually fixes it? In this case, users have to _report_ bugs, and one needs to ensure that reported bugs are systematically _tracked_. This is the job of dedicated _bug tracking systems_, which we will discuss (and demo) in this chapter.\n", "#### [Where the Bugs are](ChangeCounter.ipynb)\n", "\n", "Every time a bug is fixed, developers leave a trace – in the _version database_ when they commit the fix, or in the _bug database_ when they close the bug. In this chapter, we learn how to _mine these repositories_ for past changes and bugs, and how to _map_ them to individual modules and functions, highlighting those project components that have seen most changes and fixes over time.\n", "\n", "### [Appendices](99_Appendices.ipynb)\n", "\n", "This part holds notebooks and modules that support other notebooks.\n", "\n", "#### [Error Handling](ExpectError.ipynb)\n", "\n", "The code in this notebook helps with handling errors. Normally, an error in notebook code causes the execution of the code to stop; while an infinite loop in notebook code causes the notebook to run without end. This notebook provides two classes to help address these concerns.\n", "#### [Timer](Timer.ipynb)\n", "\n", "The code in this notebook helps with measuring time.\n", "#### [Timeout](Timeout.ipynb)\n", "\n", "The code in this notebook helps in interrupting execution after a given time.\n", "#### [Class Diagrams](ClassDiagram.ipynb)\n", "\n", "This is a simple viewer for class diagrams. Customized towards the book.\n", "#### [Inspecting Call Stacks](StackInspector.ipynb)\n", "\n", "In this book, for many purposes, we need to look up a function's location, source code, or simply definition. The class `StackInspector` provides a number of convenience methods for this purpose.\n" ] } ], "metadata": { "ipub": { "bibliography": "fuzzingbook.bib" }, "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.12.8" }, "toc": { "base_numbering": 1, "nav_menu": {}, "number_sections": true, "sideBar": true, "skip_h1_title": true, "title_cell": "", "title_sidebar": "Contents", "toc_cell": false, "toc_position": {}, "toc_section_display": true, "toc_window_display": true }, "toc-autonumbering": false }, "nbformat": 4, "nbformat_minor": 5 }