Expose memory support objects as queryable memory resources

By exposing the memory support object as a queryable memory resource, and utilizing the characteristics of execution tracking, a handle is provided to represent the memory that is overwritten during the life cycle of the memory support object, the problem of difficulty in effectively dealing with undesirable software behavior in the prior art is solved, and efficient debugging and correction are achieved.

CN113939809BActive Publication Date: 2025-06-03MICROSOFT TECHNOLOGY LICENSING LLC
View PDF 2 Cites 0 Cited by

Patent Information

Application Number
CN202080039358.9
Authority / Receiving Office
CN · China
Patent Type
Patents(China)
Current Assignee / Owner
Priority Date
2019-05-29
Filing Date
2020-04-21
Publication Date
2025-06-03
Estimated Expiration
2040-04-21

AI Technical Summary

Technical Problem

Existing historical debugging tools are difficult to effectively deal with undesirable software behaviors that occur in software development, especially when tracking and correcting these behaviors, and it is difficult to reproduce and determine the root cause.

Method used

By exposing the memory support object as a queryable memory resource, leveraging the rich characteristics of execution tracking, a handle is provided to logically represent the memory overwritten during the life cycle of the memory support object, and queries based on execution time are supported.

Benefits of technology

It realizes effective query and management of memory covered in the life cycle of memory support objects, improves debugging efficiency, and simplifies tracking and correction of undesired software behavior.

✦ Generated by Eureka AI based on patent content.

Smart Images

  • Figure CN113939809B_ABST
    Figure CN113939809B_ABST
Patent Text Reader

Abstract

The present disclosure relates to using execution tracing to process queries for an object during the object's life cycle. Embodiments support memory objects that existed during a previous execution of an entity based on a trace identifier. Identify a handle that is used to logically represent memory that is overwritten by an object during the life cycle of the object. Identify a plurality of associations represented by the handle. These associations identify memory addresses that are overwritten by the object during the life cycle of the object. Each association represents at least: (i) a memory address that is overwritten by the object during the life cycle of the object, and (ii) an execution time at which the memory address is overwritten by the object during the life cycle of the object. Process a query for the handle. The query includes a query based on execution time, and processing the query includes comparing the execution time in the query with the (multiple) execution times represented in the association.
Need to check novelty before this filing date? Find Prior Art

Description

Background Art

[0001] Tracking and correcting unwanted software behavior in software code (commonly referred to as "debugging" the code) is a core activity in software development. Unwanted software behavior can include many things, such as execution crashes, runtime exceptions, slow execution performance, incorrect data results, data corruption, etc. Unwanted software behavior can be triggered by a variety of factors, such as data input, user input, race conditions (e.g., when accessing shared resources), etc. Given the diversity of triggers, unwanted software behavior can be rare and seemingly random, and extremely difficult to reproduce. Therefore, it can be very time-consuming and difficult for developers to identify a given unwanted software behavior. After an unwanted software behavior has been identified, determining its root cause(s) again can be both time-consuming and difficult.

[0002] One method that developers use to debug code is to use a "live" debugger. Typically, a live debugger attaches to the execution of a live process and enables developers to monitor and direct the forward execution of that process. For example, a live debugger can enable developers to set breakpoints that pause program execution when a specific instruction is reached, set watchpoints that pause program execution when a specific memory address is accessed, step through lines of code during execution, and so on.

[0003] An emerging form of diagnostic tool supports "historical" debugging (also known as "time travel" or "reverse" debugging), in which the execution of at least a portion of one or more program threads is recorded / tracked into one or more trace files (i.e., an execution trace). Using certain tracing techniques, the trace can contain very high-fidelity "bit-exact" historical trace data, which enables one or more recorded portions of the traced threads to be virtually "replayed" with high fidelity - even down to the granularity of individual instructions (e.g., machine code instructions, intermediate language code instructions, etc.). Thus, using bit-exact trace data, a "time travel" debugger enables developers to not only monitor and direct the forward emulation of the traced code (e.g., via breakpoints, watchpoints, stepping, etc.), but also monitor and direct the reverse emulation of the traced code (e.g., via reverse breakpoints, reverse watchpoints, reverse stepping, etc.). Therefore, developers can monitor and direct the execution of any part of the program before the trace.

[0004] Existing historical debugging tools expose memory as a flat structure, just as in live debugging. This means that the debugger can present the memory state at each given trace execution time point. Summary of the Invention

[0005] At least some of the embodiments described herein utilize the rich characteristics of execution tracing to expose memory - backed objects as queryable memory resources. In particular, the embodiments expose memory - backed objects as handles that generally represent an object (including all of its allocated memory over time), rather than just the address that points to the object at any given time. Thus, the embodiments herein facilitate processing queries against these handles and / or returning queries for these handles. These queries can determine which memory is covered by a given memory - backed object at any traced time point and over a period of time to enable various queries against the memory of an object as the object's memory dynamically changes during the object's life cycle.

[0006] Some embodiments relate to methods, systems, and computer program products for processing queries against the life cycle of memory - backed objects based on execution tracing. These embodiments identify memory - backed objects that existed during a previous execution of an entity from a trace of the previous execution of the entity. These embodiments identify a handle that is used to logically represent the memory that was covered by the memory - backed object during the life cycle of the memory - backed object in the previous execution of the entity, and identify a plurality of associated sets represented by the handle. These associations identify a plurality of memory addresses that were covered by the memory - backed object during the life cycle of the memory - backed object. Each association represents at least (i) a memory address that was covered by the memory - backed object during the life cycle of the memory - backed object, and (ii) an execution time at which the memory address was covered by the memory - backed object during the life cycle of the memory - backed object. These embodiments at least partially process a query against the handle. The query includes at least one query condition based on execution time, and processing the query includes comparing the execution time in the query with one or more execution times represented in the set of associations. Based on processing the query, these embodiments formulate a response to the query.

[0007] In other embodiments, a method, system, and computer program product for processing queries regarding the lifecycle of a memory support object based on execution tracing includes identifying, from a trace of a previous execution of an entity, memory addresses that were part of the previous execution of the entity during at least one execution time. Based on receiving a query regarding a memory address, these embodiments identify at least one memory support object associated with the memory address during at least one execution time, identify a handle that is used to logically represent memory that was overwritten by the memory support object during the lifecycle of the memory support object in the previous execution of the entity, and identify a set of associations represented by the handle. The set of associations identifies a plurality of memory addresses that were overwritten by the memory support object during the lifecycle of the memory support object. Each association represents at least (i) a memory address that was overwritten by the memory support object during the lifecycle of the memory support object, and (ii) an execution time during which the memory address was overwritten by the memory support object during the lifecycle of the memory support object. These embodiments process the query using at least in part the handle. The query includes at least one query condition based on execution time, and processing the query includes comparing the execution time in the query with one or more execution times represented in the set of associations. Based on processing the query, these embodiments formulate a response to the query.

[0008] This "Summary of the Invention" is provided to introduce a series of concepts in a simplified form that will be further described below in the "Detailed Description". This "Summary of the Invention" is not intended to identify key features or essential features of the claimed subject matter, nor is it intended to be used to help determine the scope of the claimed subject matter. Brief Description of the Drawings

[0009] To describe the manner in which the above and other advantages and features of the invention can be obtained, a more specific description of the invention briefly described above will be presented by reference to the specific embodiments thereof shown in the accompanying drawings. It should be understood that these drawings only depict typical embodiments of the invention and are therefore not considered to limit its scope, and thus the invention will be described and explained with additional features and details by using the drawings, in which:

[0010] Figure 1A An example computing environment is shown that facilitates processing queries regarding the lifecycle of a memory support object based at least on execution tracing;

[0011] Figure 1B An example is shown that provides details of possible components of a debugger;

[0012] Figure 2 An example computing environment is shown that includes multiple levels of caching;

[0013] Figure 3illustrates an example computing environment, where Figure 1A a computer system of Figure 1A is connected to one or more other computer systems via at least one network;

[0014] Figure 4 illustrates an example of a time travel debug trace;

[0015] Figure 5A illustrates an example of memory allocation including memory filling;

[0016] Figure 5B illustrates an example of memory allocation including gaps; and

[0017] Figure 6 illustrates a flowchart of an example method for processing queries regarding the lifecycle of memory - supported objects based on an execution trace. Detailed Description

[0018] At least some embodiments described herein utilize the rich characteristics of an execution trace to expose memory - supported objects as queryable memory resources. In particular, embodiments expose memory - supported objects as handles that generally represent an object (including all of its allocated memory over time), rather than just an address that points to the object at any given time. Thus, embodiments herein facilitate processing queries for and / or returning such handles. These queries can determine which memory is covered by a given memory - supported object at any traced point in time and over a period of time, enabling various queries regarding the memory of the object.

[0019] To achieve the above, Figure 1A illustrates an example computing environment 100a that facilitates processing queries regarding the lifecycle of memory - supported objects based at least on an execution trace. As shown, the computing environment 100a may include or utilize a special - purpose or general - purpose computer system 101, which includes computer hardware such as, for example, at least one processor 102 (e.g., generally responsible for the execution of application code), system memory 103 (e.g., generally providing at least temporary data storage), one or more computer storage media 104 (e.g., for storing application code and / or data), and at least one external communication channel 105 (e.g., a network interface card, or even just one or more wires / pins for communicating with one or more other computer systems). In an embodiment, each of the processor 102, system memory 103, storage medium 104, and communication channel 105 is communicatively coupled using at least one communication bus 106.

[0020] As Figure 1AAs shown, each processor 102 may include (among other things) one or more processing units 107 (e.g., processor cores) and at least one cache 108. Generally, each processing unit 107 loads and executes machine code instructions (e.g., machine code instructions of application 113) via cache 108. During the execution of these machine code instructions at one or more execution units 107b, the machine code instructions may use internal processor registers 107a as temporary storage locations and may read from and write to various locations in system memory 103 via cache 108. In an embodiment, the operation of each processor 102 is at least partially orchestrated by control logic 109. As will be understood by those of ordinary skill in the art, control logic 109 may include digital logic (e.g., a fixed arrangement of transistors; one or more programmed field programmable gate arrays; etc.) and / or stored executable instructions (e.g., processor microcode) executable by one or more components of processor 102.

[0021] Returning to cache 108, cache 108 temporarily caches portions of data stored in system memory 103; for example, cache 108 may include a "code" portion and a "data" portion, where the "code" portion caches the portion of system memory 103 that stores application code (e.g., the application code of application 113), and the "data" portion caches the portion of system memory 103 that stores application runtime data. If processing unit 107 needs data (e.g., code or application runtime data) that is not yet stored in cache 108, then processing unit 107 may initiate a "cache miss" to cause the needed data to be retrieved from a backing store (e.g., system memory 103, another cache, etc.). For example, in Figure 1A , the backing store of cache 108 may be system memory 103, so a cache miss in cache 108 may be supplied by system memory 103. Sometimes, data may be "evicted" from cache 108 back to its backing store (e.g., system memory 103), such as when the data is no longer needed in cache 108 or when more urgent data is needed in the cache.

[0022] While cache 108 may include a single cache, cache 108 may include multiple caches. To further explain this concept, Figure 2 an example environment 200 showing a multi-level cache is illustrated. In Figure 2 , there are two processors 201a and 201b (e.g., each corresponding to Figure 1A a different processor 102) and system memory 202 (e.g., corresponding to Figure 1Aof the system memory 103). In the example environment 200, each processor 201 includes four physical processing units (i.e., processing units A1 - A4 of processor 201a and processing units B1 - B4 of processor 210b, each of which can correspond to Figure 1A one of the processing units in processing unit 107). In the example environment 200, each processor 201 also includes (or is associated with) a three - level cache hierarchy. Environment 200 is merely an example cache layout and is not limited to the cache hierarchies in which the embodiments herein can operate. In environment 200, each processing unit includes (or is associated with) its own dedicated L1 cache (e.g., L1 cache "L1 - A1" in processor 201a for unit A1, L1 cache "L1 - A2" in processor 201a for unit A2, etc.). Each processor 201 also includes (or is associated with) two L2 caches (e.g., L2 cache "L2 - A1" in processor 201a that serves as a backup repository for L1 caches L1 - A1 and L1 - A2, L2 cache "L1 - A2" in processor 201a that serves as a backup repository for L1 caches L1 - A3 and L1 - A4, etc.). Finally, each processor 201 also includes (or is associated with) a single L3 cache (e.g., L3 cache "L3 - A" in processor 201a that serves as a backup repository for L2 caches L2 - A1 and L2 - A2, and L3 cache "L3 - B" in processor 201b that serves as a backup repository for L2 caches L2 - B1 and L2 - B2). As shown, system memory 202 serves as a backup repository for L3 caches L3 - A and L3 - B. In this arrangement, and depending on the cache implementation, a cache miss in the L1 cache can be supplied by its corresponding L2 cache, its corresponding L3 cache, and / or system memory 202; a cache miss in the L2 cache can be supplied by its corresponding L3 cache and / or system memory 202; a cache miss in the L3 cache can be supplied by system memory 202.

[0023] As shown by the arrows within each processing unit 201, when multiple cache layers are used, each processing unit can directly interact with the nearest layer (e.g., L1), although this is not always the case. In many implementations, data flows between the layers (e.g., the L3 cache interacts with system memory 103 and supplies data to the L2 cache, which in turn supplies data to the L1 cache). When a processing unit 201 performs a write, the caches are coordinated to ensure that a cache that affects data shared among multiple processing units no longer has it. This coordination is performed using a cache coherence protocol (CCP).

[0024] The caches in environment 200 can thus be considered "shared" caches. For example, each L2 and L3 cache serves multiple processing units within a given processor 201 and is thus shared by these processing units. The L1 caches in a given processor 201 can also generally be considered shared - even though each cache corresponds to a single processing unit - because separate L1 caches can coordinate with each other (i.e., via the CCP) to ensure consistency (i.e., such that the memory locations of each cache are considered consistent across all L1 caches). The L2 caches within each processor 201 can similarly be coordinated via the CCP. Additionally, if processor 201 supports hyper-threading, each individual L1 cache can be considered shared by two or more logical processing units and is thus "shared" even at the individual level.

[0025] As described above, when cache 108 includes multiple caches (as Figure 2 shown), processor 102 operates on cache 108 according to one or more CCPs. Generally, the CCP defines how to maintain consistency between the various caches when the respective processing units 107 of one or more processors 102 read and write data in the various caches, and how to ensure that the respective processing units 107 always read valid data from a given location in the cache. The CCP is generally related to and enables the memory model defined by the instruction set architecture (ISA) of the processor. Examples of popular ISAs include the x86 and x86_64 series architectures from INTEL, and the ARM architecture from ARM HOLDINGS.

[0026] Examples of common CCPs include the MSI protocol (i.e., Modified, Shared, and Invalid), the MESI protocol (i.e., Modified, Exclusive, Shared, and Invalid), and the MOESI protocol (i.e., Modified, Owned, Exclusive, Shared, and Invalid). Each of these protocols defines a state for a separate location (e.g., a line) in a shared cache (e.g., cache 108). A "Modified" cache location contains data that has been modified in the shared cache and is thus inconsistent with the corresponding data in the backing store (e.g., system memory 103 or another cache). When a location with a "Modified" state is evicted from the shared cache, the common CCP requires the cache to ensure that its data is written back to the backing store, or that another cache takes over that responsibility. A "Shared" cache location contains data that has not been modified from the data in the backing store, exists in a read-only state, and is shared by multiple processing units (e.g., two or more of processing units 107). The shared cache can evict this data without writing it to the backing store. An "Invalid" cache location does not contain valid data and can be considered empty and available for storing data from a cache miss. An "Exclusive" cache location contains data that matches the backing store and is used by only a single processing unit. It can change to a "Shared" state at any time (i.e., in response to a read request), or it can change to a "Modified" state when written to. An "Owned" cache location is shared by two or more processing units, but one of the processing units has the exclusive right to make changes to it. When that processing unit makes a change, it notifies the other processing units - because the notified processing units may need to invalidate or update based on the CCP implementation.

[0027] The storage medium 104 can store computer-executable instructions and / or data structures representing executable software components such as a tracer 110, a debugger 111, an emulator 112, and at least one application 113; correspondingly, during the execution of the software by the processor 102, one or more portions of these computer-executable instructions and / or data structures can be loaded into the system memory 103 (i.e., shown as tracer 110', debugger 111', emulator 112', and application 113'). Additionally, the storage medium 104 can store additional data such as at least one execution trace 114 (e.g., representing a trace of the execution of application 113 at processor 102).

[0028] If present, the tracer 110 can record or "trace" the execution of at least one application 113 (which can include user-mode code and / or kernel-mode code) into at least one trace 114. Thus, Figure 1AIt is also shown that the tracer 110 can be loaded into the system memory 103 (i.e., tracer 110'). The arrow between the tracer 110' and the trace 114' indicates that the tracer 110' can record trace data into the trace 114' (as shown, which can be held as the trace 114 on the storage medium 104). In an embodiment, the tracer 110 can record the execution of the application 113 when the application 113 is executed directly on the processor 102 and / or when the application 113 is executed indirectly on the processor 102 (e.g., via a managed runtime, virtual machine, emulator, etc.).

[0029] The computer system 101 can additionally or alternatively receive the trace 114 from another computer system (e.g., using the communication channel 105). For example, Figure 3 An example computing environment 300 is shown, where Figure 1A the computer system 101 is connected to one or more other computer systems 302 (i.e., computer systems 302a - 302n) via at least one network 301. As shown in the example 300, each computer system 302 includes Figure 1A a tracer 110 and an application 113. Thus, the computer system 101 can receive at least one trace 114 of one or more previous executions of the application 113 at one or more of these computer systems 302 via the network 301.

[0030] In some embodiments, the tracer 110 records a "bit - exact" trace of the execution of one or more threads of the application 113. As used herein, a bit - exact trace is a trace that includes sufficient data to enable code that was previously executed at one or more processing units 107 to be "replayed" in an emulator (e.g., emulator 112) such that it executes during replay at the replay time in substantially the same manner as it did during tracing. The tracer 110 can use a variety of methods to record a bit - exact trace. Some brief overviews of some methods are now summarized, but it should be understood that the embodiments herein can operate with traces 114 recorded using other methods. Additionally, optimizations can be applied to any of these methods that are not described herein for the sake of brevity.

[0031] In an embodiment, the tracing method used by the tracer 110 is based on the recognition that processor instructions (e.g., machine code instructions executed by the processing unit 107) generally fall into one of the following three categories: (1) instructions identified as "non-deterministic" because their output is not fully determined by the data in the general-purpose registers (e.g., register 107a) or the cache (e.g., cache 108), and thus do not produce a predictable output, (2) deterministic instructions whose input does not depend on memory values (e.g., they depend only on processor register values or values defined in the code itself), and (3) deterministic instructions whose input depends on reading values from memory (e.g., cache 108). Thus, in some embodiments, storing sufficient state data to faithfully reproduce the previous execution of an instruction can be achieved by addressing the following issues: (1) how to record non-deterministic instructions that produce an output not fully determined by their input, (2) how to reproduce the values of the input registers of an instruction based on the registers, and (3) how to reproduce the values of the input memory of an instruction based on the memory reads.

[0032] To address the challenge of reproducing the execution of non-deterministic instructions that produce an output not fully determined by their input, embodiments can record the side effects (e.g., the output of such instructions) of the execution of such instructions in the trace 114. As used herein, "non-deterministic" instructions can include some less common instructions that (i) produce a non-deterministic output each time they are executed (e.g., RDTSC on an INTEL processor, which writes the number of processor cycles since the last processor reset to a register), (ii) can produce a deterministic output, but depend on inputs that are not traced during the trace recording (e.g., debug registers, timers, etc.), and / or (iii) produce processor-specific information (e.g., CPUID on an INTEL processor, which writes processor-specific data to a register). Storing the side effects of the execution of such instructions can include, for example, storing the register values and / or memory values that are changed as a result of the execution of the instruction. In certain architectures such as those from INTEL, processor features (such as those found in Virtual Machine Extensions (VMX)) can be used to capture instructions for recording their side effects in the trace 114.

[0033] Addressing the challenge of how to reproduce the values of the input registers for deterministic instructions (e.g., whose input depends only on processor register values) is straightforward because they are the output of the execution of one or more previous instructions. Thus, the trace 114 can represent the execution of an entire series of processor instructions by storing data that can be used to reproduce the register values at the start of the series.

[0034] To address how to reproduce the input memory values for deterministic instructions whose input depends on memory values, embodiments can record the memory values (i.e., reads) consumed by these instructions into trace 114—regardless of how the values read by the instructions are written to memory. In other words, trace 114 can represent the values read from memory, but not necessarily the values written to memory (although it is not excluded that trace 114 includes memory writes). For example, although values can be written to memory by the current thread, another thread (including the kernel, e.g., as part of handling an interruption), or a hardware device, only the values read by the instructions of a thread are required for a complete replay of the instructions of the thread that performs the reads. This is because the values read by the thread (not necessarily all the values written to memory) determine how the thread executes.

[0035] While trace 114 can be recorded entirely in software (e.g., based on emulation), it can also be recorded at least in part with the help of processor 102. Based on the understanding of a processor (e.g., processor 102) forming a semi-closed or quasi-closed system, a hardware-based method for recording these reads is established. For example, once a portion of a thread's data (i.e., code data and runtime application data) is loaded into cache 108, processor 102 can operate on its own—without any input—as a semi-closed or quasi-closed system for a burst time. In particular, after cache 108 is loaded with data, one or more processing units in processing unit 107 can use the runtime data stored in the data portion of cache 108 and use register 107a to execute instructions from the code portion of cache 108. When a processing unit 107 needs some information to flow in (e.g., because the instructions it is executing, will execute, or can execute access code or runtime data not in cache 108), a "cache miss" occurs and the information is brought into cache 108 from system memory 103. Then processing unit 107 can continue execution using the new information in cache 108 until the new information is brought into cache 108 again (e.g., due to another cache miss or a non-cached read). Thus, embodiments can record enough data into trace 114 that is sufficient to be able to reproduce the flow of information into cache 108 when tracing code execution. In addition, embodiments can also record enough data into trace 114 that is sufficient to be able to reproduce any non-cached or non-cacheable reads. In an embodiment, when using multiple levels of cache, the hardware-based tracing method can record the inflows to a particular "logged" cache level. Thus, for example, in Figure 2 example environment 200 of, if logging is being performed at the L2 level, the recorded inflows can be supplied by the L3 level and / or system memory 202.

[0036] Additional optimizations can be made to cache-based tracing. For example, one optimization to cache-based logging is to only trace and record the cache lines consumed by each processing unit 107, rather than simply logging cache inflows. As will be understood by one of ordinary skill in the art, this can result in a significantly smaller trace file compared to simply logging cache inflows. As used herein, a processing unit 107 has "consumed" a cache line when the processing unit 107 knows its current value. This can be because the processing unit 107 is the processing unit that wrote the current value of the cache line, or because the processing unit performed a read on the cache line (which can cause the cache line to flow in if it is not currently in system memory 103).

[0037] In some implementations, tracing consumed cache lines can involve an extension to the cache 108 that enables the processor 102 to identify for each cache line one or more processing units 107 that consumed the current value of the cache line. For example, the cache 108 can associate one or more trace bits with each cache line. Depending on the number of trace bits and the implementation of the logic that uses these trace bits, these trace bits can be used to indicate, for example, whether any processing unit 107 has consumed the corresponding cache line (e.g., a single flag bit), which specific one or more processing units consumed the corresponding cache line (e.g., one trace bit per processing unit 107), an index to the single processing unit that consumed the corresponding cache line (e.g., by using multiple trace bits to store an integer index), etc. In additional or alternative implementations, tracing consumed cache lines can involve relying on CCP messages that the cache 108 uses to determine a subset of "consumed" cache lines to record into the trace 114. For example, a CCP-based logging method can store into the trace 114 the inflow of data to a given record cache level (e.g., the L2 cache) and at least a portion of the CCP operations that can be used to determine which processing unit caused the given inflow.

[0038] Whether using trace bits and / or CCP messages to track consumed cache lines, these methods can operate at one or more cache levels. For example, a multi-level logging method using CCP messages (i.e., using two or more cache levels) can store a log of at least a portion of the inflow of data into one cache level (e.g., L2 cache) and at least a portion of the CCP messages for at least one other cache level (e.g., L1 cache) in the trace 114. For example, these CCP messages can include a subset of the CCP state transitions for each cache memory location (i.e., between a "load" operation portion and a "store" operation portion). Other multi-level logging methods can track inflows into one cache level (e.g., L1 cache) and then use knowledge of one or more backing caches (e.g., L2 cache) to determine whether and how to log the inflow. In one example variation, upon detecting an inflow into a first cache (e.g., an L1 cache), an embodiment determines whether a backing second cache (e.g., an L2 cache) has knowledge (e.g., using accounting bits, CCP data, etc.) that can prevent the inflow from being logged, or can log the inflow by referencing a previous log entry. This variation can then log the inflow at the first cache by value or reference. Another example variation can detect an inflow at a first cache (e.g., an L1 cache) and then send a logging request to a second backing cache (e.g., an L2 cache). Upon receiving the logging request, the second cache can use its knowledge (e.g., accounting bits, CCP data, etc.) to determine whether and how to log the inflow (e.g., by value or reference, by a second cache or by a first cache, etc.), and / or pass the request to another backing cache (e.g., an L3 cache) to repeat the process.

[0039] Figure 4 An example of a trace 400 is shown, which may correspond to Figure 1A Tracking 114 and may be created based on one or more of the aforementioned tracking techniques. Figure 4 In the example of , the trace 400 includes one or more trace data streams 401. Figure 4Three traced data streams 401 (i.e., traced data streams 401a - 401c) are shown. In an embodiment, each traced data stream 401 represents the execution of a different thread of the code execution of the application 113. For example, the traced data stream 401a may represent the execution of the first thread of the application 113, the traced data stream 401b may represent the execution of the second thread of the application 113, and the traced data stream 401c may represent the execution of the third thread of the application 113. As shown, each traced data stream 401 includes a plurality of data packets 402 (i.e., data packet 402a of the traced data stream 401a, data packet 402b of the traced data stream 401b, and data packet 402c of the traced data stream 401c). In other embodiments, each traced data stream 401 may represent only a subset of the thread execution, such that multiple traced data streams 401 are required to fully represent the execution of a thread. In yet another embodiment, the traced data stream 401 may represent the execution of multiple threads (e.g., multiple threads executing at a single processing unit 107). Since the specific data logged in each data packet 402 may be different, the data packets 402 are shown as having different sizes. In view of the foregoing discussion of tracing techniques, the data packet 402 may represent at least the input (e.g., register values, memory values, cache line data, etc.) of one or more executable instructions executed as part of the first thread of the application 113.

[0040] As shown by the thick horizontal line, the traced data stream 401 may also include one or more key frames 403 (e.g., key frames 403a - 403e), each key frame 403 representing sufficient information, such as a snapshot of register and / or memory values, that enables the prior execution of the thread containing the key frames to be replayed starting from the point of the key frame 403 forward. In addition, each traced data stream 401 may include one or more ordering events, as Figure 4 shown by the circles numbered 1 - 9 in. In an embodiment, while each traced data stream 401 generally represents the execution of a corresponding single thread, the ordering events represent the occurrence of events that are sortable across threads (and thus sortable across traced data streams 401). For example, these ordering events may correspond to events of thread interaction, such as via shared memory, via function calls, etc. For simplicity, although the event order in the traced data stream 401 rotates through the threads in a cyclic manner, it can be understood that they generally occur in a less predictable manner.

[0041] In an embodiment, the trace 114 may also include the actual code that was executed. Thus, in Figure 4In this figure, each data packet 402 is shown as including an unshaded execution trace portion 404 (i.e., the execution trace portion 404a of data packet 402a, the execution trace portion 404b of data packet 402b, and the execution trace portion 404c of data packet 402c) and a shaded code portion 405 (i.e., the code portion 405a of data packet 402a, the code portion 405b of data packet 402b, and the code portion 405c of data packet 402c). In an embodiment, the code portion 405 in the packet 402 may include executable instructions that are executed based on the corresponding execution trace data. However, in other embodiments, the trace 114 may omit the actual code that has been executed and instead rely on separate access to the code of the application 113. In these other embodiments, each data packet may specify, for example, an address or offset to one or more appropriate executable instructions. As shown, the trace 114 may include any number of additional data streams 406 (i.e., data streams 406a - 406n), and the data streams 406 may store any type of additional trace data. This additional trace data may include, for example, index data, such as occasional memory snapshots, reverse lookup data structures for quickly locating memory addresses / values in the trace data stream 401, etc. Thus, when the term "trace" is used herein, the term may refer not only to the actual trace data (i.e., the trace data stream 401), but also to the index data.

[0042] In some implementations, the tracker 110 may be continuously appended to the trace data stream 401 such that the trace data continuously grows during the trace. However, in other implementations, the trace data stream 401 may be implemented as one or more circular buffers. In such an implementation, when new trace data is added, the oldest trace data is removed from the trace data stream 401. Thus, when the trace data stream 401 is implemented as one or more circular buffers, they contain a rolling trace of the most recent execution at the traced thread. The use of circular buffers may enable the tracker 110 to participate in "always-on" tracing, even in production systems. In certain implementations, tracing can be enabled and disabled almost at any time. Thus, whether tracing to a circular buffer or appending to a traditional trace data stream, the trace data may include gaps between the periods when tracing is enabled.

[0043] Returning to Figure 1A, the debugger 111 can perform various debugging tasks, including processing queries regarding the lifecycle of memory - supported objects based at least on the execution trace 114. In an embodiment, the debugger 111 processes such queries based on "handles" that identify / define memory - supported objects present in one or more previous executions of the application 113 (as found in at least one trace 114). As used herein, a handle is a logical reference to memory that is "covered" by the memory - supported object corresponding to the handle during the lifecycle of the memory - supported object. Thus, as part of receiving and / or processing queries for the trace 114, the debugger 111 can identify memory - supported objects present in the traced execution of the application 113, can identify / define handles for the memory - supported objects, and / or can identify memory addresses (as found in the trace 114) that are covered by the memory - supported objects during the lifecycle of the memory - supported objects. Since the trace 114 can be used to obtain information about the memory coverage of memory - supported objects over a period of execution time, the debugger 111 can process memory - related queries that depend on the concept of execution time. These concepts are discussed in more detail below.

[0044] In an embodiment, the debugger 111 uses one or both of static analysis or dynamic analysis of the trace 114 to process such queries. As used herein, static analysis of the trace 114 includes the debugger 111 performing analysis based only on data read from the trace 114 (e.g., based on trace data in the trace data stream 401, based on index data in the additional data stream 406, etc.). On the other hand, dynamic analysis of the trace 114 can use data generated / obtained based on replay / simulation of the code of the application 113 from the trace 114. Thus, Figure 1A shows that the emulator 112 can also be loaded into the system memory 103 (i.e., emulator 112'), and the application 113 can be emulated by the emulator 112' using the trace 114 (i.e., application 113' within the emulator 112'). The arrows connecting the debugger 111', emulator 112', and trace 114' indicate that the debugger 111' can request the emulator 112' to perform a simulation of the trace 114', and the emulator 112' can provide the debugger 111' with the results of that trace simulation.

[0045] Note that although each of the tracer 110, debugger 111, and / or emulator 112 can be a separate component or application, they can also be integrated into the same application (such as a debug suite), or can be integrated into another software component - such as an operating system component, hypervisor, cloud architecture, etc. Thus, those skilled in the art will also understand that the present invention can be practiced in a cloud computing environment of which its computer system 101 is a part. For example, the cloud computing environment can be used to parallelize trace processing (e.g., trace replay, trace query, etc.) on behalf of the computer system 101, and the cloud computing environment can provide trace processing services, etc.

[0046] Turning now to Figure 1B , an example 100b is shown, which provides Figure 1A additional details of possible components of the debugger 111, particularly components that can be directly involved in providing functionality for processing queries regarding the lifecycle of memory support objects based at least on the trace 114. For example, Figure 1B the debugger 111 depicted in includes a trace access component 115, an object identification component 116, a query component 117, and an output component 118. Each of these components represents various functions that the debugger 111 can implement according to various embodiments described herein. However, it should be understood that the depicted components - including their identities, sub-components, and arrangements - are presented only to assist in describing various embodiments of the debugger 111, and these components / sub-components are non-limiting as to how software and / or hardware implement various embodiments of the debugger 111 or its specific functions.

[0047] Generally, the trace access component 115 accesses at least one trace 114. For example, as part of initiating a debug session for a previous execution of the application 113, as part of receiving a user-specified query (e.g., at the debugger user interface) in conjunction with the debug session, as part of an application programming interface (API) request of some other application, etc., the trace access component 115 can access the trace 114. The trace access component 115 can access various trace data types. For example, the trace data access component 115a can access the trace data itself (e.g., the trace data stream 401), while the index data access component 115b can access index data or other support data (e.g., the additional data stream 406).

[0048] The object identification component 116 identifies at least one memory - supported object from the accessed trace 114. As used herein, a "memory - supported object" is any runtime data structure that uses one or more memory cells for data storage (e.g., in cache 108, system memory 103, etc.). For example, memory - supported objects can include programming language primitive types (e.g., integers, booleans, characters, floating - point numbers, etc.), data structures (e.g., arrays, structs, vectors, linked lists, etc.), objects created from classes, heaps, virtual address spaces, etc. Memory - supported objects can be stored in various memory locations, such as memory locations corresponding to a process's stack and / or a process's heap. The object identification component 116 can identify memory - supported objects in a variety of ways, such as based on a specified memory address (e.g., any memory address covered by the memory - supported object), based on a specified name or reference (e.g., if debug symbols are available to the debugger 111), based on a specified pointer, etc.

[0049] As shown, the object identification component 116 can include additional components for identifying and / or defining additional information associated with the memory - supported object. For example, the lifecycle identification component 116a can identify the lifecycle of the memory - supported object. In an embodiment, this includes pairing a first event that defines the start of the lifecycle of the memory - supported object with a second event that defines the end of the lifecycle of the memory - supported object.

[0050] In an embodiment, the lifecycle identification component 116a pairs the expressed lifecycle - defining events. For example, the lifecycle of a memory - supported object can be explicitly defined by calls to allocation / deallocation primitives. For example, a call to malloc() or calloc() can define the start of an object's lifecycle, while a call to free() can define the end of an object's lifecycle; a call to HeapAlloc() can define the start of a heap's lifecycle, while a call to HeapFree() can define the end of a heap's lifecycle; a call to VirtualAlloc() can define the start of a virtual address space lifecycle, while a call to VirtualFree() can define the end of a virtual address space lifecycle; and so on. The lifecycle identification component 116a can also track intermediate allocation / deallocation primitives, such as a call to realloc().

[0051] In an embodiment, the lifecycle identification component 116a determines whether allocation and deallocation primitives are compatible. For example, an allocation primitive can be compatible with a deallocation primitive if they are in the same allocation series (e.g., malloc() and free()), plus the set of expected parameters match. Thus, for example, if a call to HeapAlloc() and a call to HeapFree() use the same heap, they can be compatible; but if these calls use different heaps, they may not be compatible.

[0052] Additionally or alternatively, the lifecycle identification component 116a can pair implicit lifecycle definition events. For example, when entering a function, a stack frame is typically "pushed" onto the thread's stack. If there are any local variables in the function, the stack frame includes the memory locations of these variables on the stack. This is an implicit memory allocation for storing these variables. Later, when the function completes, the stack frame is typically "popped" from the thread's stack. This is an implicit deallocation of the memory storing these variables. Another example of implicit allocation is the reclassification of memory, such as C++'s "placement new()", which constructs a new object from already allocated memory.

[0053] Sometimes, regardless of whether the lifecycle of a memory - supported object is explicitly or implicitly created, its lifecycle can end due to the destruction of an enclosing structure. Thus, the lifecycle identification component 116a can identify the end of the lifecycle based on the destruction of the enclosing structure. For example, the lifecycle of a memory - supported object can be terminated by the destruction of a parent object (e.g., in the case of multiple inheritance), deallocation of a heap or stack, a call to VirtualFree() (or a similar function), or thread / process termination. Additionally, the lifecycle of a memory - supported object can end due to the termination of tracing (i.e., because there is no more tracing information about the object lifecycle) - at least for the purposes of tracing analysis.

[0054] In an embodiment, the lifecycle identification component 116a can be aware of a managed runtime environment, such as JAVA,.NET Common Language Runtime (CLR), etc. Thus, the lifecycle identification component 116a can identify lifecycle events based on the operations of managed runtime components such as allocators, garbage collectors, etc.

[0055] Based at least on the life cycle of a given memory - supported object (i.e., determined by the life - cycle identification component 116a), the coverage identification component 116b determines which memory is covered by the memory - supported object and at what time or how many times the memory is covered by the memory - supported object. For example, if the memory - supported object is an array, the coverage identification component 116b can identify all memory addresses that are part of the array and the (multiple) execution times during which these memory addresses are part of the array; if the memory - supported object is a structure, the coverage identification component 116b can identify all memory addresses that are part of the structure and the (multiple) execution times during which these memory addresses are part of the structure; if the memory - supported object is an object (e.g., an instance of a class), the coverage identification component 116b can identify all memory addresses that are part of the object and the (multiple) execution times during which these memory addresses are part of the object; and so on.

[0056] It can be understood that the memory locations associated with a memory - supported object can change during the life cycle of the object. For example, a call to realloc() can expand or shrink the heap memory allocated to an object and / or can move the object completely in memory. As another example, many data types (e.g., vectors, linked lists, etc.) can grow and / or shrink over time, thus dynamically changing the memory locations allocated to these data types over time. As yet another example, a garbage collector can dynamically reduce the memory allocated to an object at any time and / or move the object completely in memory. Additionally, even a memory address once allocated to an object can become invalid for the object at another time (e.g., due to a context switch, such as a switch from kernel mode to user mode or a switch between user - mode threads). Given the foregoing, in an implementation, a memory address can be considered to be "covered" by a memory - supported object if it was once part of the memory - supported object. However, just because a memory address is "covered" by a memory - supported object does not mean that the memory address is a valid memory address for the memory - supported object throughout the entire life cycle of the memory - supported object. Thus, although a given memory address can be covered by a memory - supported object, it can be valid for the memory - supported object at one execution time and invalid for the memory - supported object at another execution time.

[0057] In an embodiment, the coverage identification component 116b can use specific knowledge of allocation primitives, data - structure types, etc. to finely track what memory is actually allocated by a memory - supported object. For example, the coverage identification component 116b can use knowledge of the allocation primitive to determine what heap memory is actually allocated to an object and what heap memory can be reserved by the allocation primitive for other purposes such as padding. For example, Figure 5AExample 500a is shown. Example 500a includes a memory allocation 501 that can be generated by a thread's request for a seven-byte heap memory block (e.g., a call to "malloc(7)"). In particular, memory allocation 501 shows a memory range of seven bytes starting from memory address 502. Thus, a call to the allocation function can return memory address 502 to the thread, and the thread can then use integer offsets from that address to access the allocated memory (bytes 1 - 7). In addition to this seven-byte allocation, Figure 5A it is also shown that memory allocation 501 may also include an eighth "padding" byte (represented by the shading). The allocation function may have reserved this padding byte to facilitate memory alignment (e.g., 8 - or 16 - byte memory alignment) in order to speed up memory access based on the characteristics of the physical memory and / or the memory bus. This padding byte is not technically allocated to the thread that requested the seven - byte allocation. In an embodiment, the coverage identification component 116b knows about this padding and can treat it as not being covered by the corresponding memory - backed object.

[0058] In another example, the coverage identification component 116b can use type information associated with a data structure to finely track individual memory allocations of the data structure. For example, Figure 5B Example 500b is included, which shows a struct primitive 503 that includes three 64 - bit integers (i.e., a, b, and d) and one 8 - bit integer (i.e., c). Figure 5B It is also shown an example memory allocation 504 that can be allocated on the thread's stack based on struct primitive 503. In particular, Figure 5B it is shown that a contemporary compiler can reserve a 64 - bit memory range for each of the integers a, b, c, and d. However, as shown, the 64 - bit memory range for integer c includes the 8 bits of the integer itself, followed by a 56 - bit gap (represented by the shading). Similar to the padding discussed Figure 5A above, this gap can be created by the compiler to align the variable on a 64 - bit boundary, but it is not actually allocated for use by the struct primitive. In an embodiment, the coverage identification component 116b knows about this gap and can treat it as not being covered by the struct.

[0059] In an embodiment, the coverage identification component 116b identifies a set of logically associated memory support objects, each logical association associating at least two pieces of information: (i) at least one memory address, and (ii) at least one execution time during which the memory address (or addresses) is “covered” by the memory support object during the lifetime of the memory support object. These logical associations can be implemented in a variety of ways, such as through tuples (e.g., data structures, each directly specifying one or more memory addresses and one or more execution times). In an embodiment, multiple memory addresses can be specified by a range (e.g., start address and byte count, start address and end address, etc.), a list of individual memory addresses, or a combination thereof. Similarly, multiple execution times can be specified by a range, a list, or a combination thereof.

[0060] The handle identification component 116c identifies or defines a handle for the memory support object. As previously described, a handle is a logical reference to memory that is covered by the memory support object during the lifetime of the memory support object. Thus, for example, a handle can be used as a logical abstraction representing the set of logical associations (e.g., tuples) identified by the coverage identification component 116b. A handle can actually be anything that can be used to identify an object, such as a pointer (e.g., pointing to a memory address covered by the memory support object), a debugger symbol, a source code-level object name, etc. In an implementation, when any memory address is considered to be “covered” by a handle, it is also considered to be “valid” for the handle when it is covered. However, a handle can also refer to coverage and validity separately.

[0061] In an embodiment, the handle may also refer to other information related to a memory support object. For example, the information may include the following: (i) start execution time (i.e., the time when the object's life cycle starts); (ii) end execution time (i.e., the time when the object's life cycle ends); (iii) memory accessibility indicators such as "kernel mode only", "user mode context A", "R--", "RX", "RWX", "-W-", "--X", paging out, etc.; (iv) a cache list of memory accesses associated with the handle; (v) an indication that the first memory address covered by the handle is "moving" to a second memory address (e.g., due to realloc()), and an indication of one or more corresponding execution times of the move; and so on. If the additional information includes a cache list of memory accesses associated with the handle, it may include the "status" of one or more of these accesses, such as (a) the access is a covered memory access to the handle, (b) the access is a covered memory access to the handle, but the accessed memory is marked as inaccessible, (c) the access is associated with the handle, but the accessed address is not covered, (d) the access is associated with the handle, but the life cycle starts before it, (e) the access is associated with the handle, but the life cycle ends after it, (f) the access is associated with the handle, but when the memory is paged out, (g) the access is to uninitialized memory (e.g., reading after the life cycle starts but before writing), (h) cache results of previous queries for this trace 114, or common queries of other traces, etc. If the additional information includes an indication that the first memory address covered by the handle is "moving" to a second memory address, it may include additional details such as, (a) writing to the old memory location after the object is copied to the new location; (b) reading from the new memory location after allocation but before copying the object from the old location (even if the allocation initializes the memory); and so on.

[0062] Since a handle is a logical reference to memory that is overwritten by a memory - backed object during the lifetime of the memory - backed object, it can refer to the object (including the logical association identified by the overwrite identification component 116b), even as the nature and / or location of the object changes over time. For example, if the underlying memory location of the object moves (e.g., due to a garbage collection cycle, due to a call to realloc(), etc.), the handle can refer to the object regardless of the object's location in memory at a given point in time; if the object has different context - based mappings (e.g., accessing a physical address via DMA; user - mode addresses locked by kernel - mode code at multiple different times and these locked kernel - mode addresses are different; etc.), the handle can refer to the object regardless of the context; if the size of the object changes over time (e.g., in the case of linked lists, vectors, etc.), the handle can refer to any and all memory allocated to the object over time - for example, if the memory - backed object is the head of a linked list, the handle can refer to any element belonging to that linked list at any particular point in time.

[0063] Furthermore, since a handle is a logical reference to memory that is overwritten by a memory - backed object during the lifetime of the memory - backed object, it can be used to identify access to the object, regardless of how the object is accessed during tracing. For example, an object is typically accessed based on an offset from a base memory address (e.g., the base address of a heap allocation returned by malloc(), the address corresponding to the first element in an array or vector, the address corresponding to the base class of an object, etc.). However, a handle can refer to access to the object based on any address overwritten by the object. For example, a handle can contain an access to the object from a positive or negative offset from a memory location within the object (i.e., not the base address). For example, this can occur in the case of multiple inheritance. For example, a base class (which typically can correspond to the first base address of an object in memory) and a derived class (which is typically laid out after the base class in memory and thus starts at a later second address) can be used to define an object. In this case, the object can be accessed based on its derived class - and thus the second address. However, even if the access is from the second address (rather than the base address), the handle can logically include that access from the second address because it is part of the whole object (i.e., including the memory associated with the base class).

[0064] The following is an additional example of the concept of using handles to identify access to an object allocated to the heap using malloc(), regardless of how the object is accessed during tracing. This example is based on the recognition that any access to a valid memory region covering an object must have a pointer (address) for that access, which ultimately can be traced back to the pointer originally returned by malloc(), and for the access to be valid, it must occur before the object is deallocated (e.g., by a call to free()). Any subsequent access to that pointer after deallocation is invalid, this occurs outside the valid scope, and any access to that region through something that cannot be traced back to that pointer is also invalid. Thus, for example, assume there are two structs: Foo and Bar. Foo has two "int" members: A1 and A2, while Bar has one "int" member: B1. In the following example, for illustrative purposes, assume A2 is allocated in memory after A1, and both are of the size and alignment of an int, and B1 is allocated in memory after A2, and this is of the size and alignment of an int. Given the statement to allocate Foo,

[0065] pointerToFoo = (Foo*)malloc(sizeof(Foo));

[0066] The logical "handle" for object Foo can now have the starting life cycle of Foo, the size of Foo, and the allocated memory location. Given the statement to allocate Bar,

[0067] pointerToBar(Bar*)malloc(sizeof(Bar));

[0068] The logical "handle" for object Bar can now have the starting life cycle of Bar, the size of Bar, and the allocated memory location. Given these two statements, Bar can be allocated in memory after Foo.

[0069] The logical handles for Foo and Bar can be used to trace various accesses to these structs, regardless of the actual "pointers" that may exist in the code. For example, the statement:

[0070] pointerToFoo_A1 = &(pointerToFoo->A1);

[0071] is another way to access Foo via its member A1. Using the logical handle for Foo, this access can be traced back to the primitive malloc() of Foo. Similarly, the statement:

[0072] anotherPointerToFoo = pointerToFoo;

[0073] is another way to access Foo. Using the logical handle of Foo, this access can also be traced back to the primitive malloc() of Foo. Additionally, the statement:

[0074] pointerToFoo_A2 = &(pointerToFoo->A2);

[0075] is yet another way to access Foo. Using the logical handle of Foo, this access can also be traced back to the primitive malloc() of Foo. Note that pointerToFoo_A1 and pointerToFoo_A2 cannot have the same memory address (i.e., the addresses of members A1 and A2 in memory are different), but they can both be traced back to Foo, and thus are valid ways to access memory in the allocation of Foo, as long as it is done before deallocating Foo.

[0076] Extended example, in the following statement:

[0077] int* pInt = (int*)pointerToFoo;

[0078] the memory access can again be traced back to Foo, so any access through the pointer pInt can legally access the memory area of Foo when the memory area of Foo is valid. This means that the statements:

[0079] *pInt = 1;

[0080] pInt[0] = 2;

[0081] pInt[1] = 3;

[0082] are all valid writes to the memory area of Foo (i.e., writing the value 1 to A1, then the value 2 to A1, and then the value 3 to A2). However, the statement:

[0083] pInt[2] = 4;

[0084] would be an invalid write to the memory area of Bar via a pointer to Foo (and thus an invalid memory access to the logical handle of Foo). This is because the access to the memory area (i.e., corresponding to Bar) is done through an access that cannot be traced back to the handle allocation.

[0085] Note that the lifecycle identification component 116a, the coverage identification component 116b, and the handle identification component 116c can each operate independently or together in any order (including in parallel). For example, the object identification component 116 can operate based on the identity of a particular memory-backed object (e.g., by name, by symbolic reference, etc.) to identify one or more of its lifecycle, its memory coverage, or its handle. As another example, the object identification component 116 can operate based on a given memory address (including execution time) to subsequently identify the corresponding memory-backed object, including one or more of its lifecycle, its memory coverage, or its handle. In yet another example, the object identification component 116 can operate based on a given handle to subsequently identify the corresponding memory-backed object, including one or more of its lifecycle or its memory coverage.

[0086] Typically, the query component 117 receives and processes queries related to memory - supported objects based on the information identified by the object identification component 116 (e.g., object lifecycle, covered memory addresses / times, handles, etc.). The query component 117 can be configured to receive and process various forms of queries, such as queries where the input is a handle, queries where the result of the query includes a handle, and / or queries where the handle is an intermediate result. The query component 117 enables a rich query array related to the memory covered by the memory - supported object. For example, when using a handle as an input, the query component 117 can enable queries that return all memory accesses to the object associated with the handle, queries that return all inputs to the object associated with the handle (e.g., based on write - over memory), queries that return all outputs to the object associated with the handle (e.g., based on reads of the overwritten memory), queries that return all objects containing the object associated with the handle, queries that return all objects contained within the object associated with the handle, queries that indicate whether the object associated with the handle has ever moved in memory, queries that are returned when the object associated with the handle is accessed, queries that are returned when the object associated with the handle is modified, queries that return whether there are memory accesses using the object handle after the end of the object's lifecycle (e.g., use after free()), queries that return whether the memory was in use before accessing the object associated with the handle using the handle (e.g., buffer underflow), queries that return whether the memory was in use after accessing the object associated with the handle using the handle (e.g., buffer overflow), queries that return whether a filled memory was accessed using the object handle, queries that return whether a memory gap was accessed using the object handle, queries that return whether unallocated memory was read within the object associated with the handle, etc. While the object handle can be directly provided as an input to any of these queries, the handle can alternatively be identified as an intermediate result. For example, the query can receive a memory address and time, the identity of the memory - supported object (e.g., by name / symbol), etc. as inputs. Then the query component 117 can use the object identification component 116 to identify the handle and then use the handle for further query processing.

[0087] The query component 117 can even return a handle as a query result. For example, the query can request a result set that includes the handles of all objects for which there is a particular type of traced memory access (e.g., all objects for which there is an access to uninitialized memory, all objects for which there is use after free(), etc.).

[0088] As some specific examples of queries, memory corruption vulnerabilities may be found in queries, such as

[0089] Allocations.Where(h => h.CorrectDeallocation == false)

[0090] Or

[0091] handles.where(h =>!(compatible(h.allocator, h.deallocator)))

[0092] It is possible to return the handles of all objects that have not been correctly deallocated (i.e., no matching pair of allocation / deallocation functions was found). In the second query, the compatible() function can return "true", for example, in the following cases:

[0093] (allocator == malloc && deallocator == free) ||

[0094] (allocator == LocalAlloc && deallocator == LocalFree) ||

[0095] (allocator == new[] && deallocator == delete[]) ||

[0096] (allocator == new && deallocator == delete).

[0097] Note that these conditions are only illustrative examples, and there can be various implementations of the compatible() function.

[0098] As another example, to return the handles of objects that have not been deallocated at the current execution, the following form can be used:

[0099] Allocations.Where(h => h.AllocationTime < Time.CurrentExecutionTime && h.DeallocationTime > Time.CurrentExecutionTime)

[0100] This query will find the allocations that have been made at a given execution time (e.g., the current execution time, the time when a given function was called, etc.) but have not been deallocated at the given execution time.

[0101] The output component 118 returns any results generated by the query component 117. For example, the user interface output component 118a can provide the results within a user interface (e.g., the user interface of a debugger), or the API output component 118a can provide the results to some other application that makes an API call to the debugger 111 to execute the query.

[0102] Figure 6 A flowchart of an example method 600 for processing queries regarding the lifecycle of memory - backed objects based on an execution trace is shown. The discussion of method 600 refers to method actions. Although these method actions may be discussed in a particular order or illustrated in a flowchart as occurring in a particular order, a particular order is not required unless specifically stated or necessary because one action depends on another action being completed before that action is executed.

[0103] As Figure 6 shown, method 600 includes an action 601 of accessing the trace. For example, the trace access component 115 can access the trace 114 (e.g., trace 400). Such trace access can include not only the trace data access component 115a accessing one or more trace data streams 401 representing a previous execution of the application 113, but also the index data access component 115b accessing one or more additional data streams 406 containing index data. In an embodiment, the index data can include any data previously identified by the object identification component 116 (e.g., based on a previous query, based on an index pass on the trace 114, etc.).

[0104] Method 600 also includes an action 602 of identifying memory - backed objects in the trace and an action 603 of processing queries regarding the memory - backed objects. As indicated by the arrow extending from action 601, it is not required to identify the memory - backed objects before processing queries regarding the memory - backed objects, nor is it required that processing the queries results in an identification of the memory - backed objects. Thus, actions 602 and 603 can be in either order (e.g., depending on the specific terms of the query) and / or executed in parallel.

[0105] In an embodiment, operation 602 may include the object identification component 116 identifying the memory - backed object based on a direct specification of the memory - backed object (e.g., by name, by symbol, by pointer, etc.). Thus, operation 602 may include identifying, from a previous execution trace of an entity, the memory - backed objects that existed during the previous execution of the entity based on the specification. For example, as part of a query, a debugger user interface may receive a specification of a memory - backed object of source code at a particular point in time. Alternatively, the query may identify the above - mentioned object as an intermediate result and use that intermediate result for further query processing. Alternatively, operation 602 may include identifying the memory - backed object based on an indirect specification of the memory - backed object. For example, as part of a query, a debugger user interface may receive a selection of a particular memory access to a particular memory address. Thus, operation 602 may include the object identification component 116 identifying, from a previous execution trace of an entity, the memory addresses that were part of the previous execution of the entity during at least one execution time and identifying at least one memory - backed object associated with the memory address during at least one execution time.

[0106] As shown, operation 602 of identifying a memory - backed object in a trace may include or at least depend on one or more of the following: operation 604 of identifying the life - cycle of the memory - backed object, operation 605 of identifying the association between a memory address and an execution time when the memory address is overwritten by a memory - backed object, and operation 606 of identifying a handle of a memory that logically represents the memory overwritten by a memory - backed object during the life - cycle of the memory - backed object. As Figure 6 shown, method 600 does not require a specific order between operations 604 - 606. Thus, depending on the implementation, these operations may be performed serially (in any order) or in parallel. In any of operations 604 - 606, the identification may be based on an analysis of trace data (e.g., trace data stream 401) and / or index data (e.g., additional data stream 406). Further, although operations 604 - 606 are shown within operation 602, any of these operations may be performed before operation 602 begins (i.e., before receiving a query), such as during the generation of index data.

[0107] In an embodiment, operation 604 includes the life - cycle identification component 116a determining the start of the life - cycle of the memory - backed object and determining the end of the life - cycle of the memory - backed object. For example, using the techniques discussed above in conjunction with Figure 1B the life - cycle identification component 116a may determine from the trace 114 when the life - cycle of the memory - backed object begins and when it ends.

[0108] For example, the lifecycle identification component 116a may depend on an allocation primitive. Thus, determining the start of the lifecycle of a memory - supported object may be based on identifying a call to the allocation primitive, and determining the end of the lifecycle of the memory - supported object may be based on identifying a call to the de - allocation primitive. In another example, the lifecycle identification component 116a may depend on stack allocation. In this way, determining the start of the lifecycle of a memory - supported object may be based on identifying the allocation of a stack frame, and determining the end of the lifecycle of the memory - supported object may be based on identifying the de - allocation of the stack frame. In another example, the lifecycle identification component 116a may depend on the memory management of the managed runtime. Thus, determining the start of the lifecycle of a memory - supported object may be based on identifying the managed runtime allocation, and determining the end of the lifecycle of the memory - supported object may be based on identifying the managed runtime de - allocation, such as by a garbage collector. In another example, the lifecycle identification component 116a may depend on memory re - classification, such as using placement new(). In this way, determining the start of the lifecycle of a memory - supported object may be based on identifying the re - classification of one or more memory locations, and determining the end of the lifecycle of the memory - supported object may be based on identifying the destruction of the memory - supported object. In another example, the lifecycle identification component 116a may track whether an object is contained by another object. In such a case, determining the end of the lifecycle of the memory - supported object may be based on identifying the end of the lifecycle of the parent container. In any of these cases, the end of the lifecycle may alternatively be based on identifying the end tracked before de - allocation.

[0109] In an embodiment, action 605 includes the coverage identification component 116b identifying a set of associations represented by a handle, where the associations identify multiple memory addresses that are covered by a memory - supported object during the lifecycle of the memory - supported object. Each association represents at least: (i) a memory address that is covered by the memory - supported object during the lifecycle of the memory - supported object, and (ii) an execution time at which the memory address is covered by the memory - supported object during the lifecycle of the memory - supported object. For example, using the techniques discussed above in connection with Figure 1B the coverage identification component 116b can identify which memory addresses are covered by a memory - supported object during the lifecycle of the memory - supported object. For example, this can be represented by an association (e.g., a tuple) between one or more memory addresses and one or more execution time points at which these memory addresses are covered by the memory - supported object.

[0110] In an embodiment, action 606 includes the handle identification component 116c identifying a handle that is used to logically represent memory that was covered by a memory - supported object during the lifecycle of the memory - supported object in a previous execution of an entity. For example, using the techniques discussed above in connection with Figure 1BFor the techniques discussed, the handle identification component 116c can identify the handle of the memory support object identified in operation 602. This handle can logically represent the memory support object at any point in the life cycle of the memory support object, regardless of the specific memory allocated to the memory support object during that point in its life cycle.

[0111] Returning to operation 603, while there are a variety of queries available, they generally rely on performing a query against the handle of the memory support object. In an embodiment, processing a query for a memory support object can include the query component 117 at least partially processing the query against the handle. Since, as discussed, the handle logically represents the memory covered by the object corresponding to the handle, the handle can logically represent the set of memory / execution time associations generated by the coverage identification component 116b. Thus, in an embodiment, the query can include at least one query condition based on execution time, and processing the query can include comparing the execution time in the query with one or more execution times represented in the associated set. It should be noted that the handle acting in operation 603 can be an intermediate query result, and even the memory support object itself can be an intermediate query result. Thus, the memory support object and / or the handle can be identified at least in part based on the processing of the query.

[0112] Method 600 also includes an operation 607 of formulating a query response. For example, the query component 117 can formulate a query result, and the output component 118 can output these results at a user interface (i.e., UI output component 118a) and / or via an API output (i.e., API output component 118b). Depending on the query received in operation 601, formulating a query response can take various forms. For example, formulating a response to the query can include identifying a first traced memory access that targets at least one memory address among the multiple memory addresses represented in the associated set during any execution time when at least one memory address was covered by the memory support object during the life cycle of the memory support object in a previous execution of the entity, where during that execution time, at least one memory address was covered by the memory support object. In other words, formulating a response to the query can include identifying memory accesses to valid covered memory locations during the life cycle of the memory support object. Formulating this type of query response can be based on, for example, processing a query to find accesses to the memory support object, processing a query to find inputs to the memory support object, processing a query to find outputs from the memory support object, processing a query to find where the memory support object was accessed, processing a query to find where the memory support object was modified, and so on.

[0113] As another example, formulating a response to a query may include identifying a second traced memory access associated with a handle and corresponding to an execution time, the second traced memory access targeting at least one memory address that is invalid for the handle at the execution time among the plurality of memory addresses represented in the associated set. In other words, formulating a response to a query may include using a handle of an invalid object to identify a memory access. Formulating a query response of this type may be based on, for example, processing a query that looks for uses after free(), processing a query that determines whether there are any accesses before the memory allocation of an object (buffer underrun), processing a query that determines whether there are any accesses after the memory allocation of an object (buffer overflow), processing a query that determines whether an access is a fill, processing a query that determines whether an access is a gap, and so on.

[0114] As another example, formulating a response to a query may include identifying a third traced memory access that includes a read targeting at least one memory address among the plurality of memory addresses represented in the associated set during any execution time when at least one memory address was covered by a memory-supported object during the life cycle of the memory-supported object in a previous execution of the entity and the read is before a write to at least one memory address when at least one of the one or more memory addresses is valid for the memory-supported object. In other words, formulating a response to a query may include using a handle to identify a read from uninitialized memory.

[0115] As another example, formulating a response to a query may include identifying that at least one memory address among one or more memory addresses was covered by a memory-supported object at a first execution time during the life cycle of the memory-supported object, but was not covered by the memory-supported object at a second execution time during the life cycle of the memory-supported object. In other words, formulating a response to a query may include determining whether the memory-supported object has moved in memory, whether the memory-supported object has changed its shape / layout in memory, and so on.

[0116] Although the subject matter has been described in language specific to structural features and / or methodological acts, it is to be understood that the subject matter defined in the appended claims is not necessarily limited to the described features or acts or the order of the above acts. On the contrary, the described features and acts are disclosed as example forms of implementing the claims.

[0117] Embodiments of the present invention may include or utilize a special-purpose or general-purpose computer system that includes computer hardware, such as one or more processors and system memory, as discussed in more detail below. Embodiments within the scope of the present invention may include physical and other computer-readable media for carrying or storing computer-executable instructions and / or data structures. Such computer-readable media can be any available media that can be accessed by a general-purpose or special-purpose computer system. A computer-readable medium storing computer-executable instructions and / or data structures is a computer storage medium. A computer-readable medium carrying computer-executable instructions and / or data structures is a transmission medium. Thus, by way of example and not limitation, embodiments of the present invention may include at least two distinct types of computer-readable media: computer storage media and transmission media.

[0118] A computer storage medium is a physical storage medium that stores computer-executable instructions and / or data structures. Physical storage media include computer hardware such as RAM, ROM, EEPROM, solid state drives (“SSDs”), flash memory, phase change memory (“PCM”), optical disc storage devices, magnetic disk storage devices, or any other magnetic storage devices, or any other hardware storage device that can be used to store program code in the form of computer-executable instructions or data structures that can be accessed and executed by a general-purpose or special-purpose computer system to implement the disclosed functionality of the present invention.

[0119] A transmission medium may include a network and / or a data link that can be used to carry program code in the form of computer-executable instructions or data structures and can be accessed by a general-purpose or special-purpose computer system. A “network” is defined as one or more data links capable of conveying electronic data between computer systems and / or modules and / or other electronic devices. When information is transmitted or provided to a computer system via a network or another communication connection (wired, wireless, or a combination of wired or wireless), the computer system can regard the connection as a transmission medium. Combinations of the above should also be included within the scope of computer-readable media.

[0120] Further, upon reaching various computer system components, program code in the form of computer-executable instructions or data structures can be automatically transferred from the transmission medium to the computer storage medium (and vice versa). For example, computer-executable instructions or data structures received via a network or data link can be cached in RAM within a network interface module (e.g., “NIC”) and then ultimately transferred to the computer system RAM and / or less volatile storage media at the computer system. Thus, it should be understood that computer-readable media can be included in computer system components that also (or even primarily) utilize a transmission medium.

[0121] For example, computer-executable instructions include instructions and data that, when executed at one or more processors, cause a general-purpose computer system, a special-purpose computer system, or a special-purpose processing device to perform a particular function or group of functions. The computer-executable instructions can be, for example, binary instructions, intermediate format instructions (such as assembly language), or even source code.

[0122] Those skilled in the art will appreciate that the present invention can be practiced in a network computing environment using many types of computer system configurations, including personal computers, desktop computers, laptop computers, messaging processors, handheld devices, multiprocessor systems, multiprocessor-based or programmable consumer electronics, network PCs, minicomputers, mainframe computers, mobile phones, PDAs, tablet computers, pagers, routers, switches, and the like. The present invention can also be practiced in a distributed system environment where local and remote computer systems that are network-linked (either through hardwired data links, wireless data links, or a combination of hardwired and wireless data links) both perform tasks. Thus, in a distributed system environment, the computer system can include multiple constituent computer systems. In a distributed system environment, program modules can be located in both local and remote memory storage devices.

[0123] Those skilled in the art will also appreciate that the present invention can be practiced in a cloud computing environment. The cloud computing environment can be distributed, although this is not required. When it is distributed, the cloud computing environment can be internationally distributed within an organization and / or have components that are processed across multiple organizations. In this specification and the following claims, "cloud computing" is defined as a model for enabling on-demand network access to a shared pool of configurable computing resources such as networks, servers, storage devices, applications, and services. The definition of "cloud computing" is not limited to any one of the many other advantages that can be obtained from such a model when appropriately deployed.

[0124] The cloud computing model can consist of various characteristics such as on-demand self-service, broad network access, resource pooling, rapid elasticity, measured service, and the like. The cloud computing model can also appear in the form of various service models such as, for example, software as a service ("SaaS"), platform as a service ("PaaS"), and infrastructure as a service ("IaaS"). The cloud computing model can also be deployed using different deployment models such as private cloud, community cloud, public cloud, hybrid cloud, and the like.

[0125] Some embodiments, such as cloud computing environments, may include a system that includes one or more hosts, each capable of running one or more virtual machines. During operation, the virtual machines emulate an operable computing system, thereby supporting an operating system and possibly one or more other applications. In some embodiments, each host includes a hypervisor that emulates the virtual resources of the virtual machines using physical resources that are abstracted from the view of the virtual machines. The hypervisor also provides appropriate isolation between the virtual machines. Thus, from the perspective of any given virtual machine, the hypervisor provides the illusion that the virtual machine is interfacing with physical resources, even though the virtual machine is only interfacing with the appearance of the physical resources (e.g., virtual resources). Examples of physical resources include processing power, memory, disk space, network bandwidth, media drives, and the like.

[0126] The present invention may be embodied in other specific forms without departing from its spirit or essential characteristics. The described embodiments are to be considered in all respects only as illustrative and not restrictive. Thus, the scope of the invention is indicated by the appended claims rather than by the foregoing description. All changes that come within the meaning and range of equivalency of the claims are to be embraced within their scope. When an element is introduced in the appended claims, the articles “a,” “an,” “the,” and “said” are intended to mean that there is one or more of the element. The terms “comprising,” “including,” and “having” are intended to be inclusive and mean that there may be additional elements other than the listed elements.

Claims

1. A method implemented at a computer system including at least one processor for processing a query regarding the lifecycle of a memory - backed object based on an execution trace, the method comprises: identifying, from a trace of a previous execution of an entity, memory - backed objects that existed during the previous execution of the entity; identifying a handle that logically represents memory covered by the memory - backed object during the lifecycle of the memory - backed object in the previous execution of the entity; identifying a plurality of sets of associations represented by the handle, the sets of associations identifying a plurality of memory addresses covered by the memory - backed object during the lifecycle of the memory - backed object, each association representing at least: (i) a memory address covered by the memory - backed object during the lifecycle of the memory - backed object, and (ii) an execution time at which the memory address was covered by the memory - backed object during the lifecycle of the memory - backed object; processing, at least in part, a query regarding the handle, the query including at least one query condition based on execution time, processing the query including comparing the execution time in the query with one or more execution times represented in the sets of associations; and formulating a response to the query based on the memory - backed object.

2. The method according to claim 1, further comprises: determining a start of the lifecycle of the memory - backed object; and determining an end of the lifecycle of the memory - backed object.

3. The method according to claim 2, wherein determining the start of the lifecycle of the memory - backed object is based on identifying a call to an allocation primitive, and wherein determining the end of the lifecycle of the memory - backed object is based on identifying at least one of: a call to a de - allocation primitive or the end of the trace.

4. The method according to claim 2, wherein determining the start of the lifecycle of the memory - backed object is based on identifying an allocation of a stack frame, and wherein determining the end of the lifecycle of the memory - backed object is based on identifying at least one of: a de - allocation of the stack frame or the end of the trace.

5. The method according to claim 2, wherein determining the start of the lifecycle of the memory - backed object is based on identifying a managed runtime allocation, and wherein determining the end of the lifecycle of the memory - backed object is based on identifying at least one of: a managed runtime de - allocation or the end of the trace.

6. The method according to claim 2, wherein determining the start of the lifecycle of the memory - backed object is based on identifying a re - classification of one or more memory locations.

7. The method according to claim 2, wherein determining the end of the lifecycle of the memory - backed object is based on identifying the end of the lifecycle of a parent container.

8. The method according to claim 1, wherein the memory - backed object and the handle are identified at least in part based on processing the query.

9. The method according to claim 1, wherein the associated set is identified based on trace index data.

10. The method according to claim 1, further comprising receiving the query that references the handle.

11. The method according to claim 1, wherein formulating the response to the query comprises at least one of the following: Identifying a first trace memory access that targets at least one of the plurality of memory addresses represented in the associated set during any execution time when the at least one memory address was covered by the memory support object during the life cycle of the memory support object in the previous execution of the entity; Identifying a second trace memory access associated with the handle and corresponding to an execution time that targets at least one of the plurality of memory addresses represented in the associated set that was invalid for the handle at the execution time; Identifying a third trace memory access that includes a read that targets at least one of the plurality of memory addresses represented in the associated set during any execution time when the at least one memory address was covered by the memory support object during the life cycle of the memory support object in the previous execution of the entity, and when the at least one of the one or more memory addresses is valid for the memory support object, the read is before a write to the at least one memory address; Or Identifying that at least one of the one or more memory addresses was covered by the memory support object at a first execution time during the life cycle of the memory support object, but not covered by the memory support object at a second execution time during the life cycle of the memory support object.

12. A computer system, Comprising: At least one processor; And At least one computer-readable medium having computer-executable instructions stored thereon, the computer-executable instructions being executable by the at least one processor to cause the computer system to process a query regarding the life cycle of a memory support object based on an execution trace, the computer-executable instructions including instructions executable by the at least one processor to cause the computer system to at least perform the following: Identifying memory support objects that existed during the previous execution of the entity from a trace of the previous execution of the entity; Identifying a handle that logically represents memory covered by the memory support object during the life cycle of the memory support object in the previous execution of the entity; Identify a plurality of associations represented by the handle, the associations identifying a plurality of memory addresses covered by the memory support object during the life cycle of the memory support object, each association representing at least: (i) a memory address covered by the memory support object during the life cycle of the memory support object, and (ii) an execution time during which the memory address is covered by the memory support object during the life cycle of the memory support object; Process the query at least in part for the handle, the query including at least one query condition based on execution time, and processing the query includes comparing the execution time in the query with one or more execution times represented in the set of associations; And Formulate a response to the query based on the memory support object.

13. The computer system according to claim 12, wherein the computer-executable instructions further include instructions executable by the at least one processor to cause the computer system to perform the following: Determine the start of the life cycle of the memory support object; and Determine the end of the life cycle of the memory support object.

14. The computer system according to claim 13, wherein determining the start of the life cycle of the memory support object is based on identifying a call to an allocation primitive, and wherein determining the end of the life cycle of the memory support object is based on identifying at least one of the following: a call to a deallocation primitive or the end of the trace.

15. The computer system according to claim 13, wherein determining the start of the life cycle of the memory support object is based on identifying the allocation of a stack frame, and wherein determining the end of the life cycle of the memory support object is based on identifying at least one of the following: the deallocation of the stack frame or the end of the trace.

16. The computer system according to claim 13, wherein determining the start of the life cycle of the memory support object is based on identifying a managed runtime allocation, and wherein determining the end of the life cycle of the memory support object is based on identifying at least one of the following: a managed runtime deallocation or the end of the trace.

17. The computer system according to claim 13, wherein determining the start of the life cycle of the memory support object is based on identifying the reclassification of one or more memory locations.

18. The computer system according to claim 13, wherein determining the end of the life cycle of the memory support object is based on identifying the end of the life cycle of a parent container.

19. The computer system according to claim 12, wherein formulating the response to the query includes at least one of the following: Identify a first traced memory access that targets at least one memory address among the plurality of memory addresses represented in the associated set during any execution time when the at least one memory address was covered by the memory support object during the lifetime of the memory support object in the previous execution of the entity; Identify a second traced memory access associated with the handle and corresponding to an execution time, the second traced memory access targeting at least one memory address among the plurality of memory addresses represented in the associated set that was invalid for the handle at the execution time; Identify a third traced memory access that includes a read targeting at least one memory address among the plurality of memory addresses represented in the associated set during any execution time when the at least one memory address was covered by the memory support object during the lifetime of the memory support object in the previous execution of the entity, and when the at least one memory address among the one or more memory addresses is valid for the memory support object, the read is before a write to the at least one memory address; Or Identify that at least one memory address among the one or more memory addresses was covered by the memory support object at a first execution time during the lifetime of the memory support object, but was not covered by the memory support object at a second execution time during the lifetime of the memory support object.

20. A method implemented at a computer system for processing queries regarding the lifetime of a memory support object based on an execution trace, the computer system including at least one processor, the method comprises: Identify, from a trace of a previous execution of an entity, memory addresses that were used as part of the previous execution of the entity during at least one execution time; Receive a query regarding the memory addresses; And Based on receiving the query regarding the memory addresses, Identify at least one memory support object associated with the memory addresses during the at least one execution time; Identify a handle that is used to logically represent memory that was covered by the memory support object during the lifetime of the memory support object in the previous execution of the entity; Identify a plurality of associated sets represented by the handle, the associations identifying a plurality of memory addresses that were covered by the memory support object during the lifetime of the memory support object, each association representing at least: (i) a memory address that was covered by the memory support object during the lifetime of the memory support object, and (ii) an execution time during the lifetime of the memory support object when the memory address was covered by the memory support object; Process the query using at least in part the handle, the query including at least one query condition based on an execution time, and processing the query including comparing the execution time in the query with one or more execution times represented in the associated set; and Formulate a response to the query based on the memory support object.

Citation Information

Patent Citations

  • Defining trace handles independently of the storage addresses of the traces

    CN101583927A

  • Determining causes of external fragmentation of memory

    CN107077422A